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:
superIf 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
-Walldoes 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++11is the recommended. N.B. Using 2011 standard requires some additional tweaks. See below.
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.
.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).
-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
