2 Step 2
- In step 1 we learned how to create a simple project with a single
.cxx
file and a single executable - In step 2 we learn:
- how to create and use a library,
- how to make the use of the library optional
2.1 Exercise 1 - Creating a Library
Goal: Add and use a library
To add a library with CMake, use the add_library()
command and specify the source files that make up the library.
Instead of placing all source files in a single directory, we can organize our project with one or more subdirectories. Here we create a subdirectory specifically for our library.
To this subdirectory we add another CMakeLists.txt
file and source files.
In the top level CMakeLists.txt
file, use the add_subdirectory()
command to add the subdirectory to the build.
The library is connected to the executable target with
target_include_directories()
target_link_libraries()
Getting Started
We add a library that contains own implementation for computing square root of a number. The executable can then optionally use this library instead of the standard square root function.
The libary is put into a subdirectory MathFunctions
. This directory already contains:
- header files:
mysqrt.h
MathFunctions.h
- their respective source files:
mysqrt.cxx
contains custom implementation of square root functionMathFunctions.cxx
contains a wrapper aroundsqrt
function frommsqrt.cxx
in order to hide implementation details.
- TODO: 1 - 6
- Creating a library target
- Making use of the new library target
- Linking the new library target to the executable target
- Specifying library’s header location
- Using the library
- Replacing
sqrt
with the wrapper functionmathfunctions::sqrt
In the CMakeLists.txt
file in the MathFunctions
directoyr, we craete a library target called MathFunctions
with add_library()
.
TODO 1 - Creating a Library Target
In the CMakeLists.txt
in the MathFunctions
directory, we create a library target called MathFunctions
with add_library()
:
MathFunctions/CMakeLists.txt
# TODO 1: Add a library called MathFunctions with sources MathFunctions.cxx add_library(MathFunctions MathFunctions.cxx mysqrt.cxx)
The source files of the library are passed as arguments.
TODO 2 - Making use of the new Library
To make use of the new library we add an add_subdirectory()
in the top-level CMakeLists.txt
:
CMakeLists.txt
add_subdirectory(MathFunctions)
TODO 3 - Linking the new Library Target to the Executable Target
We link the new library target to the executable target with target_link_libraries()
CMakeLists.txt
target_link_libraries(Tutorial PUBLIC MathFunctions)
TODO 4 - Specifying Library’s Header File Location
Modify the existing target_include_directories()
to add the MathFunctions
subdirectory as an include directory so that the MathFunctions.h
header file can be found:
CMakeLists.txt
# TODO 4: Add MathFunctions to Tutorial's target_include_directories()
# Hint: ${PROJECT_SOURCE_DIR} is a path to the project source. AKA This folder!
# add the binary tree to the search path for include files
# so that we will find TutorialConfig.h
target_include_directories(Tutorial PUBLIC
"${PROJECT_BINARY_DIR}"
"${PROJECT_BINARY_DIR}/MathFunctions" )
TODO 5 & 6- Using the Library
We use the library by including MathFunctions.h
in tutorial.cxx
:
tutorial.cxx
// TODO 5: Include MathFunctions.h
#include "MathFunctions/MathFunctions.h"
Replace sqrt
with the wrapper function mathfunctions::sqrt
:
tutorial.cxx
// TODO 6: Replace sqrt with mathfunctions::sqrt
// calculate square root
// const double outputValue = sqrt(inputValue);
const double outputValue = mathfunctions::sqrt(inputValue);
2.2 Exercise 2 - Adding an Option
In this exercise we add an option in the MathFunctions
library to allow developers to select either the custom or the built-in implementation using the option()
command
Goal: Add an option to build without MathFunctions
Getting Started
We will create a variable USE_MYMATH
using option()
in MathFunctions/CMakeLists.txt
There we use that option to pass a compile time definition to the MathFunctions
library.
Then, update MathFunctions.cxx
to redirect compilation based on USE_MYMATH
.
Lastly, we prevent mysqrt.cxx
from being compiled when USE_MYMATH
is on by making it its own library inside of the USE_MYMATH
block of MathFunctions/CMakeLists.txt
TODOS: 7 - 14:
- Add an option to
MathFunctions/CMakeLists.txt
- Make building and linking our library with
mysqrt
function conditional using this new option - Add the corresponding changes to the source code
MathFunctions/MathFunctions.cxx
- Including
mysqrt.h
if the optional varible is defined. - Including
cmath
as well - Ommitting unneccesary usage/build of
mysqrt.cxx
if the custom option is off. - Link
SqrtLibrary
ontoMathFunctions
when the optional variable is enabled. - We remove
mysqrt.cxx
fromMathFunctions
library source list because it will be pulled whenSqrtLibrary
is enabled.
TODO 7 - Adding an Option
We add an option to MathFunctions/CMakeLists.txt
. This will be displayed in the cmake-gui
and ccmake
with a default value of ON
.
MathFunctions/CMakeLists.txt
# TODO 7: Create a variable USE_MYMATH using option and set default to ON option(USE_MYMATH "Use custom math implementation" ON)
TODO 8 - Make Building and Linking the Library Conditional
Make building and linking our library with mysqrt
function conditional using this new option.
Create an if()
statement which checks the value of USE_MATH
. Inside the if()
put the target_compile_definitions()
command with the compile definition USE_MYMATH
:
MathFunctions/CMakeLists.txt
# TODO 8: If USE_MYMATH is ON, use target_compile_definitions to pass
# USE_MYMATH as a precompiled definition to our source files
if(USE_MYMATH)
target_compile_definitions(MathFunctions PRIVATE "USE_MYMATH") endif()
Now when USE_MYMATH
is ON
, the compile definition USE_MYMATH
will be set. We can then use this compile definitnion to enable or disable sections of our source code.
TODO 9 - Adding the Changes to the Source Code
We add the corresponding changes to the source code. In MathFunctions.cxx
we use USE_MYMATH
to control which square root function is used:
MathFunctions/MathFunctions.cxx
// TODO 9: If USE_MYMATH is defined, use detail::mysqrt.
// Otherwise, use std::sqrt.
#ifdef USE_MYMATH
return detail::mysqrt(x);
#else
return std::sqrt(x);
#endif
TODO 10 - Including mysqrt.h
Conditionally
Next, we need to include mysqrt.h
if USE_MYMATH
is defined.
MathFunctions/MathFunctions.cxx
// TODO 10: Wrap the mysqrt include in a precompiled ifdef based on USE_MYMATH
#ifdef USE_MYMATH
#include "mysqrt.h"
#endif
TODO 11 - Including cmath
Now since we use std::sqrt()
(see TODO 9), we must include cmath
:
MathFunctions/MathFunctions.cxx
// TODO 11: include cmath
#include <cmath>
TODO 12 & 13 - Omitting Compilation of mysqrt.cxx
if Option is off
At this piont, even if USE_MYMATH
is off, mysqrt.cxx
would not be used but still compiled because MathFunctions
target has mysqrt.cxx
listed under sources.
We can fix this in various ways:
- use
target_sources()
to addmysqrt.cxx
rom within theUSE_MYMATH
block. - create an additional library within the
USE_MYMATH
block which is responsible for compilingmysqrt.cxx
.
We will go with the second option.
First we create an additional library from within USE_MYMATH
called SqrtLibrary
that has sources mysqrt.cxx
:
MathFunctions/CMakeLists.txt
if(USE_MYMATH)
target_compile_definitions(MathFunctions PRIVATE "USE_MYMATH")
# TODO 12: When USE_MYMATH is ON, add a library for SqrtLibrary with
# source mysqrt.cxx
add_library(SqrtLibrary STATIC
mysqrt.cxx) endif()
Next, we link SqrtLibrary
onto MathFunctions
when USE_MYMATH
is enabled:
MathFunctions/CMakeLists.txt
if(USE_MYMATH)
target_compile_definitions(MathFunctions PRIVATE "USE_MYMATH")
# TODO 12: When USE_MYMATH is ON, add a library for SqrtLibrary with
# source mysqrt.cxx
add_library(SqrtLibrary STATIC
mysqrt.cxx)
# TODO 13: When USE_MYMATH is ON, link SqrtLibrary to the MathFunctions Library
target_link_libraries(MathFunctions PRIVATE SqrtLibrary) endif()
TODO 14 - Removing mysqrt.cxx
from Library Source
Finally, we can remove mysqrt.cxx
from our MathFunctions
library source list because it will be pulled when SqrtLibrary
is included.
MathFunctions/CMakeLists.txt
add_library(MathFunctions MathFunctions.cxx)
With these changes, the mysqrt
function is now completely optional to whoever is building and using MathFunctions
library. Users can toggle USE_MYMATH
to this end.
Building & Running
We can manually configure CMake to use the variable providing an option from the command line:
cmake ../ -DUSE_MYMATH=OFF #or ON
Alternatively we can use cmake-gui
or ccmake
:
ccmake ../
and set the automatically detected USE_MYMATH
variable via the user interface. Afterwards build from within the build directory:
cmake --build .