Executable program files are created from readable source code.
main.cpp
executable
Creating a C++ executable is a four step process.
Download hello.cpp
By default, all four stages (preprocessor, compiler, assembler
and linker)
are done
clang++ hello.cpp # or ` hello.cpp`
./a.out
Provide a name for the created executable (instead of the default
a.out
clang++ hello.cpp -o hello
./hello
Compilation can be done with either clang++
or
.
clang++ $INFILE -o $PROGRAM_NAME
$INFILE -o $PROGRAM_NAME
Stop after preprocessor and send output to stdout
clang++ -E hello.cpp
Creates assembler files (usually *.s
)
clang++ -S hello.cpp
*.o
filesmain(.)
main(.)
clang++ -c hello.cpp
clang++ -o hello hello.o
Imagine a project with three files:
main.cpp
and modules
array.cpp
and
ui.cpp
main.cpp
array.cpp
ui.cpp
executable
What do we have to do to satisfy the compiler when using functionality
of array.cpp
in all other files?
What if we have thousands of files and change
array.cpp
?
Write the declarations exported by a source file into a separate header file.
Include the header file where the declarations are used.
Header files do not need to be compiled separately since their content is copied into the source files by the preprocessor.
Example
#include
GuardsA construct used to avoid the problem of double inclusion when dealing with the include directive.
#ifndef FILENAME_
#define FILENAME_
// ... your header file's code
#endif // FILENAME_
#include
guards
can also be referred to as
macro guards, header guards
or file guards
Compiling all source files produces a single executable.
Remember: header files are already included in the
*.cpp
files.
clang++ *.cpp
It would be much faster to re-compile
only the files that need to be re-compiled and then link the
object files.
How do we know what needs re-compilation?
Everything affected by a change must be re-compiled. If, for example,
a header file is changed, we need to re-compile all
*.cpp
files that #include
that header file.
Download
main.cpp,
ui.cpp,
ui.,
array.cpp and
array.
(or data/cpp/multiple_files).
Compile all files at once:
clang++ *.cpp -o array_tool
Since we did not create object files, any change would require complete re-compilation. Instead, we should create object files and link them together.
clang++ -c *.cpp
clang++ *.o -o array_tool
Now, make a change to main.cpp
.
Check the return value of get_dimension(.)
and issue a
warning if the value is 0.
Once done, we can just re-compile main.cpp
and link to the existing object files.
clang++ -c main.cpp
clang++ *.o -o array_tool
Extend the program to contain another function
int amax(int* array, size_t dimension)
that returns the
maximum of the given array. Add the function declaration to
array.
and the definition to
array.cpp
.
Call the function in main.cpp
and print the result
to stdout
.
Which files need to re-compiled to object files before a new executable can be linked? Once you know the answer, compile them and create a new executable.
Build tools allow you to re-compile exactly the files that need to be re-compiled with a single command or the click of a button.
There are many different build tools for each programming language.
For C and C++, popular examples are
Makefile
for the
projectall: array_tool # default target
array_tool: main.o ui.o array.o
g++ -o array_tool main.o ui.o array.o
array.o: array.cpp array.hpp
g++ -std=c++20 -Wall -c array.cpp
ui.o: ui.cpp ui.hpp array.hpp
g++ -std=c++20 -Wall -c ui.cpp
main.o: main.cpp ui.hpp array.hpp
g++ -std=c++20 -Wall -c main.cpp
.PHONY: clean
clean:
find . -name '*~' -o -name '*.o' -o -name 'array_tool' | xargs rm
Download Makefile
Makefiles quickly get complicated: example Makefile using more features
To make a build, run make -f YourMakeFile
If no -f option is present, make will look for the makefiles
GNUmakefile
, makefile
, and
Makefile
, in that order.
make # run the default (first) target
make array_tool # run the target explicitly (usually it is aliased to `all`)
make clean # run the target clean
make array.o # run the target to build array.o if that is needed
make -j8 # run 8 jobs in parallel (use up to 8 CPU cores)
Makefile
cmake_minimum_required(VERSION 3.18)
project(array_tool VERSION 1.0)
set(CPP_SRCS # all cpp source files
array.cpp
main.cpp
ui.cpp
)
set(CMAKE_CPP_STANDARD 20)
add_executable(${PROJECT_NAME} ${CPP_SRCS})
Download CMakeLists.txt
CMake isn't trivial either: example CMakeLists.txt using more features
To make a build, run the following commands
mkdir build # create directory for all files created during build
cd build
cmake .. # create the Makefile for your setup
make -j8 # start actual build on 8 cores; alternatively `cmake --build . -j8`