6/9

4.2. Compilation tools

Typing by hand all compiler calls and arguments can become tedious when dealing with large projects.

Different tools have been developed to ease this process.

We can notably separate low level build tools storing compiler calls

  • Make: The common GNU tool to automatize a set of chaining command lines (typically used to compile programs) from a so called Makefile. Makefiles can be written manually.

  • Ninja: A more recent compiler call focused on speed (less automatization than Make), but not supposed to be manually written.

And higher level tools used to generate build tools files such as Makefile or ninja files.

  • CMake: A large software to handle build systems on project. Can generate for instance Makefile, Ninja configuration, and Visual Studio project.

  • Meson: A lighter (and more recent) tool dedicated to generate ninja files.

Example on single file project

Consider the following file

#include <iostream>

int main()
{
    std::cout << "Hello world" << std::endl;
    return 0;
}

In command line

$ g++ main.cpp -g -Wall -Wextra -O2 -std=c++14 -o pgm

The executable is created, and you can run it using

$ ./pgm

With Make

Create the file Makefile

[ Makefile ]

CXXFLAGS = -g -Wall -Wextra -O2 -std=c++14
CXX = g++

all: pgm
pgm: main.cpp
	${CXX} $^ -o pgm ${CXXFLAGS}
clean:
	rm -f pgm

You can compile and execute the program using

$ make
$ ./pgm

With CMake

Create the file CMakeLists.txt

cmake_minimum_required(VERSION 2.8)
project(pgm)

set(CMAKE_CXX_FLAGS "-O2 -g -std=c++14 -Wall -Wextra")

add_executable(pgm main.cpp)

CMakeLists.txt is a configuration file for CMake. CMake will generate several temporary files. It is usually a good idea to execute CMake in a separated directory in order to avoid poluting the src directory.

# Create temporary build directory
$ mkdir build
$ cd build


# Call CMake on the CMakeLists.txt
$ cmake ..


# A Makefile should have been created
$ make


# It is usually a good idea to execute the pgm from the original directory
$ cd ..
$ build/pgm

With Meson

Create the file meson.build

project('pgm', 'cpp')
cxxflags = ['-O2','-g','-std=c++14','-Wall','-Wextra']
add_global_arguments(cxxflags, language : 'cpp')
executable('pgm', 'main.cpp')

# Call Meson to generate build file in a directory called build
$ meson build


# Compile using ninja
$ cd build
$ ninja


# It is usually a good idea to execute the pgm from the original directory
$ cd ..
$ build/pgm

Example on multiple files project

Consider the following files that we will consider to be in /src directory

[ source ]

#include "f1.hpp"

int main()
{
    f1();

    return 0;
}
#pragma once

void f1();
#include <iostream>

void f1()
{
    std::cout<<"Function f1"<<std::endl;
}

In command line

$ g++ -c src/main.cpp -g -Wall -Wextra -O2 -std=c++14
$ g++ -c src/f1.cpp -g -Wall -Wextra -O2 -std=c++14
$ g++ main.o f1.o -o pgm
$ ./pgm

With Make

[ Makefile ]

CXXFLAGS = -g -Wall -Wextra -O2 -std=c++14
CXX = g++

all: pgm
pgm: src/main.o src/f1.o
	${CXX} $^ -o pgm

src/main.o: src/main.cpp src/f1.hpp
src/f1.o: src/f1.cpp


clean:
	rm -f pgm src/*.o
$ make
$ ./pgm

With CMake

cmake_minimum_required(VERSION 2.8)
project(pgm)

set(CMAKE_CXX_FLAGS "-O2 -g -std=c++14 -Wall -Wextra")

file(
    GLOB_RECURSE
    source_files
    src/*.[ch]pp
)
add_executable(pgm ${source_files})
  • Note that the file inclusion is very generic and include recursively all files ending by .cpp and .hpp.

$ mkdir build
$ cd build
$ cmake ..
$ make
$ cd ..
$ build/pgm

With Meson

project('pgm', 'cpp')
cxxflags = ['-O2','-g','-std=c++14','-Wall','-Wextra']
add_global_arguments(cxxflags, language : 'cpp')
src = ['src/main.cpp','src/f1.cpp']
executable('pgm',  sources : src)

$ meson build
$ cd build
$ ninja
$ cd ..
$ build/pgm