Skip to main content

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:

src/cpp/basics/Makefile
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:

CommandsDescription
break/b line-numbercreate breakpoint at specific line
break filename:line-numbercreate breakpoint at specific line and file
run/rrun program
ccontinue execution
nextexecute next line
step/sexecute next line or step into function
quit/qquit gdb
print expressionprint current value of a specified expression
help [command]in-program help
btprint the stack trace
clear line-numberclear break point
clear filename:line-numberclear break point in a specific file and line
info/i break/blist all break points
del breakpoint Numdelete a break point
del start-br-pt-end-br-ptdelete 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.