Setting up C/C++ compiler
I will be using GNU C Compiler (GCC) to compile codes in a Linux computer. You can install GCC in Ubuntu/Debian by:
apt install gcc
Command to compile:
gcc filename.c
# linking math lib
gcc filename.c -lm
# show all compiler warnings
gcc -Wall filename.c
g++ filename.cpp
# compile with specific standard (might require for latest language features)
g++ -std=c++17 filename.cpp
g++ -std=c++2a filename.cpp
This would produce executable with default name a.out
. You can specify the
executable name by using the -o
flag:
gcc filename.c -o program_name
For complex programs, you can use -g
flag to generate debugging information.
-O
flag can be used to optimize the executable file (-O2
, -O3
denotes
various levels of optimization).
Compiler (GCC/Clang) flags for warnings: -Wall
, -Wextra
, -Wpedantic
,
-Wunused
.
Makefile
For large/complex projects with multiple source/header files and might require linking various various libraries, unix makefile is very helpful to write the compilation rules and build the program. Here is a very simple example:
CC=g++
CFLAGS=-O3 -Wall
# By default the left-hand-side of the first dependency is what you
# get if you just type `make` with no arguments, in this case `make all`
all: hello
# commands must be indented with TAB not spaces
# If you need to repair a Makefile that uses spaces, one way of converting
# leading spaces into TABs is to use the unexpand program:
# mv Makefile Makefile.old
# unexpand Makefile.old > Makefile
# $@ = target
# $^ = dependencies
# ${CC} -o hello hello.o
hello: hello.o
$(CC) $(CFLAGS) -o $@ $^
# ${CC} -c 00-hello-world.cpp -o hello.o
# $(CC) $(CFLAGS) -o $@ -c $^
hello.o: 00-hello-world.cpp
$(CC) $(CFLAGS) -o $@ -c $^
# The $(RM) variable is predefined to "rm -f"
clean:
$(RM) hello *.o
A makefile is consists of a set of rules. A rule consists of a target, a list of
prerequisites, and a command. In the above example, we have several rules:
all
, hello
, hello.o
, and clean
. In case of all
, we have prerequisite
hello
, while there is no command. In case of hello
, prerequisite is hello.o
and rule is: ${CC} -o hello hello.o
and so on. If we run make
without any
argument, the first rule will run, which is in this case all
. We can run
another rule, we can run it by providing its name, e.g., make clean
. Later we
will see use of more complex makefile.
Debugging
sudo apt update && sudo apt install gdb
We can use gdb
to debug our program. We can embeed debugging information to
our code by using -g
or -g3
flag. It might be helpful also to disable
optimizations with -O0
while debugging. We compile the program:
gcc -g -O0 -Wall filename.c -o filename.o
Using gdb
:
gdb filename.o
Useful gdb commands:
Commands | Description |
---|---|
break/b line-number | create breakpoint at specific line |
break filename:line-number | create breakpoint at specific line and file |
run/r | run program |
c | continue execution |
next | execute next line |
step/s | execute next line or step into function |
quit/q | quit gdb |
print expression | print current value of a specified expression |
help [command] | in-program help |
bt | print the stack trace |
clear line-number | clear break point |
clear filename:line-number | clear break point in a specific file and line |
info/i break/b | list all break points |
del breakpoint Num | delete a break point |
del start-br-pt -end-br-pt | delete break points from start-breakpoint-Num to end-breakpoint-Num |
Cppcheck
Sometimes I will be using cppcheck
to debug codes as well.
apt install cppcheck
cppcheck --enable=all filename.cpp
Valgrind
Install valgrind in Ubuntu/Debian:
apt install valgrind
Valgrind is a memory profiling tool (includes memcheck, cachegrind, callgrind, etc). First compile your program with debug flag:
gcc -g filename.c
valgrind ./a.out
valgrind --tool=memcheck --leak-check=yes --show-reachable=yes --num-callers=20 --track-fds=yes ./a.out
Valgrind can also detect:
- invalid pointer use
- use of uninitialized variables
- double frees
Valgrind does not check bounds on statically allocated arrays.