This repository will help you learn Modern CMake
The documentation is available at github pages
By the time you complete this exercise you will know:
- Basic CMake - defining a project for a simple library
- How to enable unit-tests in CMake
- How to enable static code analisys using
cppcheck
andclang-tidy
- How to export your library in a modern way so that other developers will be able to import it as a CMake dependency.
- How to create & publish documentation on Github Pages.
This repo contains a simple C++ library: Fact
The Fact
library has only one function:
unsigned int factorial(unsigned int);
which computes the factorial of a certain number. There are some unit-tests and even a downstream dependency test.
There is also a CI pipeline set-up for building the library and running the tests!
However, this repo does not have any build-system support, so all this goodies cannot be put to use, and the pipeline fails miserably.
Your mission - should you choose to accept it - is to make the CI pipeline work by writing the necessary CMake files that will define how the library is built and installed.
Fork this repository. You will work on your own fork. Clone your fork on your development machine. Notice the excercise might change, so it is recommended to allow mirroring.
In your local repo, create a new branch on top of master:
git checkout master
git pull
git checkout -b solution/<your name>
Use conda
for this exercise. It is a great tool for setting up an isolated
development environment with all the dependencies for your project.
I recommend using miniconda.
Install miniconda
and verify that it is working:
conda -V
For your convenience, this project contains environment.yml
file, which
describes the environment necessary for this project. You can create the environment by running the following command:
conda env create
The environment name will be modern-cmake
and you can activate your environment using:
conda activate modern-cmake
- Create a topic branch
solution/<your name>
- Follow the insctructions below about the tasks required at each stage.
- Once you finished the first stage, submit a Merge Request for
your branch. Prefix your MR title with
WIP:
. This will allow the tutors to perform CR on your code. - As you move through the stages, more jobs in the CI pipeline will become green, until you complete the exercise.
Notice: You SHOULD NOT change the code or the .gitlab-ci.yml
or the source files.
All you have to do is create the necessary CMake files that will cause the CI to work.
Since the CMake documentation might be too obscure for novel CMakers as yourself, I recommend reading Its time to do CMake right. This will get you through Stages 1-3, solving them using the modern features of CMake. If you're up to more reading, take a look at Jason Turner's cpp_starter_project.
In the first stage all you have to do is create the simplest valid CMakeLists.txt file that defines a project. It doesn't matter what the project name is.
In this stage you will write the necessary CMake files to actually compile the library.
- Create a target called
Fact
. It should be a library of course. - The target is composed of a single source file,
src/fact.cpp
- Make sure that the target has the proper include directory (Notice that
fact.cpp
includesfact/fact.hpp
) - Make sure your target is linked against
spdlog
which is a build dependency ofFact
.spdlog
is installed in your conda environment already. All you have to do is find it in your CMake file, and set it as a dependency ofFact
.
There are some unit tests written in test/tests.cpp
. These tests
are using the CppUTest
test framework.
- Create an project-level option for compiling the unit-tests. It
should be
ON
by default. - Add an executable target for
tests.cpp
. The target must be calledFactTests
. - Add
CppUTest
as a build dependency forFactTests
(as you already know - you have to find it).
This is by far the hardest part. In this stage you will write installation rules that will:
- Install your library - put the compiled
.a
/.so
and the public header in the proper location. - Export your target so that other developers will be able to find your library including all of its dependency after installation.
- CMake uses find_package(), in order to find your package you have to create a CMakeConfig.make file (hint: should be names FactConfig.cmake).
- Together with the recommended reading you may use the example found in the last paragraph in the CMake doc.
- Notice The CMakeLists.txt file in the downstream folder, it uses a certain Namespace for your targert, you should be using the same Namespace. As for cpp programmaing, target namespaces allow multiple developers create targets with the same name (E.G. Steam::Fact, Async::Fact).