Modern CMake for C++ Discover a better approach to building, testing, and packaging your software 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: 1250222 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 1 First Steps with CMake Technical requirements 4 The source tree 30 Understanding the basics 5 The build tree 30 Listfiles 31 What is CMake? 5 CMakeLists.txt 32 How does it work? 7 CMakeCache.txt 33 Installing CMake on different The Config-files for packages 34 platforms 10 The cmake_install.cmake, Docker 11 CTestTestfile.cmake, and CPackConfig. cmake files 35 Windows 12 CMakePresets.json and Linux 13 CMakeUserPresets.json 35 macOS 13 Ignoring files in Git 39 Building from the source 14 Discovering scripts and modules 40 Mastering the command line 14 Scripts 40 CMake 15 Utility modules 41 CTest 26 Find-modules 41 CPack 27 The CMake GUI 28 Summary 42 CCMake 29 Further reading 42 Navigating the project files 30 viii Table of Contents 2 The CMake Language Technical requirements 44 Understanding control The basics of the CMake structures in CMake 63 Language syntax 45 Conditional blocks 63 Comments 45 Loops 68 Command invocations 47 Command definitions 70 Command arguments 49 Useful commands 76 Working with variables 53 The message() command 76 Variable references 54 The include() command 78 Using the environment variables 55 The include_guard() command 79 Using the cache variables 57 The file() command 79 How to correctly use the variable The execute_process() command 79 scope in CMake 59 Summary 80 Using lists 61 Further reading 81 3 Setting Up Your First CMake Project Technical requirements 84 Cross-compilation – what are host and target systems? 100 Basic directives and commands 85 Abbreviated variables 100 Specifying the minimum CMake Host system information 101 version – cmake_minimum_required() 85 Does the platform have 32-bit or 64-bit Defining languages and metadata – architecture? 102 project() 86 What is the endianness of the system? 103 Partitioning your project 87 Configuring the toolchain 103 Scoped subdirectories 90 Setting the C++ standard 103 Nested projects 92 Insisting on standard support 104 External projects 92 Vendor-specific extensions 105 Thinking about the project Interprocedural optimization 105 structure 93 Checking for supported compiler Scoping the environment 99 features 106 Compiling a test file 106 Discovering the operating system 99 Table of Contents ix Disabling in-source builds 108 Further reading 111 Summary 110 Section 2: Building With CMake 4 Working with Targets Technical requirements 116 Using a custom command as a generator 132 The concept of a target 116 Using a custom command as a target Dependency graph 118 hook 134 Visualizing dependencies 121 Target properties 122 Understanding generator What are transitive usage expressions 135 requirements? 123 General syntax 136 Dealing with conflicting propagated Types of evaluation 137 properties 126 Examples to try out 144 Meet the pseudo targets 128 Build targets 130 Summary 148 Further reading 148 Writing custom commands 131 5 Compiling C++ Sources with CMake Technical requirements 152 General level 165 The basics of compilation 152 Function inlining 167 Loop unrolling 168 How compilation works 153 Loop vectorization 170 Initial configuration 155 Managing sources for targets 156 Managing the process of compilation 171 Preprocessor configuration 158 Reducing compilation time 171 Providing paths to included files 158 Finding mistakes 176 Preprocessor definitions 159 Configuring the headers 162 Summary 182 Configuring the optimizer 164 Further reading 183