Managing C++ Projects
In the world of C++, we have several tools that help in managing project sources and their dependencies. For example, pkg-config, Autotools, make, and CMake are the most notable ones in the community. Compared to the tools of the other high-level languages, these are much more complicated to use. CMake has arisen among these as the de facto standard for managing C++ projects and their dependencies. It is more opinionated compared to make, and it is accepted as the direct project format for most IDEs (Integrated Development Environments).
While CMake helps with managing projects and their dependencies, the experience is still far from higher-level languages in which you list the libraries and their versions that you want to use and everything else is taken care of for you. With CMake, you still are responsible for installing libraries properly in your development environment, and you are expected to use compatible versions for each library. In popular Linux distributions with extensive package managers, you can easily install binary versions of most popular libraries. However, sometimes, you may have to compile and install the libraries yourself. This is a part of the whole C++ developer experience, which you will gather by learning more about the development platform of your choice. Here, we will focus more on how to properly set up our CMake projects, including understanding and resolving issues related to libraries.
The Code-Build-Test-Run Loop
In order to base our discussion on a solid foundation, we will immediately start with a practical example. We will start with a C++ code base template that you can use as a starting point for your own projects. We will see how we can build and compile it using CMake on the command line. We will also set up the Eclipse IDE for C/C++ developers and import our CMake project. The use of an IDE will provide us with facilities that ease the creation of source code and enable us to debug our programs line by line to view what exactly happens during the execution of our program and correct our mistakes in an informed fashion rather than trial and error and superstition.
Building a CMake Project
The de facto standard for C++ projects is to use CMake to organize and build the project. Here, we will use a basic template project as a starting point. The following is the folder structure of a sample template:
Figure 1.1: Folder structure of a sample template
In the preceding figure, the .gitignore file lists the file patterns that should not be added to the git version control system. Such ignored files include the outputs of the build process, which are created locally and should not be shared among computers.
The files in the include and src folders are the actual C++ source files, and the CMakeLists.txt file is the CMake script file that glues the project together by handling the source compilation rules, library dependencies, and other project settings. CMake rules are high-level platform-independent rules. CMake uses them to create various types of make files for different platforms.
Building a project with CMake is a two-step process. First, we get CMake to generate platform-dependent configuration files for a native build system that will compile and build the project. Then, we will use the generated files to build the project. The platform-dependent build systems that CMake can generate configuration files for include UNIX Makefiles, Ninja build files, NMake Makefiles, and MinGW Makefiles. The choice here depends on the platform in use, the availability of these tools, and personal preference. UNIX Makefiles are a de facto standard for Unix and Linux, whereas NMake is its Windows and Visual Studio counterpart. MinGW, on the other hand, is a Unix-like environment in Windows in which Makefiles are also in use. Ninja is a modern build system that provides exceptional speed compared to other build systems coupled with multi-platform support, which we choose to use here. Furthermore, in addition to these command-line build systems, we can also generate IDE projects for Visual Studio, XCode, Eclipse CDT, and many others, and build our projects inside the IDE. Therefore, CMake is a meta tool that will create the configuration files for another system that will actually build the project. In the next section, we will solve an exercise, wherein we will generate Ninja build files using CMake.
Exercise 1: Using CMake to Generate Ninja Build Files
In this exercise, we will use CMake to generate Ninja build files, which are used to build C++ projects. We will first download our source code from a git repository and will use CMake and Ninja to build it. The aim of this exercise is to use CMake to generate Ninja build files, build the project, and then run them.
Note
The link to the GitHub repository can be found here: https://github.com/TrainingByPackt/Advanced-CPlusPlus/tree/master/Lesson1/Exercise01/project.
Perform the following steps to complete the exercise:
- In a terminal window, type the following command to download the CxxTemplate repository from GitHub onto your local system:
git clone https://github.com/TrainingByPackt/Advanced-CPlusPlus/tree/master/Lesson1/Exercise01/project
The output of the previous command is similar to the following:
Figure 1.2: Checking out the sample project from GitHub
Now you have the source code in the CxxTemplate folder.
- Navigate into the CxxTemplate folder by typing the following command in the terminal:
cd CxxTemplate
- Now you can list all the files in the project by typing the following command:
find .
- Generate our Ninja build file using the cmake command in the CxxTemplate folder. To do that, write the following command:
cmake -Bbuild -H. -GNinja
The output of the preceding command is as follows:
Figure 1.3: Generating the Ninja build file
Let's explain parts of the preceding command. With -Bbuild, we are telling CMake to use the build folder to generate build artifacts. Since this folder does not exist, CMake will create it. With –H., we are telling CMake to use the current folder as the source. By using a separate build folder, we will keep our source files clean and all the build artifacts will live in the build folder, which is ignored by Git thanks to our .gitignore file. With –GNinja, we are telling CMake to use the Ninja build system.
- Run the following commands to list the project files and to check the files that were created inside the build folder:
ls
ls build
The preceding command will show the following output in the terminal:
Figure 1.4: Files in the build folder
It's clear that the preceding files will be present inside the build folder. build.ninja and rules.ninja in the preceding output are the Ninja build files that can actually build our project in this platform.
Note
By using CMake, we did not have to write the Ninja build files and avoided committing to the Unix platform. Instead, we have a meta-build system that can generate low-level build files for other platforms such as UNIX/Linux, MinGW, and Nmake.
- Now, go into the build folder and build our project by typing the following commands in the terminal:
cd build
ninja
You should see a final output like the following:
Figure 1.5: Building with ninja
- Type ls in the build folder and check whether we have generated the CxxTemplate executable or not:
ls
The previous command yields the following output in the terminal:
Figure 1.6: Files in the build folder after running ninja
In the preceding figure, you can see that the CxxTemplate executable is generated.
- In the terminal, type the following command to run the CxxTemplate executable:
./CxxTemplate
The previous command in the terminal will provide the following output:
Figure 1.7: Running the executable
The following line from the src/CxxTemplate.cpp file is responsible for writing the previous output:
std::cout << "Hello CMake." << std::endl;
Now you have successfully built a CMake project in Linux. Ninja and CMake work quite well together. You have to run CMake only once and Ninja will detect whether CMake should be called again and will call it for you. For example, even if you add new source files to your CMakeLists.txt file, you only need to type the ninja command in the terminal, and it will run CMake automatically for you to update the Ninja build files. Now that you have learned about building a CMake project in Linux, in the next section, we will look at how to import a CMake project into Eclipse CDT.