-
Notifications
You must be signed in to change notification settings - Fork 141
Cpp Build
Source codes of programs are usually separated to several files. It improves readability of code, increases speed of rebuild, because you have to rebuild only few files; also it is more convinient for version control systems like SVN or Git.
The drawback is increased complexity of the build process. This wiki page will describe the most "popular" problems and common ways of solution.
C++ source codes are divided in 2 big groups: headers an translated files. Translated files can be compiled to objective files, that can be linked together to binary file. Table below show common file extensions
Type | File extensions |
---|---|
Header |
.h , .hpp
|
Translated files |
.c , .cxx , .cpp , .cc
|
Objective files |
Windows: .obj Linux: .o
|
Executables |
Windows: .exe Linux: .out , no extension |
Static libraries |
Windows: .lib Linux: .a
|
Dynamic libraries |
Windows: .dll Linux: .so
|
Headers are not compiled. They are needed just to declare classes, methods and functions that can be common for another headers and translated files. Header's content can be added to them with #include
preprocessor directive.
There are two options to include source files:
#include <filename>
#include "filename"
First directive will find a file to include in directories that are specified by compiler options, so this method is commonly used for libraries headers, like STL or Boost, but your are able to provide more pathes to compiler using -I
option:
gcc file.c -I/home/my/includes/
Second directive will find a file in current directory. This method should be used to include headers from your projects. So, usually including code looks like:
#include <cstdio>
#include <cstring> // C headers firstly
#include <vector>
#include <iostream> // C++ headers than
#include <boost/filesystem.hpp>
#include <libelf.h> // External libraries than
#include "perfsim.h"
#include "top/def.h" // Local after all
Imagine that your project have two header files, a.h
and b.h
. After expansion of preprocessor directives, you may face that a.h
must include b.h
, and b.h
must include a.h
. To avoid infinite recursion, special trick of include protectors is widely used.
Note: Usually this problem is not detected even by modern compilers and it is hard to understand by compiler logs. |
---|
Source code in headers should look like:
/*
* Copyright info, brief desciption etc.
*/
#ifndef _UNIQUE_HEADER_NAME_
#define _UNIQUE_HEADER_NAME_
/*
* Code itself
*/
#endif // _UNIQUE_HEADER_NAME_
Warning: Macrovariable _UNIQUE_HEADER_NAME_ must be unique for each .h file. It's strongly recommended to name it like file name, e.g. simulator.h should have _SIMULATOR_H_ protector. |
---|
This macro will gurantee that each header's content will be included only once.
Translated files are compiled independently. If you have correct header files, you are able to compile main.cpp
file to main.o
, wait 2 hours and than compile function.cpp
to function.o
.
GCC builds objective file by command:
g++ file.cc -c -o file.o
but usually more good arguments are passed, like this:
g++ file.cc -c -O2 -Wall -Werror -std=c++03 -o file.o
Objective files contain binary code that can be run directly on target machine. One objective file correspondes to one translated file.
But, .o
is not a complete program, some code that is called from objective file is contained in other objective file or in library, file contains only a link to this code. The process of combining of objective files is called linkage and performed by linker.
Common linker for GNU\Linux environment is ld
, but command gcc
can be used instead:
gcc funcsim.o memory.o decoder.o -o funcsim.out
Executable files can be launched by OS, e.g. by user command. Therefore, one of source objectives should define entry point — int main(int, char**)
method, otherwise linker won't be able to complete linkage.
Static library is a merged objective file that can be linked during compilation of executables or other libraries. To produce it, following flow should be completed:
gcc -c archsim.cpp -o archsim.o
gcc -c decoder.cpp -o decoder.o
gcc decoder.o archsim.o -o libarch.o
ar rcs libarch.a libarch.o
After you may link this library to your program with -l<libname>
flag:
gcc simulator.cpp –larch -o arch_simulator
Note that all libraries that are used by GCC should have libname.a name! |
---|
You can provide to GCC a path where it should find static library with -L
option:
gcc simulator.cpp –larch -o arch_simulator -L/usr/bin/libs
Note: Dynamic libraries are not used in our project, we will skip them. |
---|
MIPT-V / MIPT-MIPS — Cycle-accurate pre-silicon simulation.