Build system

Build automation is the process of automating the creation of a software package. In general it includes: compiling source code, running automated tests, and the creation of a installation package. Build-automation tools allow the automation of simple, repeatable tasks. When we use them we improve team efficiency and production as well as product quality. As a result of it we achieve faster product delivery. When we choose a build system we should take into consideration if we want:

When the build systems come into play we should be familiar with a notion of a target. The build systems:construction_worker::construction_worker: organize files into targets. Each target corresponds to an executable or library, or is a custom target containing custom commands or actions the build tool must perform, such as installing an application, whereas a project is a logical group of targets gathered together into a self-contained collection that can be built on its own. Projects are the containers that developers use to organize source code files and other resources. When we think about building of software project two new concepts emerge. A source directory and a binary directory. The source directory is where source code and resource files are located. The build system needs them to create binaries. Inside the source directory there are build system files contain a set of directives describing how to build, test, and deploy a project. The source directory is frequently under version control (GIT, SVN, Mercurial etc). The binary directory is where every items created by the build system are placed. These are object and temporary files, executables, libraries, test output and packages created during the build process.

Cross-platform solution

As cross-platform programmers we need a simple build system which we can leverage on many platforms in the same way irrespective of IDE or toolchain we utilize. We use it to configure the build options and create the final applications or libraries from sources. That tasks developers have to repeat several times every day, so it is extremely important to ensure that the process is under control and repeatable.

Powerful duo comes to rescue

Our project is growing. More and more modules come into play. That will be harder to do all things manually. We need automate a build process. It’s about time we need to get familiar with the main actors of our story. Ladies and gentlemen let me introduce a fantastic couple:couple: Cmake and Ninja. As we may expect these are command line tools too. It means we need run they from a shell. Run your shell such a bash on Unix , cmd.exe or Msys2 shell on Windows. Now an operating system is at our command.
Type cmake --version and press Enter. Cmake
Type cmake --help don’t forget about enter, then try out:

cmake --help-command-list
cmake --help-manual-list

Now play with Ninja:

ninja --version
ninja --help

Ninja
I feel we got the hang of the tools. Although command-line tools often require manuals for the user’s reference, we can frequently try out a “help” option and “version” one too. A more interesting matter is why we use command-line tools. From our developers’ point of view three things are important and crucial. We want to:

Strutting our stuff

Before we’ll delve into building processes, we have the opportunity to present our tools.
Cmake stuff

Get our feet wet

As you may recall from section A typical programmer’s pipeline there are a few " green boxes "(processes) in the flowchart/workflow. Here is a list of processes we don’t want to do manually:

As you can guess, we want to automate these processes using scripts and CMAKE command-line tools. We will be utilizing cmake.exe to build, ctest.exe to test and cpack.exe to deploy a software package. Let’s start learning how to build a software with cmake.exe. On the whole while triggering a build with cmake we mainly perform a simple workflow:

During the generation stage the scripts for the native build tools are created. In next step we use cmake.exe to invoke the native build tools which uses scripts previously generated to create binaries.

Simple executable project - HelloWorld

Open MSYS2 Mingw-w64 command line and create HelloWorld folder (mkdir HelloWorld) for a project. Then run your favourite text editor (notepad for example) and write code as below:

#include <iostream>
int main()
{
    std::cout << "Hello, World!";
    return 0;
}

Save a written source code as hello.cpp in HelloWorld folder.
Create a new file inside the editor (File->New) and type:

# CMakeList.txt : HelloWorld CMake project file
cmake_minimum_required (VERSION 3.8 FATAL_ERROR)

project("HelloWorld" LANGUAGES CXX)

add_executable(hello hello.cpp)

Save text as CMakeLists.txt file. Close the editor. Make build directory. Your project folder structure should look like as follows:

+HelloWorld
|   CMakeLists.txt
|   hello.cpp
|
\---build

You should be inside HelloWorld folder.
Please follow a simple recipe to create and run hello executable.

mkdir build
cd build
cmake -GNinja ..
cmake --build .
./hello

Close MSYS2 terminal. Now open Developer Command prompt for VS and go where your project is located:

REM remove build directory
rmdir build /s
mkdir build
cd build
cmake -GNinja ..

g++ Ninja bug
Whoops! A wrong compiler is selected (if you have two or more compilers installed). Although this is MSVC environment I don’t know why but cmake chooses g++ compiler when you use Ninja generator (-GNinja). We have to fix it. We can do that in two ways:
settings environment variables

REM you can omit .exe I leave it for clarity
set CC=cl.exe
set CXX=cl.exe

or adding additional parameters to cmake call. I prefer the second one. Go back to the top:smile:

REM remove build directory
rmdir build /s
mkdir build
cd build
cmake -G "Ninja" -DCMAKE_C_COMPILER=cl.exe -DCMAKE_CXX_COMPILER=cl.exe
cmake --build .
./hello

Discourse

Now when we’ve completed the whole work, it’s time to shed some light on to answer the question “What on earth is going on here?”. To start with we have to get familiar with a few ideas (I took definitions of Source Tree, Build Tree and Generator from cmake documentation):

Source Tree
The top-level directory containing source files provided by the project. The project specifies its buildsystem using files as described in the cmake-language manual, starting with a top-level file named CMakeLists.txt. These files specify build targets and their dependencies as described in the cmake-buildsystem manual.

Build Tree
The top-level directory in which buildsystem files and build output artifacts (e.g. executables and libraries) are to be stored. CMake will write a CMakeCache.txt file to identify the directory as a build tree and store persistent information such as buildsystem configuration options.

To maintain a pristine source tree, perform an out-of-source build by using a separate dedicated build tree. An in-source build in which the build tree is placed in the same directory as the source tree is also supported, but discouraged.

Generator
This chooses the kind of buildsystem to generate. See the cmake-generators manual for documentation of all generators. Run cmake –help to see a list of generators available locally. Optionally use the -G option below to specify a generator, or simply accept the default CMake chooses for the current platform.

When using one of the Command-Line Build Tool Generators CMake expects that the environment needed by the compiler toolchain is already configured in the shell. When using one of the IDE Build Tool Generators, no particular environment is needed.

CMakeLists.txt
A human-readable text file containing the entire platform independent build specification which gives a description how to build the whole project. CMakeLists.txt file located in the top-level source directory is the entry point for cmake during configuring the project source tree.
Let’s analyze hello cmake project top-level configuration file line by line:

Cheer up, still only the building process remained for us to discuss in detail. We do it short and sweet but step by step. It’s a common pattern of building procedure. Because we want to use Ninja build system we have to specify a generator explicitly otherwise a default platform generator will be used. To list available generators for current platform type cmake --help command in your terminal. See below we call cmake.exe twice first time when we want to generate files for a native build system and second one when we run build process. You may ask why we don’t run ninja.exe in a second step directly. Well, let’s imagine that we saved that list of commands in a script, in this case if you change the generator, you must change the call of the native build tool too. If you call cmake.exe in the second step it runs a proper build tool automatically for you. Additionally we don’t need to remember mappings the generator <-> the native tool.

mkdir build               - to avoid a hotch-potch create a build directory for buildsystem files  
cd build                  - go inside the build directory  
cmake -GNinja [params] .. - generate files for Ninja (-GNinja) look for CMakelists.txt in a parent directory (..) specify additional parameters for a project buildsystem generating process
cmake --build .           - build project (--build) using current directory (.) as the build tree

Hierarchical project - Area and Perimeter Calculation

Under construction stay tuned :smile:

«Back
Next »