Modern C++
Programming
15. C++ Ecosystem
Cmake and Other Tools
Federico Busato
2024-03-29
Table of Contents
1 CMake
ctest
2 Code Documentation
doxygen
3 Code Statistics
Count Lines of Code
Cyclomatic Complexity Analyzer
1/41
Table of Contents
4 Other Tools
Code Formatting - clang-format
Compiler Explorer
Code Transformation - CppInsights
Code Autocompletion - GitHub CoPilot, TabNine
Local Code Search - ugrep, ripgrep, hypergrep
Code Search Engine - searchcode, grep.app
Code Benchmarking - Quick-Bench
Font for Coding
2/41
CMake
CMake Overview
CMake  is an open-source, cross-platform family of tools designed to build,
test and package software
CMake is used to control the software compilation process using simple platform and
compiler independent conﬁguration ﬁles, and generate native Makefile/Ninja and
workspaces that can be used in the compiler environment of your choice
CMake features:
• Turing complete language (if/else, loops, functions, etc.)
• Multi-platform (Windows, Linux, etc.)
• Open-Source
• Generate: makefile, ninja, etc.
• Supported by many IDEs: Visual Studio, Clion, Eclipse, etc.
3/41
CMake Books
Professional CMake: A Practical Guide
(14th)
C. Scott, 2023
Modern CMake for C++
R.
´
Swidzi
´
nski, 2022
4/41
CMake - References
• 19 reasons why CMake is actually awesome
• An Introduction to Modern CMake
• Effective Modern CMake
• Awesome CMake
• Useful Variables
5/41
Install CMake
Using PPA repository
$ wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null |
gpg --dearmor - | sudo tee /etc/apt/trusted.gpg.d/kitware.gpg >/dev/null
$ sudo apt-add-repository 'deb https://apt.kitware.com/ubuntu/ focal main' # bionic, xenial
$ sudo apt update
$ sudo apt install cmake cmake-curses-gui
Using the installer or the pre-compiled binaries: cmake.org/download/
# download the last cmake package, e.g. cmake-x.y.z-linux-x86_64.sh
$ sudo sh cmake-x.y.z-linux-x86_64.sh
6/41
A Minimal Example
CMakeLists.txt:
project(my_project) # project name
add_executable(program program.cpp) # compile command
# we are in the project root dir
$ mkdir build # 'build' dir is needed for isolating temporary files
$ cd build
$ cmake .. # search for CMakeLists.txt directory
$ make # makefile automatically generated
Scanning dependencies of target program
[100%] Building CXX object CMakeFiles/out_program.dir/program.cpp.o
Linking CXX executable program
[100%] Built target program
7/41
Parameters and Message
CMakeLists.txt:
project(my_project)
add_executable(program program.cpp)
if (VAR)
message("VAR is set, NUM is ${NUM}")
else()
message(FATAL_ERROR "VAR is not set")
endif()
$ cmake ..
VAR is not set
$ cmake -DVAR=ON -DNUM=4 ..
VAR is set, NUM is 4
...
[100%] Built target program
8/41
Language Properties
project(my_project
DESCRIPTION "Hello World"
HOMEPAGE_URL "github.com/"
LANGUAGES CXX)
cmake_minimum_required(VERSION 3.15)
set(CMAKE_CXX_STANDARD 14) # force C++14
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF) # no compiler extensions
add_executable(program ${PROJECT_SOURCE_DIR}/program.cpp) #$
# PROJECT_SOURCE_DIR is the root directory of the project
9/41
Target Commands
add_executable(program) # also add_library(program)
target_include_directories(program
PUBLIC include/
PRIVATE src/)
# target_include_directories(program SYSTEM ...) for system headers
target_sources(program # best way for specifying
PRIVATE src/program1.cpp # program sources and headers
PRIVATE src/program2.cpp
PUBLIC include/header.hpp)
target_compile_definitions(program PRIVATE MY_MACRO=ABCEF)
target_compile_options(program PRIVATE -g)
target_link_libraries(program PRIVATE boost_lib)
target_link_options(program PRIVATE -s)
10/41
Build Types
project(my_project) # project name
cmake_minimum_required(VERSION 3.15) # minimum version
add_executable(program program.cpp)
if (CMAKE_BUILD_TYPE STREQUAL "Debug") # "Debug" mode
# cmake already adds "-g -O0"
message("DEBUG mode")
if (CMAKE_COMPILER_IS_GNUCXX) # if compiler is gcc
target_compile_options(program "-g3")
endif()
elseif (CMAKE_BUILD_TYPE STREQUAL "Release") # "Release" mode
message("RELEASE mode") # cmake already adds "-O3 -DNDEBUG"
endif()
$ cmake -DCMAKE_BUILD_TYPE=Debug ..
11/41
Custom Targets and File Managing
project(my_project)
add_executable(program)
add_custom_target(echo_target # makefile target name
COMMAND echo "Hello" # real command
COMMENT "Echo target")
# find all .cpp file in src/ directory
file(GLOB_RECURSE SRCS ${PROJECT_SOURCE_DIR}/src/*.cpp)
# compile all *.cpp file
target_sources(program PRIVATE ${SRCS}) # prefer the explicit file list instead
$ cmake ..
$ make echo_target
12/41
Local and Cached Variables
Cached variables can be reused across multiple runs, while local variables are only
visible in a single run. Cached FORCE variables can be modiﬁed only after the
initialization
project(my_project)
set(VAR1 "var1") # local variable
set(VAR2 "var2" CACHE STRING "Description1") # cached variable
set(VAR3 "var3" CACHE STRING "Description2" FORCE) # cached variable
option(OPT "This is an option" ON) # boolean cached variable
# same of var2
message(STATUS "${VAR1}, ${VAR2}, ${VAR3}, ${OPT}")
$ cmake .. # var1, var2, var3, ON
$ cmake -DVAR1=a -DVAR2=b -DVAR3=c -DOPT=d .. # var1, b, var3, d
13/41
Manage Cached Variables
$ ccmake . # or 'cmake-gui'
14/41
Find Packages
project(my_project) # project name
cmake_minimum_required(VERSION 3.15) # minimum version
add_executable(program program.cpp)
find_package(Boost 1.36.0 REQUIRED) # compile only if Boost library
# is found
if (Boost_FOUND)
target_include_directories("${PROJECT_SOURCE_DIR}/include" PUBLIC ${Boost_INCLUDE_DIRS})
else()
message(FATAL_ERROR "Boost Lib not found")
endif()
15/41
Compile Commands
Generate JSON compilation database (compile commands.json)
It contains the exact compiler calls for each ﬁle that are used by other tools
project(my_project)
cmake_minimum_required(VERSION 3.15)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # <--
add_executable(program program.cpp)
Change the C/C++ compiler:
CC=clang CXX=clang++ cmake ..
16/41
ctest 1/2
CTest is a testing tool (integrated in CMake) that can be used to automate updating,
conﬁguring, building, testing, performing memory checking, performing coverage
project(my_project)
cmake_minimum_required(VERSION 3.5)
add_executable(program program.cpp)
enable_testing()
add_test(NAME Test1 # check if "program" returns 0
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/build
COMMAND ./program <args>) # command can be anything
add_test(NAME Test2 # check if "program" print "Correct"
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/build
COMMAND ./program <args>)
set_tests_properties(Test2
PROPERTIES PASS_REGULAR_EXPRESSION "Correct")
17/41
ctest 2/2
Basic usage (call ctest):
$ make test # run all tests
ctest usage:
$ ctest -R Python # run all tests that contains 'Python' string
$ ctest -E Iron # run all tests that not contain 'Iron' string
$ ctest -I 3,5 # run tests from 3 to 5
Each ctest command can be combined with other tools (e.g. valgrind)
18/41
ctest with Diﬀerent Compile Options
It is possible to combine a custom target with ctest to compile the same code with
diﬀerent compile options
add_custom_target(program-compile
COMMAND mkdir -p test-release test-ubsan test-asan # create dirs
COMMAND cmake .. -B test-release # -B change working dir
COMMAND cmake .. -B test-ubsan -DUBSAN=ON
COMMAND cmake .. -B test-asan -DASAN=ON
COMMAND make -C test-release -j20 program # -C run make in a
COMMAND make -C test-ubsan -j20 program # different dir
COMMAND make -C test-asan -j20 program)
enable_testing()
add_test(NAME Program-Compile
COMMAND make program-compile)
19/41
CMake Alternatives - xmake
xmake  is a cross-platform build utility based on
Lua.
Compared with makefile/CMakeLists.txt, the conﬁguration syntax is more concise
and intuitive. It is very friendly to novices and can quickly get started in a short time.
Let users focus more on actual project development
Comparison: xmake vs cmake
20/41
Code
Documentation
doxygen 1/6
Doxygen  is the de facto standard tool for generating documentation from annotated
C++ sources
Doxygen usage
• comment the code with /// or /** comment */
• generate doxygen base conﬁguration ﬁle
$ doxygen -g
• modify the conﬁguration ﬁle Doxyfile
• generate the documentation
$ doxygen <config_file>
21/41
doxygen 2/6
22/41
doxygen 3/6
Doxygen requires the following tags for generating the documentation:
• @file Document a ﬁle
• @brief Brief description for an entity
• @param Run-time parameter description
• @tparam Template parameter description
• @return Return value description
23/41
doxygen - Features 4/6
• Automatic cross references between functions, variables, etc.
• Speciﬁc highlight. Code `<code>` , input/output parameters
@param[in] <param>
• Latex/MathJax $<code>$
• Markdown (Markdown Cheatsheet link), Italic text *<code>* , bold text
**<code>** , table, list, etc.
• Call/Hierarchy graph can be useful in large projects (requires graphviz)
HAVE DOT = YES
GRAPHICAL HIERARCHY = YES
CALL GRAPH = YES
CALLER GRAPH = YES
24/41
doxygen - Example 5/6
/**
* @file
* @copyright MyProject
* license BSD3, Apache, MIT, etc.
* @author MySelf
* @version v3.14159265359
* @date March, 2018
*/
/// @brief Namespace brief description
namespace my_namespace {
/// @brief "Class brief description"
/// @tparam R "Class template for"
template<typename R>
class A {
/**
* @brief "What the function does?"
* @details "Some additional details",
* Latex/MathJax: $\sqrt a$
* @tparam T Type of input and output
* @param[in] input Input array
* @param[out] output Output array
* @return `true` if correct,
* `false` otherwise
* @remark it is *useful* if ...
* @warning the behavior is **undefined** if
* @p input is `nullptr`
* @see related_function
*/
template<typename T>
bool my_function(const T* input, T* output);
/// @brief
void related_function();
25/41
doxygen - Call Graph 6/6
26/41
Doxygen Alternatives
M.CSS Doxygen C++ theme
Doxypress Doxygen fork
clang-doc LLVM tool
Sphinx Clear, Functional C++ Documentation with Sphinx + Breathe
+ Doxygen + CMake
standardese The nextgen Doxygen for C++ (experimental)
HDoc The modern documentation tool for C++ (alpha)
Adobe Hyde Utility to facilitate documenting C++
27/41
Code Statistics
Count Lines of Code - cloc
cloc  counts blank lines, comment lines, and physical lines of source code in many
programming languages
$cloc my_project/
4076 text files.
3883 unique files.
1521 files ignored.
http://cloc.sourceforge.net v 1.50 T=12.0 s (209.2 files/s, 70472.1 lines/s)
-------------------------------------------------------------------------------
Language files blank comment code
-------------------------------------------------------------------------------
C 135 18718 22862 140483
C/C++ Header 147 7650 12093 44042
Bourne Shell 116 3402 5789 36882
Features: ﬁlter by-ﬁle/language, SQL database, archive support, line count diﬀ, etc.
28/41
Cyclomatic Complexity Analyzer - lyzard 1/3
Lizard  is an extensible Cyclomatic Complexity Analyzer for many programming
languages including C/C++
Cyclomatic Complexity: is a software metric used to indicate the complexity of a program. It
is a quantitative measure of the number of linearly independent paths through a program
source code
$lizard my_project/
==============================================================
NLOC CCN token param function@line@file
--------------------------------------------------------------
10 2 29 2 start_new_player@26@./html_game.c
6 1 3 0 set_shutdown_flag@449@./httpd.c
24 3 61 1 server_main@454@./httpd.c
--------------------------------------------------------------
• CCN: cyclomatic complexity (should not exceed a threshold)
• NLOC: lines of code without comments
• token: Number of conditional statements
• param: Parameter count of functions
29/41
Cyclomatic Complexity Analyzer - lyzard 2/3
CCN = 3
30/41
Cyclomatic Complexity Analyzer - lyzard 3/3
CC Risk Evaluation
1-10 a simple program, without much risk
11-20 more complex, moderate risk
21-50 complex, high risk
> 50 untestable program, very high risk
CC Guidelines
1-5 The routine is probably ﬁne
6-10 Start to think about ways to simplify the routine
> 10 Break part of the routine
Risk: Lizard: 15, OCLint: 10
• www.microsoftpressstore.com/store/code-complete-9780735619678
• blog.feabhas.com/2018/07/code-quality-cyclomatic-complexity
31/41
Other Tools
Code Formatting - clang-format
clang-format  is a tool to automatically format C/C++ code (and other languages)
$ clang-format <file/directory>
clang-format searches the conﬁguration ﬁle .clang-format ﬁle located in the
closest parent directory of the input ﬁle
clang-format example:
IndentWidth: 4
UseTab: Never
BreakBeforeBraces: Linux
ColumnLimit: 80
SortIncludes: true
32/41
Compiler Explorer (assembly and execution)
Compiler Explorer  is an interactive tool that lets you type source code and see
assembly output, control ﬂow graph, optimization hint, etc.
Key features: support multiple architectures and compilers
33/41
Code Transformation - CppInsights
CppInsights  See what your compiler does behind the scenes
34/41
Code Autocompletion - GitHub CoPilot
CoPilot  is an AI pair programmer that helps you write code faster and with less
work. It draws context from comments and code to suggest individual lines and whole
functions instantly
35/41
Code Autocompletion - TabNine
TabNine  uses deep learning to provide code completion
Features:
• Support all languages
• C++ semantic completion is available through clangd
• Project indexing
• Recognize common language patterns
• Use even the documentation to infer this function name, return type, and arguments
Available for Visual Studio Code, IntelliJ, Sublime, Atom, and Vim
36/41
Local Code Search - ugrep, ripgrep, hypergrep
ugrep , Ripgrep , Hypergrep  are code-searching-oriented tools for regex pattern
Features:
• Default recursively searches
• Skip .gitignore patterns, binary and hidden ﬁles/directories
• Windows, Linux, Mac OS support
• Up to 100x faster than GNU grep
37/41
Code Search Engine - searchcode
Searchcode  is a free source code search engine
Features:
• Search over 20 billion lines of code from 7,000,000 projects
• Search sources: github, bitbucket, gitlab, google code, sourceforge, etc.
38/41
Code Search Engine - grep.app
grep.app  searches across a half million GitHub repos
39/41
Code Benchmarking - Quick-Bench
Quick-benchmark  is a micro benchmarking tool intended to quickly and simply
compare the performances of two or more code snippets. The benchmark runs on a
pool of AWS machines
40/41
Font for Coding
Many editors allow adding optimized fonts for programming which improve legibility
and provide extra symbols (ligatures)
Some examples:
• JetBrain Mono
• Fira Code
• Microsoft Cascadia
• Consolas Ligaturized
41/41