Compiled languages rely on the compiler to transform source codes into an executable binary. This process involves two stages:
.c
/.cpp
files into object files .o
.o
together by matching the function calls, adding the libraries, etc.Two very common compilers exist: gcc
and clang
.
gcc
is a GNU compiler featuring the GNU-GPL license. It used to be very common a few years ago but it has recently lost ground in favor of clang
.
clang
is the LLVM-based c/c++ compiler. It transforms the source code into LLVM sub-language, which is then in turn transformed into object files.
The compiler is based on a permissive license, which makes is more attractive for companies than gcc
. Also, the use of the LLVM-backend is shared by other languages like Julia.
Due to its permissive license LLVM and clang
are also used by software companies (intel, nvidia) as a basis to their own compilers.
It is common in the compilation process to define environment variables containing the compiler’s name. Usual names are CC=clang
and CXX=clang
.
For the GNU compilers it becomes CC=gcc
and CXX=g++
respectively.
To compile the code, simply enter
CXX [options] -o code.cpp
Many options are available for each compilers, see here for GNU and here for clang.
The linker is used to put together the object files into an executable or a library. Commonly called using ld
every compiler suite features one.
To make it easier you can link using your compiler:
CXX obj1.o obj2.o -o exe
You can also use the linker to create shared libraries using the -shared
option. To create static libraries you should use ar
instead.
To use external libraries, after having installed them you can simply request the linker to link to it:
CXX -lfancy obj1.o obj2.o -o exe
The linker will look for a file named libfancy.so
in your LIBRARY_PATH
.
When linking to external libraries, the link can be dynamic or static.
The former means that at the start of the exe, i.e. when typing ./exe
, it will look for the different libraries (in your LIBRARY_PATH
).
This approach is opposed to the static linking where the library is included into the exe hence increasing its size.
The dynamic linking should be used whenever possible to ease its use, but it might also mean that sometimes the library are not found.
Before starting the program you can check which library is found or missing using the tool ldd
: ldd exe
.
Sometimes an improved version of this tool is useful, among others libtree.
However, it might be convenient to encode the path to the library that you use inside the exe as an in-between solution
For example that path might be known at compile time only, or you may want to make sure that a given version of the library is used instead of the default one found in your LIBRARY_PATH
.
To enforce the exe to look into path/to/lib
when loading the library libfancy.so
you can use
CXX -Lpath/to/lib -lfancy -Wl,-rpath,path/to/lib
clang
The compiler clang
has some advantages compared to gcc
, especially in the wide range of tools provided: clang-format
, clang-tidy
, etc.
Here is a non-exhaustive list of some features we have found useful over time:
sanitize: sanitize=address
: this option makes the debugging easy in case of segfaults, especially when used in parallel (MPI). Add the option -fsanitize=address
to both the compiler and the linker. Similar to the previous option sanitize=undefined
helps to detect undefined variables. Finally to improve the trace output that you get from clang
, you can use -O1 -fno-omit-frame-pointer
. More information are given in the clang documentation.
optimization you can easily generate a readable optimization report (in html) from the compilation process with -fsave-optimization-record
. Then use the provided python script to generate the html output: python3 /usr/lib/llvm-xx/share/opt-viewer/opt-viewer.py --output-dir opt_reports build/*.opt.yaml
. Note that the exact path of the opt-viewer.py
script might change on your system.
compilation database clang-format
and clang-tidy
are part of the tools provided as part of the LLVM suite. In general those tools rely on the compilation database. The latter can be generated by the clang
compiler as a two step process. First generate the json
file for every source file using the options -MJ source.o.json
during compilation. Once done, you can gather the json
into a single database using sed -e '1s/^/[\n/' -e '$$s/,$$/\n]/' $^ > compile_commands.json
.