Hide menu

TDDD33 Programming (C++)

Compilation


If you just want to know the command to compile you should use in the course, skip to Enable correct compiler version and Create a short compile command later on this page.

Compile your programs

To transform your programs to a format (machine code) the computer can understand, you must compile the source code. The compilation is a lengthy process of feeding the source code through several programs, each performing one part of the transformation. The steps involved are in order: preprocessing, compilation and linking. More information on each step is given below, and are relevant to interpret some errors you can encounter. As programmers we normally want the computer to do all our work, so doing each step manually is not something we want. Instead we have a program that do all steps for us automatically. We lazily call this program "the compiler" in spite of it doing also preprocessing and linking. For a simple program the compiler is invoked with one command. If we assume your source code is stored in a file called my_superior_program.cc the following is the command you need to type in your terminal:

g++ my_superior_program.cc

g++ is "the compiler" and takes care of invoking the preprocessor, the compilation step, and the linker on the source file my_superior_program.cc. The result is either an error message written in your terminal, or a new file called a.out in your current folder. a.out is your executable program. Simply type it in your terminal to start it:

a.out

Often you want your program to be named something else. In our case we may want the final executable file to be named super. Then you have two options. You can use the standard system command (mv) to rename the file a.out to super (mv a.out super). But that requires one extra command, and as said above, a programmer want things automated in one command:

g++ my_superior_program.cc -o super

-o is called a flag to the compiler. It is a special directive telling the compiler to do something different from the default. In this case -o instructs the compiler to name the output file super instead of the default a.out. To run the program, just type the name of it's file in the terminal:

super
If you name your program yourself chances are that another command exist that have the same name, this happen for example if you name the program test. When you start a program by typing it's file name the system will start the first program it finds with that file name. Chances are that this will be the system command with that name, not your program, as system commands are usually searched first. This will cause you much confusion until you figure out what happened. To be sure you are executing your program and not an equally named system or built-in command you write the relative (or full) search path to your file:

./super

Important compiler flags

As said above a flag changes default settings in the compiler, and as it turns out some non-default settings are essential to have some help to create correct programs. Here follow a list of flags you should use in the course. To get the full list of flags, use the command man g++.

-Wall
Make the compiler issue a warning when you do something wrong (or suspicious). Take them serious. Good code do not generate warnings. It is absolutely crucial to correct warnings you do not understand. You should use this flag.
-Wextra
C++ is a language with a lot of history, all the way from the predecessor of C. In order not to change the default behaviour of the compiler from one version to the next it turns out that -Wall does not really enable all possible warnings. This flag adds the last few. You should use this flag.
-std=c++98
-std=c++11
Tell the compiler to follow the C++ standard from 1998 or 2011. We always want to write standard compliant code, so you should use one of those flags. As we in some labs will use some of the minor improvements in the C++ 2011 standard -std=c++11 is the recommended. N.B. Using 2011 standard requires some additional tweaks. See below.
-pedantic
Warn about everything required by the standard. You should use this flag.
-g
Tell the compiler to generate extra information that make it easier to use the debugger. You should use this when you have segmentation fault and need to use gdb. Often, it is easier to use it always, it does no harm. The only reason you may like to remove it is when you compile a release of your program that ship to your end customers.
-Weffc++
Include warnings recommended by the "Effective C++" book. See man page for full information. Unfortunately it will produce warnings about some aspects of the C++ Standard Template Library. Those warnings can be safely ignored, but tend to obscure more important warnings. You will use this flag in some labs. I recommend that you use it whenever you can, as you get warnings for some easy to make, but serious, omissions. Specially when it comes to memory management of classes. Make sure to use it on the exam.
-c
Just preprocess and compile, do not link. You will get only an object file (extension .o) as result. It can later be used together with other files to build a large program. If it contain a well written function it will be usable in many programs without the need to compile it again (unless you change the source code).
-lLIBRARYNAME
Add the precompiled program library LIBRARYNAME to the linking step. Examples: -lncurses for programs using console graphics library or -lSDL for programs using windowed graphics library.

Enable correct compiler version

The default compiler on our system is gcc version 3.4.6, since this is good and stable for most languages (the gcc compiler can compile many languages, gcc stands for GNU Compiler collection). We would like to use the latest version of the compiler that includes C++ 2011 features. The correct way to do this is to execute the following 5 commands:

module rm prog/gcc
module add prog/gcc/4
module list

If all went good the last of above three commands will print a list of all enabled software packages, and prog/gcc should only occur once, with version 4.7.x listed. Then you can continue with the two last commands (press up-arrow three times to modify the previous commands):

module initrm prog/gcc
module initadd prog/gcc/4

Now you need to log out and then log in again for the new setting to take effect in all windows.

Create a short compile command

Once you enable all flags you should use the command to compile starts to get long and tedious to type:

g++ -Wall -Wextra -Weffc++ -std=c++98 -pedantic -g my_superior_program.cc -o super

Programmers want the computer to do all work at all times, so we can of course automate the typing of the extra flags by means of an alias. Use man alias to see how aliases work in general. You should create two aliases:

alias g++98 'g++ -Wall -Wextra -std=c++98 -pedantic -g'
alias g++11 'g++ -Wall -Wextra -std=c++11 -L/sw/gcc-$GCC4_V/lib -static-libstdc++ -pedantic -g'

Specially note the two extra flags used in the g++11 alias. They are required to use the new standard on out system.

If you add both lines in ~/.cshrc.private the aliases are enabled automatically every time you start a new terminal. Once the alias is active you can simply write:

g++11 my_superior_program.cc -o super

And you will compile your program with all nice flags according to C++ 2011 standard. Very convenient. You can of course still add more flags if you like:

g++11 -Weffc++ my_superior_program.cc -o super

Header files versus source files

Larger programs consist of both header files and source files. Sometimes you also have template files.

Header files

Header files consist of only declarations. The declarations describe a list of functions or classes that are written in a source file accompanying the header file. Only functions that may be called by others should be listed in the header file. Functions that should only be used internally in the source file should not be in the header file.

Header files are included in other source and header files in order to call or make known functions declared in the header file.

Header files should never be compiled. They are only included.

As header files are included in other files they should never have any using namespace ...; lines.

Source files

Source files consist of definitions of the functions and classes listed in corresponding header file, and possibly other internal help functions and classes not listed in the header file. This is the actual implementation of the functions and classes.

Source files should never be included in other source or header files. Instead you add them to the list of source files in your compile command.

Template files

Template files are the exception to the rules about source and header files. Template files contain a template for how a certain algorithm will work, but certain aspects, such as constants and data types are not yet decided.

Template files can not be compiled until all aspects are decided, and must be included in the source code that use the template. You can not compile a template on it's own.

The compilation steps

When you execute the command g++ the following steps are performed in order.

Preprocessor (cpp)

The preprocessors reads your source code and adds, replaces or removes certain parts according to preprocessing instructions you can add in your code. The most common preprocessing directive you use is #include. The output from the preprocessing step is new source code.

Compiler (g++)

The compiler reads the output from the preprocessor and verify the code is valid C++ without any syntax errors. The high level instructions are converted to low level assembler instructions closely matching the capabilities of the processor. The output is a form of assembler program, still readable by humans.

Assembler

The assembler converts the assembler code from the compilation step to binary instructions (machine code) that processor can understand.

Linker (ld)

The linker reads several pieces of the program and libraries you used and put them together to form a complete program, and arranges the final program memory layout. Sometimes you get errors from this step. That is usually because some piece of the program is missing. Each time your program calls a function or use a variable the linker make sure that the used function or variable is actually compiled and available. When you forgot to compile one or more files the linker will complain about "missing symbols".

C++ compilers at IDA

You may find this page on compilers at IDA useful.

It is written by Tommy Olsson, He is a senior programmer/teacher at the department (IDA) and has an excellent collection on C++ and programming information, unfortunately mostly available in Swedish.

Make

Larger programs contain several source files. Compiling every file whenever the program is to be built is tedious and time consuming. Only the source files that was changed should need new compilation. But keeping track of which files was changed is even harder. To aid this task we use make. It is a program that reads a file containing instructions (rules) of how and in which order files should be processed. This file is named Makefile and most often reside in the same directory as the source code. A basic Makefile, containing the rules needed to build our super program in two steps would contain:

CXX=g++
CXXFLAGS=-Wall -Wextra -std=c++11 -L/sw/gcc-4.7.1/lib -static-libstdc++ -pedantic -g

super : my_superior_program.o
       $(CXX) $(CXXFLAGS) $^ -o $@

super.o : my_superior_program.cc
       $(CXX) $(CXXFLAGS) -c $<

The first line defines a variable with the compiler we want to use. The second line define the compiler flags. Saving this in variables make it easy to change later.

The next two lines defines the first rule. It tells make to create the file super from the file(s) my_superior_program.o by using the following command (after variables are expanded):

g++ -Wall -Wextra -std=c++11 -L/sw/gcc-4.7.1/lib -static-libstdc++ -pedantic -g my_superior_program.o -o super

Notice how $^ (all files after the colon on previous lines), $< (first file after colon on previous line) and $@ (file before colon on previous line) expand to my_superior_program.o, my_superior_program.cc and super respectively (determined from the previous line). Read the make manual page to get all the details. You can find it more readable online.

The last two lines describe how to create the file my_superior_program.o from the file my_superior_program.cc by using the command (after variables are expanded):

g++ -Wall -Wextra -std=c++11 -L/sw/gcc-4.7.1/lib -static-libstdc++ -pedantic -g -c my_superior_program.cc

Notice the new -c flag. It instruct the compiler to skip the linking step and just compile the program. An object file with .o extension is created.

Once you have the Makefile all you have to do is to issue the command make in the same folder as your Makefile, and you program will be built according to the rules you set up:

make

Finally a more general form of a Makefile. The make program automatically figures out dependencies between the rules, and whether files need to be recreated.

VARIABLE1=values
VARIABLE2=values
...
VARIABLEn=values

file1_to_create : file11_needed file12_needed ... file1M_needed
_tab_  command_to_do_it
       
file2_to_create : file21_needed file22_needed ... file2M_needed
_tab_  command_to_do_it

...

fileN_to_create : fileN1_needed fileN2_needed ... fileNM_needed
_tab_  command_to_do_it

N.B. _tab_ should be exactly one tabulator, not a series of spaces.

Now, consider how to do if my_superior_program consist of three different source files: my.cc, superior.cc and program.cc. This is the Makefile required:

CXX=g++
CXXFLAGS=-Wall -Wextra -std=c++11 -L/sw/gcc-4.7.1/lib -static-libstdc++ -pedantic -g

# rule to link the three object files to the final program
super : my.o superior.o program.o
       $(CXX) $(CXXFLAGS) $^ -o $@

# rules to compile each individual source file to corresponding object file
my.o : my.cc
       $(CXX) $(CXXFLAGS) -c $<

superior.o : superior.cc
       $(CXX) $(CXXFLAGS) -c $<

program.o : program.cc
       $(CXX) $(CXXFLAGS) -c $<

Page responsible: Klas Arvidsson
Last updated: 2012-10-27