Modern CMake for C++: Discover a better approach to building, testing, and packaging your software
4.5/5
()
About this ebook
Creating top-notch software is an extremely difficult undertaking. Developers researching the subject have difficulty determining which advice is up to date and which approaches have already been replaced by easier, better practices. At the same time, most online resources offer limited explanation, while also lacking the proper context and structure.
This book offers a simpler, more comprehensive, experience as it treats the subject of building C++ solutions holistically. Modern CMake for C++ is an end-to-end guide to the automatization of complex tasks, including building, testing, and packaging. You'll not only learn how to use the CMake language in CMake projects, but also discover what makes them maintainable, elegant, and clean. The book also focuses on the structure of source directories, building targets, and packages. As you progress, you’ll learn how to compile and link executables and libraries, how those processes work, and how to optimize builds in CMake for the best results. You'll understand how to use external dependencies in your project – third-party libraries, testing frameworks, program analysis tools, and documentation generators. Finally, you'll get to grips with exporting, installing, and packaging for internal and external purposes.
By the end of this book, you’ll be able to use CMake confidently on a professional level.
Related to Modern CMake for C++
Related ebooks
CMake Best Practices: Upgrade your C++ builds with CMake for maximum efficiency and scalability Rating: 0 out of 5 stars0 ratingsLearn Qt 5: Build modern, responsive cross-platform desktop applications with Qt, C++, and QML Rating: 0 out of 5 stars0 ratingsCMake Best Practices: Discover proven techniques for creating and maintaining programming projects with CMake Rating: 0 out of 5 stars0 ratingsMetaprogramming in C#: Automate your .NET development and simplify overcomplicated code Rating: 0 out of 5 stars0 ratingsDeploying Node.js Rating: 5 out of 5 stars5/5Hands-On Microservices with Kubernetes: Build, deploy, and manage scalable microservices on Kubernetes Rating: 5 out of 5 stars5/5Learning Docker - Second Edition Rating: 0 out of 5 stars0 ratingsTools and Skills for .NET 8: Get the career you want with good practices and patterns to design, debug, and test your solutions Rating: 0 out of 5 stars0 ratingsCrystal Programming: A project-based introduction to building efficient, safe, and readable web and CLI applications Rating: 0 out of 5 stars0 ratingsLearn LLVM 12: A beginner's guide to learning LLVM compiler tools and core libraries with C++ Rating: 0 out of 5 stars0 ratingsEmbedded Programming with Modern C++ Cookbook: Practical recipes to help you build robust and secure embedded applications on Linux Rating: 0 out of 5 stars0 ratingsMastering MongoDB 6.x: Expert techniques to run high-volume and fault-tolerant database solutions using MongoDB 6.x Rating: 0 out of 5 stars0 ratingsLearn Bosque Programming: Boost your productivity and software reliability with Microsoft's new open-source programming language Rating: 0 out of 5 stars0 ratingsDocker and Kubernetes for Java Developers Rating: 0 out of 5 stars0 ratingsSoftware Architecture for Busy Developers: Talk and act like a software architect in one weekend Rating: 0 out of 5 stars0 ratingsHands-On Machine Learning with ML.NET: Getting started with Microsoft ML.NET to implement popular machine learning algorithms in C# Rating: 0 out of 5 stars0 ratingsMachine Learning in Production: Master the art of delivering robust Machine Learning solutions with MLOps (English Edition) Rating: 0 out of 5 stars0 ratingsHands-On Embedded Programming with C++17: Create versatile and robust embedded solutions for MCUs and RTOSes with modern C++ Rating: 0 out of 5 stars0 ratingsHands-On Microservices with Node.js: Build, test, and deploy robust microservices in JavaScript Rating: 0 out of 5 stars0 ratingsArchitecting ASP.NET Core Applications: An atypical design patterns guide for .NET 8, C# 12, and beyond Rating: 0 out of 5 stars0 ratingsThe Kubernetes Bible: The definitive guide to deploying and managing Kubernetes across major cloud platforms Rating: 4 out of 5 stars4/5
Software Development & Engineering For You
Python For Dummies Rating: 4 out of 5 stars4/5Coding with AI For Dummies Rating: 0 out of 5 stars0 ratingsLevel Up! The Guide to Great Video Game Design Rating: 4 out of 5 stars4/5PYTHON: Practical Python Programming For Beginners & Experts With Hands-on Project Rating: 5 out of 5 stars5/5Hand Lettering on the iPad with Procreate: Ideas and Lessons for Modern and Vintage Lettering Rating: 4 out of 5 stars4/5Learn to Code. Get a Job. The Ultimate Guide to Learning and Getting Hired as a Developer. Rating: 5 out of 5 stars5/5Coding All-in-One For Dummies Rating: 0 out of 5 stars0 ratingsBeginning Programming For Dummies Rating: 4 out of 5 stars4/5How to Write Effective Emails at Work Rating: 4 out of 5 stars4/5Agile Practice Guide Rating: 4 out of 5 stars4/5After Steve: How Apple Became a Trillion-Dollar Company and Lost Its Soul Rating: 4 out of 5 stars4/5Grokking Algorithms: An illustrated guide for programmers and other curious people Rating: 4 out of 5 stars4/5Managing Humans: Biting and Humorous Tales of a Software Engineering Manager Rating: 4 out of 5 stars4/5Engineering Management for the Rest of Us Rating: 5 out of 5 stars5/5Hacking for Beginners: Mastery Guide to Learn and Practice the Basics of Computer and Cyber Security Rating: 0 out of 5 stars0 ratingsWordpress 2023 A Beginners Guide : Design Your Own Website With WordPress 2023 Rating: 0 out of 5 stars0 ratingsFlow: A Handbook for Change-Makers, Mavericks, Innovators and Leaders Rating: 0 out of 5 stars0 ratingsKodi Made Easy: Complete Beginners Step by Step Guide on How to Install Kodi on Amazon Firestick Rating: 0 out of 5 stars0 ratingsSQL For Dummies Rating: 0 out of 5 stars0 ratingsAdobe Illustrator CC For Dummies Rating: 5 out of 5 stars5/5OneNote: The Ultimate Guide on How to Use Microsoft OneNote for Getting Things Done Rating: 1 out of 5 stars1/5The Inmates Are Running the Asylum (Review and Analysis of Cooper's Book) Rating: 4 out of 5 stars4/5Tiny Python Projects: Learn coding and testing with puzzles and games Rating: 4 out of 5 stars4/5Lua Game Development Cookbook Rating: 0 out of 5 stars0 ratingsAndroid App Development For Dummies Rating: 0 out of 5 stars0 ratingsTest-Driven iOS Development with Swift Rating: 5 out of 5 stars5/5Succeeding with AI: How to make AI work for your business Rating: 0 out of 5 stars0 ratings
Reviews for Modern CMake for C++
1 rating0 reviews
Book preview
Modern CMake for C++ - Rafał Świdziński
BIRMINGHAM—MUMBAI
Modern CMake for C++
Copyright © 2022 Packt Publishing
All rights reserved. No part of this book may be reproduced, stored in a retrieval system, or transmitted in any form or by any means, without the prior written permission of the publisher, except in the case of brief quotations embedded in critical articles or reviews.
Every effort has been made in the preparation of this book to ensure the accuracy of the information presented. However, the information contained in this book is sold without warranty, either express or implied. Neither the author, nor Packt Publishing or its dealers and distributors, will be held liable for any damages caused or alleged to have been caused directly or indirectly by this book.
Packt Publishing has endeavored to provide trademark information about all of the companies and products mentioned in this book by the appropriate use of capitals. However, Packt Publishing cannot guarantee the accuracy of this information.
Associate Group Product Manager: Richa Tripathi
Publishing Product Manager: Rohit Rajkumar
Senior Editor: Mark Dsouza
Content Development Editor: Divya Vijayan
Technical Editor: Joseph Aloocaran
Copy Editor: Safis Editing
Project Coordinator: Rashika Ba
Proofreader: Safis Editing
Indexer: Tejal Daruwale Soni
Production Designer: Jyoti Chauhan
Marketing Coordinator: Elizabeth Varghese
First published: February 2022
Production reference: 3131022
Published by Packt Publishing Ltd.
Livery Place
35 Livery Street
Birmingham
B3 2PB, UK.
ISBN 978-1-80107-005-8
www.packt.com
To my family: my parents, Bożena and Bogdan, my sisters, Ewelina and Justyna, and my wife, Katarzyna, for their ongoing support and advice.
– Rafał Świdziński
Contributors
About the author
Rafał Świdziński works as a staff engineer at Google. With over 10 years of professional experience as a full stack developer, he has been able to experiment with a vast multitude of programming languages and technologies. During this time, he has been building software under his own company and for corporations including Cisco Meraki, Amazon, and Ericsson.
Originally from Łódź, Poland, he now lives in London, UK, from where he runs a YouTube channel, Smok,
discussing topics related to software development. He tackles technical problems, including real-life and work-related challenges encountered by many people in the field. Throughout his work, he explains the technical concepts in detail and demystifies the art and science behind the role of software engineer. His primary focus is on high-quality code and the craftsmanship of programming.
About the reviewers
Sergio Guidi Tabosa Pessoa is a software engineer with more than 30 years of experience in software development and maintenance, from complex enterprise software projects to modern mobile applications. In the early days, he worked primarily with the Microsoft stack, but soon discovered the power of the UNIX and Linux operating systems. Even though he has worked with many languages over the years, C and C++ remain his favorite languages for their power and speed.
He has a bachelor's degree in computer science and an MBA in IT management and is always hungry to learn new technologies, break code, and learn from his mistakes. He currently lives in Brazil with his wife, two Yorkshire Terriers, and two cockatiels.
First and foremost, I would like to thank all the people involved in this project, including the author for crafting such a great piece of work, and Packt Publishing for giving me this opportunity. I also would like to thank my beautiful wife, Lucia, as well as Touché and Lion, for their patience and for allowing me the time needed to help with this book.
Holding an engineering degree from ENSEEIHT and a Ph.D. in computer science from UVSQ in France, Eric Noulard has been writing and compiling source code in a variety of languages for 20 years. A user of CMake since 2006, he has also been an active contributor to the project for several years. During his career, Eric has worked for private companies and government agencies. He is now employed by Antidot, a software vendor responsible for developing and marketing high-end information retrieval technology and solutions.
Mohammed Alqumairi is a software engineer at Cisco Meraki with experience in developing critical and performant backend services using a variety of languages and frameworks, with a particular focus on modern C++, CMake, and the Poco libraries. Mohammed graduated with honors from City, University of London, with a B.Sc. in Computer Science.
Table of Contents
Preface
Section 1: Introducing CMake
Chapter 1: First Steps with CMake
Technical requirements
Understanding the basics
What is CMake?
How does it work?
Installing CMake on different platforms
Docker
Windows
Linux
macOS
Building from the source
Mastering the command line
CMake
CTest
CPack
The CMake GUI
CCMake
Navigating the project files
The source tree
The build tree
Listfiles
CMakeLists.txt
CMakeCache.txt
The Config-files for packages
The cmake_install.cmake, CTestTestfile.cmake, and CPackConfig.cmake files
CMakePresets.json and CMakeUserPresets.json
Ignoring files in Git
Discovering scripts and modules
Scripts
Utility modules
Find-modules
Summary
Further reading
Chapter 2: The CMake Language
Technical requirements
The basics of the CMake Language syntax
Comments
Command invocations
Command arguments
Working with variables
Variable references
Using the environment variables
Using the cache variables
How to correctly use the variable scope in CMake
Using lists
Understanding control structures in CMake
Conditional blocks
Loops
Command definitions
Useful commands
The message() command
The include() command
The include_guard() command
The file() command
The execute_process() command
Summary
Further reading
Chapter 3: Setting Up Your First CMake Project
Technical requirements
Basic directives and commands
Specifying the minimum CMake version – cmake_minimum_required()
Defining languages and metadata – project()
Partitioning your project
Scoped subdirectories
Nested projects
External projects
Thinking about the project structure
Scoping the environment
Discovering the operating system
Cross-compilation – what are host and target systems?
Abbreviated variables
Host system information
Does the platform have 32-bit or 64-bit architecture?
What is the endianness of the system?
Configuring the toolchain
Setting the C++ standard
Insisting on standard support
Vendor-specific extensions
Interprocedural optimization
Checking for supported compiler features
Compiling a test file
Disabling in-source builds
Summary
Further reading
Section 2: Building With CMake
Chapter 4: Working with Targets
Technical requirements
The concept of a target
Dependency graph
Visualizing dependencies
Target properties
What are transitive usage requirements?
Dealing with conflicting propagated properties
Meet the pseudo targets
Build targets
Writing custom commands
Using a custom command as a generator
Using a custom command as a target hook
Understanding generator expressions
General syntax
Types of evaluation
Examples to try out
Summary
Further reading
Chapter 5: Compiling C++ Sources with CMake
Technical requirements
The basics of compilation
How compilation works
Initial configuration
Managing sources for targets
Preprocessor configuration
Providing paths to included files
Preprocessor definitions
Configuring the headers
Configuring the optimizer
General level
Function inlining
Loop unrolling
Loop vectorization
Managing the process of compilation
Reducing compilation time
Finding mistakes
Summary
Further reading
Chapter 6: Linking with CMake
Technical requirements
Getting the basics of linking right
Building different library types
Static libraries
Shared libraries
Shared modules
Position-independent code
Solving problems with the One Definition Rule
Dynamically linked duplicated symbols
Use namespaces – don't count on a linker
The order of linking and unresolved symbols
Separating main() for testing
Summary
Further reading
Chapter 7: Managing Dependencies with CMake
Technical requirements
How to find installed packages
Discovering legacy packages with FindPkgConfig
Writing your own find-modules
Working with Git repositories
Providing external libraries through Git submodules
Git-cloning dependencies for projects that don't use Git
Using ExternalProject and FetchContent modules
ExternalProject
FetchContent
Summary
Further reading
Section 3: Automating With CMake
Chapter 8: Testing Frameworks
Technical requirements
Why are automated tests worth the trouble?
Using CTest to standardize testing in CMake
Build-and-test mode
Test mode
Creating the most basic unit test for CTest
Structuring our projects for testing
Unit-testing frameworks
Catch2
GTest
GMock
Generating test coverage reports
Avoiding the SEGFAULT gotcha
Summary
Further reading
Chapter 9: Program Analysis Tools
Technical requirements
Enforcing the formatting
Using static checkers
Clang-Tidy
Cpplint
Cppcheck
include-what-you-use
Link what you use
Dynamic analysis with Valgrind
Memcheck
Memcheck-Cover
Summary
Further reading
Chapter 10: Generating Documentation
Technical requirements
Adding Doxygen to your project
Generating documentation with a modern look
Summary
Further reading
Other documentation generation utilities
Chapter 11: Installing and Packaging
Technical requirements
Exporting without installation
Installing projects on the system
Installing logical targets
Low-level installation
Invoking scripts during installation
Creating reusable packages
Understanding the issues with relocatable targets
Installing target export files
Writing basic config-files
Creating advanced config-files
Generating package version files
Defining components
How to use components in find_package()
How to use components in the install() command
Packaging with CPack
Summary
Further reading
Chapter 12: Creating Your Professional Project
Technical requirements
Planning our work
Project layout
Object libraries
Shared libraries versus static libraries
Project file structure
Building and managing dependencies
Building the Calc library
Building the Calc Console executable
Testing and program analysis
Preparing the coverage module
Preparing the Memcheck module
Applying testing scenarios
Adding static analysis tools
Installing and packaging
Installation of the library
Installation of the executable
Packaging with CPack
Providing the documentation
Automatic documentation generation
Not-as-technical documents of professional project
Summary
Further reading
Appendix: Miscellaneous Commands
The string() command
Search and replace
Manipulation
Comparison
Hashing
Generation
JSON
The list() command
Reading
Searching
Modification
Ordering
The file() command
Reading
Writing
Filesystem
Path conversion
Transfer
Locking
Archiving
The math() command
Why subscribe?
Other Books You May Enjoy
Preface
Creating top-notch software isn't an easy task. Developers researching this subject online frequently have problems determining which advice is up to date and which approaches have already been superseded by fresher, better practices. At the same time, most resources explain this process chaotically, without the proper background, context, and structure.
Modern CMake for C++ is an end-to-end guide offering a simpler experience, as it treats building C++ solutions in a comprehensive manner. It teaches you how to use CMake in your CMake projects, and also shows you what makes them maintainable, elegant, and clean. It guides you through the automation of complex tasks appearing in many projects, including building, testing, and packaging.
The book instructs you on how to form the source directories, as well as build targets and packages. As you progress, you will learn how to compile and link executables and libraries, how these processes work in detail, and how to optimize all steps to achieve the best results. You'll also understand how to add external dependencies to the project: third-party libraries, testing frameworks, program analysis tools, and documentation generators. Finally, you'll explore how to export, install, and package your solution for internal and external purposes.
After completing this book, you'll be able to use CMake confidently on a professional level.
Who this book is for
Learning the C++ language often isn't enough to prepare you for delivering projects to the highest standards. If you're interested in becoming a professional build engineer, a better software developer, or simply want to become proficient with CMake, if you'd like to understand how projects come together and why, if you're transitioning from a different build environment, or if you're interested in learning modern CMake from the ground up, then this book is for you.
What this book covers
Chapter 1, First Steps with CMake, covers how to install and use CMake's command line, along with what files make up the project.
Chapter 2, The CMake Language, provides key code information: comments, command invocations and arguments, variables, lists, and control structures.
Chapter 3, Setting Up Your First CMake Project, introduces the basic configuration of a project, the required CMake version, project metadata, and file structure, as well as the toolchain setup.
Chapter 4, Working with Targets, introduces the logical build targets that produce artifacts for executables and libraries.
Chapter 5, Compiling C++ Sources with CMake, explains how the details of compilation process works and how it can be controlled in a CMake project.
Chapter 6, Linking with CMake, provides general information on linking, static, and shared libraries. This chapter also explains how to structure a project so that it can be tested.
Chapter 7, Managing Dependencies with CMake, explains the dependency management methods available in modern CMake.
Chapter 8, Testing Frameworks, describes how to add the most popular testing frameworks to your project, as well as how to use the CTest utility available in the CMake toolset.
Chapter 9, Program Analysis Tools, covers how to perform automatic formatting, as well as static and dynamic analyses, in your project.
Chapter 10, Generating Documentation, explains how to use Doxygen to generate manuals for users straight from the C++ source code.
Chapter 11, Installing and Packaging, shows how to prepare your project to be used in other projects or installed on the system. We'll also see an explanation of the CPack utility.
Chapter 12, Creating Your Professional Project, sets out how to put together all the knowledge you have acquired hitherto in to a fully formed project.
Appendix: Miscellaneous Commands, provides a quick reference of the most popular commands: string(), list(), file(), and math().
To get the most out of this book
Basic familiarity with C++ and Unix-like systems is assumed throughout the book. Although this isn't a strict requirement, it will prove helpful in fully understanding the examples given in this book.
This book targets CMake 3.20, but most of the techniques described should work from CMake 3.15 (features that were added after are usually highlighted).
All examples have been tested on Debian with the following packages installed:
clang-format clang-tidy cppcheck doxygen g++ gawk git graphviz lcov libpqxx-dev libprotobuf-dev make pkg-config protobuf-compiler tree valgrind vim wget
To experience the same environment, it is recommended to use the Docker images, as explained in Chapter 1.
If you are using the digital version of this book, we advise you to type the code yourself or access the code from the book's GitHub repository (a link is available in the next section). Doing so will help you avoid any potential errors related to the copying and pasting of code.
Download the example code files
You can download the example code files for this book from GitHub at https://github.com/PacktPublishing/Modern-CMake-for-Cpp. If there's an update to the code, it will be updated in the GitHub repository.
We also have other code bundles from our rich catalog of books and videos available at https://github.com/PacktPublishing/. Check them out!
Download the color images
We also provide a PDF file that has color images of the screenshots and diagrams used in this book. You can download it here: https://static.packt-cdn.com/downloads/9781801070058_ColorImages.pdf.
Conventions used
There are a number of text conventions used throughout this book.
Code in text: Indicates code words in the text, database table names, folder names, filenames, file extensions, pathnames, dummy URLs, user input, and Twitter handles. Here is an example: Select Debug, Release, MinSizeRel, or RelWithDebInfo and specify it as follows.
A block of code is set as follows:
cmake_minimum_required(VERSION 3.20)
project(Hello)
add_executable(Hello hello.cpp)
When we wish to draw your attention to a particular part of a code block, the relevant lines or items are set in bold:
cmake_minimum_required(VERSION 3.20)
project(app)
message(Top level CMakeLists.txt
)
add_subdirectory(api)
Any command-line input or output is written as follows:
cmake --build
cmake --build
Bold: Indicates a new term, an important word, or words that you see on screen. For instance, words in menus or dialog boxes appear in bold. Here is an example: If all else fails and we need to use the big guns there is always trace mode.
Tips or Important Notes
Appear like this.
Get in touch
Feedback from our readers is always welcome.
General feedback: If you have questions about any aspect of this book, email us at [email protected] and mention the book title in the subject of your message.
Errata: Although we have taken every care to ensure the accuracy of our content, mistakes do happen. If you have found a mistake in this book, we would be grateful if you would report this to us. Please visit www.packtpub.com/support/errata and fill in the form.
Piracy: If you come across any illegal copies of our works in any form on the internet, we would be grateful if you would provide us with the location address or website name. Please contact us at [email protected] with a link to the material.
If you are interested in becoming an author: If there is a topic that you have expertise in and you are interested in either writing or contributing to a book, please visit authors.packtpub.com.
Share Your Thoughts
Once you've read Modern CMake for C++, we'd love to hear your thoughts! Please click here to go straight to the Amazon review page for this book and share your feedback.
Your review is important to us and the tech community and will help us make sure we're delivering excellent quality content.
Download a free PDF copy of this book
Thanks for purchasing this book!
Do you like to read on the go but are unable to carry your print books everywhere?
Is your eBook purchase not compatible with the device of your choice?
Don’t worry, now with every Packt book you get a DRM-free PDF version of that book at no cost.
Read anywhere, any place, on any device. Search, copy, and paste code from your favorite technical books directly into your application.
The perks don’t stop there, you can get exclusive access to discounts, newsletters, and great free content in your inbox daily
Follow these simple steps to get the benefits:
Scan the QR code or visit the link below
https://packt.link/free-ebook/9781801070058
Submit your proof of purchase
That’s it! We’ll send your free PDF and other benefits to your email directly
Section 1: Introducing CMake
Getting the basics right is critical to understanding the more advanced subjects and avoiding silly mistakes. This is where the majority of CMake users get in trouble: without a proper foundation, it's difficult to achieve the right outcome. No wonder. It's tempting to skip the introductory material and jump right in where the action is and get things done quickly. We address both points in this section by explaining the core topics of CMake and by hacking together a few lines of code to show what the simplest project looks like.
To build an appropriate mental context, we'll explain what CMake is exactly and how it does its job, along with what the command line is like. We'll talk about the different build stages and learn the language used to generate build systems. We'll also discuss CMake projects: what files they contain, how to approach their directory structure, and we'll explore their primary configuration.
This section comprises the following chapters:
Chapter 1, First Steps with CMake
Chapter 2, The CMake Language
Chapter 3, Setting Up Your First CMake Project
Chapter 1: First Steps with CMake
There is something magical about turning source code into a working application. It is not only the effect itself, that is, a working mechanism that we devise and bring to life, but the very process or act of exercising the idea into existence.
As programmers, we work in the following loop: design, code, and test. We invent changes, we phrase them in a language that the compiler understands, and we check whether they work as intended. To create a proper, high-quality application from our source code, we need to meticulously execute repetitive, error-prone tasks: invoking the correct commands, checking the syntax, linking binary files, running tests, reporting issues, and more.
It takes great effort to remember each step every single time. Instead, we want to stay focused on the actual coding and delegate everything else to automated tooling. Ideally, this process would start with a single button, right after we have changed our code. It would be smart, fast, extensible, and work in the same way across different OSs and environments. It would be supported by multiple Integrated Development Environments (IDEs) but also by Continuous Integration (CI) pipelines that test our software after a change is submitted to a shared repository.
CMake is the answer to many such needs; however, it requires a bit of work to configure and use correctly. This is not because CMake is unnecessarily complex but because the subject that we're dealing with here is. Don't worry. We'll undergo this whole learning process very methodically; before you know it, you will have become a building guru.
I know you're eager to rush off to start writing your own CMake projects, and I applaud your attitude. Since your projects will be primarily for users (yourself included), it's important for you to understand that perspective as well.
So, let's start with just that: becoming a CMake power user. We'll go through a few basics: what this tool is, how it works in principle, and how to install it. Then, we'll do a deep dive on the command line and modes of operation. Finally, we'll wrap up with the purposes of different files in a project, and we'll explain how to use CMake without creating a project at all.
In this chapter, we're going to cover the following main topics:
Understanding the basics
Installing CMake on different platforms
Mastering the command line
Navigating the project files
Discovering scripts and modules
Technical requirements
You can find the code files that are present in this chapter on GitHub at https://github.com/PacktPublishing/Modern-CMake-for-Cpp/tree/main/examples/chapter01.
To build examples provided in this book always use recommended commands:
cmake -B
cmake --build
Be sure to replace placeholders
Understanding the basics
The compilation of C++ source code appears to be a fairly straightforward process. Let's take a small program, such as a classic hello.cpp application, as follows:
chapter-01/01-hello/hello.cpp
#include
int main() {
std::cout << Hello World!
<< std::endl;
return 0;
}
Now, all we need to do to get an executable is to run a single command. We call the compiler with the filename as an argument:
$ g++ hello.cpp -o a.out
Our code is correct, so the compiler will silently produce an executable binary file that our machine can understand. We can run it by calling its name:
$ ./a.out
Hello World!
$
However, as our projects grow, you will quickly understand that keeping everything in a single file is simply not possible. Clean code practices recommend that files should be kept small and in well-organized structures. The manual compilation of every file can be a tiresome and fragile process. There must be a better way.
What is CMake?
Let's say we automate building by writing a script that goes through our project tree and compiles everything. To avoid any unnecessary compilations, our script will detect whether the source has been modified since the last time we ran it (the script). Now, we'd like a convenient way to manage arguments that are passed to the compiler for each file – preferably, we'd like to do that based on configurable criteria. Additionally, our script should know how to link all of the compiled files in a binary or, even better, build whole solutions that can be reused and incorporated as modules in bigger projects.
The more features we will add the higher the chance that we will get to a full-fledged solution. Building software is a very versatile process and can span multiple different aspects:
Compiling executables and libraries
Managing dependencies
Testing
Installing
Packaging
Producing documentation
Testing some more
It would take a very long time to come up with a truly modular and powerful C++ building application that is fit for every purpose. And it did. Bill Hoffman at Kitware implemented the first versions of CMake over 20 years ago. As you might have already guessed, it was very successful. It now has a lot of features and support from the community. Today, CMake is being actively developed and has become the industry standard for C and C++ programmers.
The problem of building code in an automated way is much older than CMake, so naturally, there are plenty of options out there: Make, Autotools, SCons, Ninja, Premake, and more. But why does CMake have the upper hand?
There are a couple of things about CMake that I find (granted, subjectively) important:
It stays focused on supporting modern compilers and toolchains.
CMake is truly cross-platform – it supports building for Windows, Linux, macOS, and Cygwin.
It generates project files for popular IDEs: Microsoft Visual Studio, Xcode, and Eclipse CDT. Additionally, it is a project model for others such as CLion.
CMake operates on just the right level of abstraction – it allows you to group files in reusable targets and projects.
There are tons of projects that are built with CMake and offer an easy way to include them in your project.
CMake views testing, packaging, and installing as an inherent part of the build process.
Old, unused features get deprecated to keep CMake lean.
CMake provides a unified, streamlined experience across the board. It doesn't matter if you're building your software in an IDE or directly from the command line; what's really important is it takes care of post-build stages as well. Your Continous Integration/Continous Deployment (CI/CD) pipeline can easily use the same CMake configuration and build projects using a single standard even if all of the preceding environments differ.
How does it work?
You might be under the impression that CMake is a tool that reads source code on one end and produces binaries on the other – while that's true in principle, it's not the full picture.
CMake can't build anything on its own – it relies on other tools in the system to perform the actual compilation, linking, and other tasks. You can think of it as the orchestrator of your building process: it knows what steps need to be done, what the end goal is, and how to find the right workers and materials for the job.
This process has three stages:
Configuration
Generation
Building
The configuration stage
This stage is about reading project details stored in a directory, called the source tree, and preparing an output directory or build tree for the generation stage.
CMake starts by creating an empty build tree and collecting all of the details about the environment it is working in, for example, the architecture, the available compilers, the linkers, and the archivers. Additionally, it checks whether a simple test program can be compiled correctly.
Next, the CMakeLists.txt project configuration file is parsed and executed (yes, CMake projects are configured with CMake's coding language). This file is the bare minimum of a CMake project (source files can be added later). It tells CMake about the project structure, its targets, and its dependencies (libraries and other CMake packages). During this process, CMake stores collected information in the build tree such as system details, project configurations, logs, and temp files, which are used for the next step. Specifically, a CMakeCache.txt file is created to store more stable variables (such as paths to compilers and other tools) and save time during the next configuration.
The generation stage
After reading the project configuration, CMake will generate a buildsystem for the exact environment it is working in. Buildsystems are simply cut-to-size configuration files for other build tools (for example, Makefiles for GNU Make or Ninja and IDE project files for Visual Studio). During this stage, CMake can still apply some final touches to the build configuration by evaluating generator expressions.
Note
The generation stage is executed automatically after the configuration stage. For this reason, this book and other resources often refer to both of these stages when mentioning configuration
or generation
of a buildsystem. To explicitly run just the configuration stage, you can use the cmake-gui utility.
The building stage
To produce the final artifacts specified in our project, we have to run the appropriate build tool. This can be invoked directly, through an IDE, or using the CMake command. In turn, these build tools will execute steps to produce targets with compilers, linkers, static and dynamic analysis tools, test frameworks, reporting tools, and anything else you can think of.
The beauty of this solution lies in the ability to produce buildsystems on demand for every platform with a single configuration (that is, the same project files):
Figure 1.1 – The stages of CMakeFigure 1.1 – The stages of CMake
Do you remember our hello.cpp application from the Understanding the basics section? CMake makes it really easy for you to build it. All we need is the following CMakeLists.txt file next to our source and two simple commands, cmake -B buildtree and cmake --build buildtree, as follows:
chapter01/01-hello/CMakeLists.txt: Hello world in the CMake language
cmake_minimum_required(VERSION 3.20)
project(Hello)
add_executable(Hello hello.cpp)
Here is the output from the Dockerized Linux system (note that we'll discuss Docker in the Installing CMake on different platforms section):
root@5f81fe44c9bd:/root/examples/chapter01/01-hello# cmake -B buildtree.
-- The C compiler identification is GNU 9.3.0
-- The CXX compiler identification is GNU 9.3.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /root/examples/chapter01/01-hello/buildtree
root@5f81fe44c9bd:/root/examples/chapter01/01-hello# cmake --build buildtree/
Scanning dependencies of target Hello
[ 50%] Building CXX object CMakeFiles/Hello.dir/hello.cpp.o
[100%] Linking CXX executable Hello
[100%] Built target Hello
All that's left is to run it:
root@68c249f65ce2:~# ./buildtree/Hello
Hello World!
Here, we have generated a buildsystem that is stored in the buildtree directory. Following this, we executed the build stage and produced a final binary that we were able to run.
Now you know what the end result looks like, I'm sure you will be full of questions: what are the prerequisites to this process? What do these commands mean? Why do we need two of them? How do I write my own project files? Do not worry – these questions will be answered in the following sections.
Getting Help
This book will provide you with the most important information that is relevant to the current version of CMake (at the time of writing, this is 3.20). To provide you with