Modern CMake for C++ - Second Edition

Book description

Gain proficiency in CMake and unlock the complete potential of C++ to develop exceptional projects Purchase of the print or Kindle book includes a free eBook in the PDF format

Key Features

  • Get to grips with CMake and take your C++ development skills to enterprise standards
  • Use hands-on exercises and self-assessment questions to lock-in your learning
  • Understand how to build in an array of quality checks and tests for robust code

Book Description

Modern CMake for C++ isn't just another reference book, or a repackaging of the documentation, but a blueprint to bridging the gap between learning C++ and being able to use it in a professional setting. It's an end-to-end guide to the automation of complex tasks, including building, testing, and packaging software.

This second edition is significantly rewritten, restructured and refreshed with latest additions to CMake, such as support of C++20 Modules.

In this book, you'll not only learn how to use the CMake language in CMake projects but also discover how to make those projects maintainable, elegant, and clean. As you progress, you'll dive into the structure of source directories, building targets, and packages, all while learning how to compile and link executables and libraries. You'll also gain a deeper understanding of how those processes work and how to optimize builds in CMake for the best results. You'll discover how to use external dependencies in your project – third-party libraries, testing frameworks, program analysis tools, and documentation generators. Finally, you'll gain profi ciency in exporting, installing, and packaging for internal and external purposes.

By the end of this book, you'll be able to use CMake confi dently at a professional level.

What you will learn

  • Understand best practices to build ++ code
  • Gain practical knowledge of the CMake language
  • Guarantee code quality with tests and static and dynamic analysis
  • Discover how to manage, discover, download, and link dependencies with CMake
  • Build solutions that can be reused and maintained in the long term
  • Understand how to optimize build artifacts and the build process
  • Program modern CMake and manage your build processes
  • Acquire expertise in complex subjects such as CMake presets

Who this book is for

The book is for build engineers and software developers with knowledge of C/C++ programming who are looking to learn CMake to automate the process of building small and large software solutions. If you’re just getting started with CMake, a long-time GNU Make user, or simply looking to brush up on the latest best practices, this book is for you.

Table of contents

  1. Preface
    1. Who this book is for
    2. What this book covers
    3. To get the most out of this book
    4. Get in touch
  2. First Steps with CMake
    1. Technical requirements
    2. Understanding the basics
      1. What is CMake?
      2. How does it work?
        1. The configuration stage
        2. The generation stage
        3. The building stage
    3. Installing CMake on different platforms
      1. Docker
      2. Windows
      3. Linux
      4. macOS
      5. Building from the source
    4. Mastering the command line
      1. CMake command line
        1. Generating a project buildsystem
        2. Building a project
        3. Installing a project
        4. Running a script
        5. Running a command-line tool
        6. Running a workflow preset
        7. Getting help
      2. CTest command line
      3. CPack command line
      4. CMake GUI
      5. CCMake command line
    5. Navigating project directories and files
      1. The source tree
      2. The build tree
      3. Listfiles
        1. Project file
        2. Cache file
        3. Package definition file
        4. Generated files
      4. JSON and YAML files
        1. Preset files
        2. File-based API
        3. Configure log
      5. Ignoring files in Git
    6. Discovering scripts and modules
      1. Scripts
      2. Utility modules
      3. Find-modules
    7. Summary
    8. Further reading
  3. The CMake Language
    1. Technical requirements
    2. The basics of the CMake language syntax
      1. Comments
      2. Command invocations
      3. Command arguments
        1. Bracket arguments
        2. Quoted arguments
        3. Unquoted arguments
    3. Working with variables
      1. Variable references
      2. Using environment variables
      3. Using cache variables
      4. How to correctly use variable scopes in CMake
    4. Using lists
    5. Understanding control structures in CMake
      1. Conditional blocks
        1. The syntax for conditional commands
      2. Loops
        1. while()
        2. foreach() loops
      3. Command definitions
        1. Macros
        2. Functions
        3. The procedural paradigm in CMake
        4. A word on naming conventions
    6. Exploring the frequently used commands
      1. The message() command
      2. The include() command
      3. The include_guard() command
      4. The file() command
      5. The execute_process() command
    7. Summary
    8. Further reading
  4. Using CMake in Popular IDEs
    1. Getting to know IDEs
      1. Choosing an IDE
        1. Choose a comprehensive IDE
        2. Choose an IDE that is widely supported in your organization
        3. Don’t pick an IDE based on the target OS and platform
        4. Pick an IDE with remote development support
      2. Installing toolchains
      3. Using this book’s examples with IDEs
    2. Starting with the CLion IDE
      1. Why you might like it
      2. Take your first steps
      3. Advanced feature: Debugger on steroids
    3. Starting with Visual Studio Code
      1. Why you might like it
      2. Take your first steps
      3. Advanced feature: Dev Containers
    4. Starting with the Visual Studio IDE
      1. Why you might like it
      2. Take your first steps
      3. Advanced feature: Hot Reload debugging
    5. Summary
    6. Further reading
  5. Setting Up Your First CMake Project
    1. Technical requirements
    2. Understanding the basic directives and commands
      1. Specifying the minimum CMake version
      2. Defining languages and metadata
    3. Partitioning your project
      1. Managing scope with subdirectories
      2. When to use nested projects
      3. Keeping external projects external
    4. Thinking about the project structure
    5. Scoping the environment
      1. Detecting the operating system
      2. Cross-compilation – what are host and target systems?
      3. Abbreviated variables
      4. Host system information
      5. Does the platform have 32-bit or 64-bit architecture?
      6. What is the endianness of the system?
    6. Configuring the toolchain
      1. Setting the C++ standard
      2. Insisting on standard support
      3. Vendor-specific extensions
      4. Interprocedural optimization
      5. Checking for supported compiler features
      6. Compiling a test file
    7. Disabling in-source builds
    8. Summary
    9. Further reading
  6. Working with Targets
    1. Technical requirements
    2. Understanding the concept of a target
      1. Defining executable targets
      2. Defining library targets
      3. Custom targets
      4. Dependency graph
      5. Visualizing dependencies
      6. Setting properties of targets
        1. What are Transitive Usage Requirements?
        2. Dealing with conflicting propagated properties
      7. Meet the pseudo targets
        1. Imported targets
        2. Alias targets
        3. Interface libraries
      8. Object libraries
      9. Build targets
    3. Writing custom commands
      1. Using a custom command as a generator
      2. Using a custom command as a target hook
    4. Summary
    5. Further reading
  7. Using Generator Expressions
    1. Technical requirements
    2. What are generator expressions?
    3. Learning the basic rules of general expression syntax
      1. Nesting
    4. Conditional expansion
      1. Evaluating to Boolean
        1. Logical operators
        2. Comparisons
        3. Queries
    5. Querying and transforming
      1. Dealing with strings, lists, and paths
      2. Parametrizing the build configuration and platform
      3. Tuning for toolchain
      4. Querying target-related information
      5. Escaping
    6. Trying out examples
      1. Build configurations
      2. System-specific one liners
      3. Interface libraries with compiler-specific flags
      4. Nested generator expressions
      5. The difference between a conditional expression and the evaluation of a BOOL operator
    7. Summary
    8. Further reading
  8. Compiling C++ Sources with CMake
    1. Technical requirements
    2. The basics of compilation
      1. How compilation works
      2. Initial configuration
        1. Requiring specific features from the compiler
      3. Managing sources for targets
    3. Configuring the preprocessor
      1. Providing paths to included files
      2. Preprocessor definitions
        1. Avoid accessing private class fields in your unit tests
        2. Using git commit to track a compiled version
      3. Configuring the headers
    4. Configuring the optimizer
      1. General level
      2. Function inlining
      3. Loop unrolling
      4. Loop vectorization
    5. Managing the process of compilation
      1. Reducing compilation time
        1. Precompilation of headers
        2. Unity builds
      2. Finding mistakes
        1. Configuring errors and warnings
        2. Debugging the build
        3. Providing information for the debugger
    6. Summary
    7. Further reading
  9. Linking Executables and Libraries
    1. Technical requirements
    2. Getting the basics of linking right
    3. Building different library types
      1. Static libraries
      2. Shared libraries
      3. Shared modules
      4. Position-independent code (PIC)
    4. Solving problems with the ODR
      1. Sorting out dynamically linked duplicated symbols
      2. Use namespaces – don’t count on the linker
    5. The order of linking and unresolved symbols
      1. Dealing with unreferenced symbols
    6. Separating main() for testing
    7. Summary
    8. Further reading
  10. Managing Dependencies in CMake
    1. Technical requirements
    2. Using already installed dependencies
      1. Finding packages with CMake’s find_package()
        1. Writing your own find modules
      2. Discovering legacy packages with FindPkgConfig
    3. Using dependencies not present in the system
      1. FetchContent
        1. Basic example with a YAML reader
        2. Downloading the dependencies
        3. Updating and patching
        4. Using the installed dependency where possible
      2. ExternalProject
    4. Summary
    5. Further reading
  11. Using the C++20 Modules
    1. Technical requirements
    2. What are the C++20 modules?
    3. Writing projects with C++20 module support
      1. Enabling the experimental support in CMake 3.26 and 3.27
      2. Enabling support for CMake 3.28 and up
      3. Setting the compiler requirements
      4. Declaring a C++ module
    4. Configuring the toolchain
    5. Summary
    6. Further reading
  12. Testing Frameworks
    1. Technical requirements
    2. Why are automated tests worth the trouble?
    3. Using CTest to standardize testing in CMake
      1. Build-and-test mode
      2. Test mode
        1. Querying tests
        2. Filtering tests
        3. Shuffling tests
        4. Handling failures
        5. Repeating tests
        6. Controlling output
        7. Miscellaneous
    4. Creating the most basic unit test for CTest
    5. Structuring our projects for testing
    6. Unit-testing frameworks
      1. Catch2
      2. GoogleTest
        1. Using GTest
        2. GMock
    7. Generating test coverage reports
      1. Using LCOV for coverage reports
      2. Avoiding the SEGFAULT gotcha
    8. Summary
    9. Further reading
  13. Program Analysis Tools
    1. Technical requirements
    2. Enforcing formatting
    3. Using static checkers
      1. clang-tidy
      2. Cpplint
      3. Cppcheck
      4. include-what-you-use
      5. Link What You Use
    4. Dynamic analysis with Valgrind
      1. Memcheck
      2. Memcheck-Cover
    5. Summary
    6. Further reading
  14. Generating Documentation
    1. Technical requirements
    2. Adding Doxygen to your project
    3. Generating documentation with a modern look
    4. Enhancing output with custom HTML
    5. Summary
    6. Further reading
  15. Installing and Packaging
    1. Technical requirements
    2. Exporting without installation
    3. Installing projects on the system
      1. Installing logical targets
        1. Utilizing the default destination for different platforms
        2. Dealing with public headers
      2. Low-level installation
        1. Installing with install(FILES) and install(PROGRAMS)
        2. Working with entire directories
      3. Invoking scripts during installation
      4. Installing runtime dependencies
    4. Creating reusable packages
      1. Understanding the issues with relocatable targets
      2. Installing target export files
      3. Writing basic config files
      4. Creating advanced config files
      5. Generating package version files
    5. Defining components
      1. How to use components in find_package()
      2. How to use components in the install() command
      3. Managing symbolic links for versioned shared libraries
    6. Packaging with CPack
    7. Summary
    8. Further reading
  16. Creating Your Professional Project
    1. Technical requirements
    2. Planning our work
    3. Project layout
      1. Shared libraries versus static libraries
      2. Project file structure
    4. Building and managing dependencies
      1. Building the Calc library
      2. Building the Calc console executable
    5. Testing and program analysis
      1. Preparing the Coverage module
      2. Preparing the Memcheck module
      3. Applying testing scenarios
      4. Adding static analysis tools
    6. Installing and packaging
      1. Installation of the library
      2. Installation of the executable
      3. Packaging with CPack
    7. Providing the documentation
      1. Generating the technical documentation
      2. Writing non-technical documents for a professional project
    8. Summary
    9. Further reading
  17. Writing CMake Presets
    1. Technical requirements
    2. Using presets defined in a project
    3. Writing a preset file
    4. Defining stage-specific presets
      1. Common features across presets
        1. Unique name fields
        2. Optional fields
        3. Association with configuration-stage presets
      2. Defining configuration-stage presets
      3. Defining build-stage presets
      4. Defining test-stage presets
      5. Defining package-stage presets
      6. Adding the installation preset
    5. Defining workflow presets
    6. Adding conditions and macros
    7. Summary
    8. Further reading
  18. Appendix
    1. Miscellaneous commands
    2. The string() command
      1. Search and replace
      2. Manipulation
      3. Comparison
      4. Hashing
      5. Generation
      6. JSON
    3. The list() command
      1. Reading
      2. Searching
      3. Modification
      4. Ordering
    4. The file() command
      1. Reading
      2. Writing
      3. Filesystem
      4. Path conversion
      5. Transfer
      6. Locking
      7. Archiving
    5. The math() command
  19. Other Books You May Enjoy
  20. Index

Product information

  • Title: Modern CMake for C++ - Second Edition
  • Author(s): Rafał Świdziński
  • Release date: May 2024
  • Publisher(s): Packt Publishing
  • ISBN: 9781805121800