Configuration and Cache Variables.rst 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606
  1. Step 3: Configuration and Cache Variables
  2. =========================================
  3. CMake projects often have some project-specific configuration variables which
  4. users and packagers are interested in. CMake has many ways that an invoking
  5. user or process can communicate these configuration choices, but the most
  6. fundamental of them are :option:`-D <cmake -D>` flags.
  7. In this step we'll explore the ins and out of how to provide project
  8. configuration options from within a CML, and how to invoke CMake to take
  9. advantage of configuration options provided by both CMake and individual
  10. projects.
  11. Background
  12. ^^^^^^^^^^
  13. If we had a CMake project for compression software which supported multiple
  14. compression algorithms, we might want to let the packager of the project decide
  15. which algorithms to enable when they build our software. We can do so by
  16. consuming variables set via :option:`-D <cmake -D>` flags.
  17. .. code-block:: cmake
  18. if(COMPRESSION_SOFTWARE_USE_ZLIB)
  19. message("I will use Zlib!")
  20. # ...
  21. endif()
  22. if(COMPRESSION_SOFTWARE_USE_ZSTD)
  23. message("I will use Zstd!")
  24. # ...
  25. endif()
  26. .. code-block:: console
  27. $ cmake -B build \
  28. -DCOMPRESSION_SOFTWARE_USE_ZLIB=ON \
  29. -DCOMPRESSION_SOFTWARE_USE_ZSTD=OFF
  30. ...
  31. I will use Zlib!
  32. Of course, we will want to provide reasonable defaults for these configuration
  33. choices, and a way to communicate the purpose of a given option. This function
  34. is provided by the :command:`option` command.
  35. .. code-block:: cmake
  36. option(COMPRESSION_SOFTWARE_USE_ZLIB "Support Zlib compression" ON)
  37. option(COMPRESSION_SOFTWARE_USE_ZSTD "Support Zstd compression" ON)
  38. if(COMPRESSION_SOFTWARE_USE_ZLIB)
  39. # Same as before
  40. # ...
  41. .. code-block:: console
  42. $ cmake -B build \
  43. -DCOMPRESSION_SOFTWARE_USE_ZLIB=OFF
  44. ...
  45. I will use Zstd!
  46. The names created by :option:`-D <cmake -D>` flags and :command:`option` are
  47. not normal variables, they are **cache** variables. Cache variables are globally
  48. visible variables which are *sticky*, their value is difficult to change after
  49. it is initially set. In fact they are so sticky that, in project mode, CMake
  50. will save and restore cache variables across multiple configurations. If a
  51. cache variable is set once, it will remain until another :option:`-D <cmake -D>`
  52. flag preempts the saved variable.
  53. .. note::
  54. CMake itself has dozens of normal and cache variables used for configuration.
  55. These are documented at :manual:`cmake-variables(7)` and operate in the same
  56. manner as project-provided variables for configuration.
  57. :command:`set` can also be used to manipulate cache variables, but will not
  58. change a variable which has already been created.
  59. .. code-block:: cmake
  60. set(StickyCacheVariable "I will not change" CACHE STRING "")
  61. set(StickyCacheVariable "Overwrite StickyCache" CACHE STRING "")
  62. message("StickyCacheVariable: ${StickyCacheVariable}")
  63. .. code-block:: console
  64. $ cmake -P StickyCacheVariable.cmake
  65. StickyCacheVariable: I will not change
  66. Because :option:`-D <cmake -D>` flags are processed before any other commands,
  67. they take precedence for setting the value of a cache variable.
  68. .. code-block:: console
  69. $ cmake \
  70. -DStickyCacheVariable="Commandline always wins" \
  71. -P StickyCacheVariable.cmake
  72. StickyCacheVariable: Commandline always wins
  73. While cache variables cannot ordinarily be changed, they can be *shadowed* by
  74. normal variables. We can observe this by :command:`set`'ing a variable to have
  75. the same name as a cache variable, and then using :command:`unset` to remove
  76. the normal variable.
  77. .. code-block:: cmake
  78. set(ShadowVariable "In the shadows" CACHE STRING "")
  79. set(ShadowVariable "Hiding the cache variable")
  80. message("ShadowVariable: ${ShadowVariable}")
  81. unset(ShadowVariable)
  82. message("ShadowVariable: ${ShadowVariable}")
  83. .. code-block:: console
  84. $ cmake -P ShadowVariable.cmake
  85. ShadowVariable: Hiding the cache variable
  86. ShadowVariable: In the shadows
  87. Exercise 1 - Using Options
  88. ^^^^^^^^^^^^^^^^^^^^^^^^^^
  89. We can imagine a scenario where consumers really want our ``MathFunctions``
  90. library, and the ``Tutorial`` utility is a "take it or leave it" add-on. In
  91. that case, we might want to add an option to allow consumers to disable
  92. building our ``Tutorial`` binary, building only the ``MathFunctions`` library.
  93. With our knowledge of options, conditionals, and cache variables we have all
  94. the pieces we need to make this configuration available.
  95. Goal
  96. ----
  97. Add an option named ``TUTORIAL_BUILD_UTILITIES`` to control if the ``Tutorial``
  98. binary is configured and built.
  99. .. note::
  100. CMake allows us to determine which targets are built after configuration. Our
  101. users could ask for the ``MathFunctions`` library alone without ``Tutorial``.
  102. CMake also has mechanisms to exclude targets from ``ALL``, the default target
  103. which builds all the other available targets.
  104. However, options which completely exclude targets from the configuration are
  105. convenient and popular, especially if configuring those targets involves
  106. heavy-weight steps which might take some time.
  107. It also simplifies :command:`install()` logic, which we'll discuss in later
  108. steps, if targets the packager is uninterested in are completely excluded.
  109. Helpful Resources
  110. -----------------
  111. * :command:`option`
  112. * :command:`if`
  113. Files to Edit
  114. -------------
  115. * ``CMakeLists.txt``
  116. Getting Started
  117. ---------------
  118. The ``Help/guide/tutorial/Step3`` folder contains the complete, recommended
  119. solution to ``Step1`` and the relevant ``TODOs`` for this step. Take a minute
  120. to review and refamiliarize yourself with the ``Tutorial`` project.
  121. When you feel you have an understanding of the current code, start with
  122. ``TODO 1`` and complete through ``TODO 2``.
  123. Build and Run
  124. -------------
  125. We can now reconfigure our project. However, this time we want to control the
  126. configuration via :option:`-D <cmake -D>` flags. We again start by navigating
  127. to ``Help/guide/tutorial/Step3`` and invoking CMake, but this time with our
  128. configuration options.
  129. .. code-block:: console
  130. cmake -B build -DTUTORIAL_BUILD_UTILITIES=OFF
  131. We can now build as usual.
  132. .. code-block:: console
  133. cmake --build build
  134. After the build we should observe no Tutorial executable is produced. Because
  135. cache variables are sticky even a reconfigure shouldn't change this, despite
  136. the default-``ON`` option.
  137. .. code-block:: console
  138. cmake -B build
  139. cmake --build build
  140. Will not produce the Tutorial executable, the cache variables are "locked in".
  141. To change this we have two options. First, we can edit the file which stores
  142. the cache variables between CMake configuration runs, the "CMake Cache". This
  143. file is ``build/CMakeCache.txt``, in it we can find the option cache variable.
  144. .. code-block:: text
  145. //Build the Tutorial executable
  146. TUTORIAL_BUILD_UTILITIES:BOOL=OFF
  147. We can change this from ``OFF`` to ``ON``, rerun the build, and we will get
  148. our ``Tutorial`` executable.
  149. .. note::
  150. ``CMakeCache.txt`` entries are of the form ``<Name>:<Type>=<Value>``, however
  151. the "type" is only a hint. All objects in CMake are strings, regardless of
  152. what the cache says.
  153. Alternatively, we can change the value of the cache variable on the command
  154. line, because the command line runs before ``CMakeCache.txt`` is loaded its
  155. value take precedence over those in the cache file.
  156. .. code-block:: console
  157. cmake -B build -DTUTORIAL_BUILD_UTILITIES=ON
  158. cmake --build build
  159. Doing so we observe the value in ``CMakeCache.txt`` has flipped from ``OFF``
  160. to ``ON``, and that the ``Tutorial`` executable is built.
  161. Solution
  162. --------
  163. First we create our :command:`option` to provide our cache variable with a
  164. reasonable default value.
  165. .. raw:: html
  166. <details><summary>TODO 1: Click to show/hide answer</summary>
  167. .. literalinclude:: Step4/CMakeLists.txt
  168. :caption: TODO 1: CMakeLists.txt
  169. :name: CMakeLists.txt-option-TUTORIAL_BUILD_UTILITIES
  170. :language: cmake
  171. :start-at: option(TUTORIAL_BUILD_UTILITIES
  172. :end-at: option(TUTORIAL_BUILD_UTILITIES
  173. .. raw:: html
  174. </details>
  175. Then we can check the cache variable to conditionally enable the ``Tutorial``
  176. executable (by way of adding its subdirectory).
  177. .. raw:: html
  178. <details><summary>TODO 2: Click to show/hide answer</summary>
  179. .. literalinclude:: Step4/CMakeLists.txt
  180. :caption: TODO 2: CMakeLists.txt
  181. :name: CMakeLists.txt-if-TUTORIAL_BUILD_UTILITIES
  182. :language: cmake
  183. :start-at: if(TUTORIAL_BUILD_UTILITIES)
  184. :end-at: endif()
  185. .. raw:: html
  186. </details>
  187. Exercise 2 - ``CMAKE`` Variables
  188. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  189. CMake has several important normal and cache variables provided to allow
  190. packagers to control the build. Decisions such as compilers, default flags,
  191. search locations for packages, and much more are all controlled by CMake's
  192. own configuration variables.
  193. Among the most important are language standards. As the language standard can
  194. have significant impact on the ABI presented by a given package. For example,
  195. it's quite common for libraries to use standard C++ templates on later
  196. standards, and provide polyfills on earlier standards. If a library is consumed
  197. under different standards then ABI incompatibilities between the standard
  198. templates and the polyfills can result in incomprehensible errors and runtime
  199. crashes.
  200. Ensuring all of our targets are built under the same language standard is
  201. achieved with the :variable:`CMAKE_<LANG>_STANDARD` cache variables. For C++,
  202. this is ``CMAKE_CXX_STANDARD``.
  203. .. note::
  204. Because these variables are so important, it is equally important that
  205. developers not override or shadow them in their CMLs. Shadowing
  206. :variable:`CMAKE_<LANG>_STANDARD` in a CML because the library wants C++20,
  207. when the packager has decided to build the rest of their libraries and
  208. applications with C++23, can lead to the aforementioned terrible,
  209. incomprehensible errors.
  210. Do not :command:`set` ``CMAKE_`` globals without very strong reasons for
  211. doing so. We'll discuss better methods for targets to communicate
  212. requirements like definitions and minimum standards in later steps.
  213. In this exercise, we'll introduce some C++20 code into our library and
  214. executable and build them with C++20 by setting the appropriate cache variable.
  215. Goal
  216. ----
  217. Use ``std::format`` to format printed strings instead of stream operators. To
  218. ensure availability of ``std::format``, configure CMake to use the C++20
  219. standard for C++ targets.
  220. Helpful Resources
  221. -----------------
  222. * :option:`cmake -D`
  223. * :variable:`CMAKE_<LANG>_STANDARD`
  224. * :variable:`CMAKE_CXX_STANDARD`
  225. * :prop_tgt:`CXX_STANDARD`
  226. * `cppreference \<format\> <https://en.cppreference.com/w/cpp/utility/format/format.html>`_
  227. Files to Edit
  228. -------------
  229. * ``Tutorial/Tutorial.cxx``
  230. * ``MathFunctions/MathFunctions.cxx``
  231. Getting Started
  232. ---------------
  233. Continue to edit files from ``Step3``. Complete ``TODO 3`` through ``TODO 7``.
  234. We'll be modifying our prints to use ``std::format`` instead of stream
  235. operators.
  236. Ensure your cache variables are set such that the Tutorial executable will be
  237. built, using any of the methods discussed in the previous exercise.
  238. Build and Run
  239. -------------
  240. We need to reconfigure our project with the new standard, we can do this
  241. using the same method as our ``TUTORIAL_BUILD_UTILITIES`` cache variable.
  242. .. code-block:: console
  243. cmake -B build -DCMAKE_CXX_STANDARD=20
  244. .. note::
  245. Configuration variables are, by convention, prefixed with the provider of the
  246. variable. CMake configuration variables are prefixed with ``CMAKE_``, while
  247. projects should prefix their variables with ``<PROJECT>_``.
  248. The tutorial configuration variables follow this convention, and are prefixed
  249. with ``TUTORIAL_``.
  250. Now that we've configured with C++20, we can build as usual.
  251. .. code-block:: console
  252. cmake --build build
  253. Solution
  254. --------
  255. We need to include ``<format>`` and then use it.
  256. .. raw:: html
  257. <details><summary>TODO 3-5: Click to show/hide answer</summary>
  258. .. literalinclude:: Step4/Tutorial/Tutorial.cxx
  259. :caption: TODO 3: Tutorial/Tutorial.cxx
  260. :name: Tutorial/Tutorial.cxx-include-format
  261. :language: c++
  262. :start-at: #include <format>
  263. :end-at: #include <string>
  264. .. literalinclude:: Step4/Tutorial/Tutorial.cxx
  265. :caption: TODO 4: Tutorial/Tutorial.cxx
  266. :name: Tutorial/Tutorial.cxx-format1
  267. :language: c++
  268. :start-at: if (argc < 2) {
  269. :end-at: return 1;
  270. :append: }
  271. :dedent: 2
  272. .. literalinclude:: Step4/Tutorial/Tutorial.cxx
  273. :caption: TODO 5: Tutorial/Tutorial.cxx
  274. :name: Tutorial/Tutorial.cxx-format3
  275. :language: c++
  276. :start-at: // calculate square root
  277. :end-at: outputValue);
  278. :dedent: 2
  279. .. raw:: html
  280. </details>
  281. And again for the ``MathFunctions`` library.
  282. .. raw:: html
  283. <details><summary>TODO 6-7: Click to show/hide answer</summary>
  284. .. literalinclude:: Step4/MathFunctions/MathFunctions.cxx
  285. :caption: TODO 6: MathFunctions.cxx
  286. :name: MathFunctions/MathFunctions.cxx-include-format
  287. :language: c++
  288. :start-at: #include <format>
  289. :end-at: #include <iostream>
  290. .. literalinclude:: Step4/MathFunctions/MathFunctions.cxx
  291. :caption: TODO 7: MathFunctions.cxx
  292. :name: MathFunctions/MathFunctions.cxx-format
  293. :language: c++
  294. :start-at: double delta
  295. :end-at: std::format
  296. :dedent: 4
  297. .. raw:: html
  298. </details>
  299. Exercise 3 - CMakePresets.json
  300. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  301. Managing these configuration values can quickly become overwhelming. In CI
  302. systems it is appropriate to record these as part of a given CI step. For
  303. example in a Github Actions CI step we might see something akin to the
  304. following:
  305. .. code-block:: yaml
  306. - name: Configure and Build
  307. run: |
  308. cmake \
  309. -B build \
  310. -DCMAKE_BUILD_TYPE=Release \
  311. -DCMAKE_CXX_STANDARD=20 \
  312. -DCMAKE_CXX_EXTENSIONS=ON \
  313. -DTUTORIAL_BUILD_UTILITIES=OFF \
  314. # Possibly many more options
  315. # ...
  316. cmake --build build
  317. When developing code locally, typing all these options even once might be error
  318. prone. If a fresh configuration is needed for any reason, doing so multiple
  319. times could be exhausting.
  320. There are many and varied solutions to this problem, and your choice is
  321. ultimately up to your preferences as a developer. CLI-oriented developers
  322. commonly use task runners to invoke CMake with their desired options for a
  323. project. Most IDEs also have a custom mechanism for controlling CMake
  324. configuration.
  325. It would be impossible to fully enumerate every possible configuration workflow
  326. here. Instead we will explore CMake's built-in solution, known as
  327. :manual:`CMake Presets <cmake-presets(7)>`. Presets give us a format to name
  328. and express collections of CMake configuration options.
  329. .. note::
  330. Presets are capable of expressing entire CMake workflows, from
  331. configuration, through building, all the way to installing the software
  332. package.
  333. They are far more flexible than can we have room for here. We'll limit
  334. ourselves to using them for configuration.
  335. CMake Presets come in two standard files, ``CMakePresets.json``, which is
  336. intended to be a part of the project and tracked in source control; and
  337. ``CMakeUserPresets.json``, which is intended for local user configuration
  338. and should not be tracked in source control.
  339. The simplest preset which would be of use to a developer does nothing more
  340. than configure variables.
  341. .. code-block:: json
  342. {
  343. "version": 4,
  344. "configurePresets": [
  345. {
  346. "name": "example-preset",
  347. "cacheVariables": {
  348. "EXAMPLE_FOO": "Bar",
  349. "EXAMPLE_QUX": "Baz"
  350. }
  351. }
  352. ]
  353. }
  354. When invoking CMake, where previously we would have done:
  355. .. code-block:: console
  356. cmake -B build -DEXAMPLE_FOO=Bar -DEXAMPLE_QUX=Baz
  357. We can now use the preset:
  358. .. code-block:: console
  359. cmake -B build --preset example-preset
  360. CMake will search for files named ``CMakePresets.json`` and
  361. ``CMakeUserPresets.json``, and load the named configuration from them if
  362. available.
  363. .. note::
  364. Command line flags can be mixed with presets. Command line flags have
  365. precedence over values found in a preset.
  366. Presets also support limited macros, variables that can be brace-expanded
  367. inside the preset. The only one of interest to us is the ``${sourceDir}`` macro,
  368. which expands to the root directory of the project. We can use this to set our
  369. build directory, skipping the :option:`-B <cmake -B>` flag when configuring
  370. the project.
  371. .. code-block:: json
  372. {
  373. "name": "example-preset",
  374. "binaryDir": "${sourceDir}/build"
  375. }
  376. Goal
  377. ----
  378. Configure and build the tutorial using a CMake Preset instead of command line
  379. flags.
  380. Helpful Resources
  381. -----------------
  382. * :manual:`cmake-presets(7)`
  383. Files to Edit
  384. -------------
  385. * ``CMakePresets.json``
  386. Getting Started
  387. ---------------
  388. Continue to edit files from ``Step3``. Complete ``TODO 8`` and ``TODO 9``.
  389. .. note::
  390. ``TODOs`` inside ``CMakePresets.json`` need to be *replaced*. There should
  391. be no ``TODO`` keys left inside the file when you have completed the exercise.
  392. You can verify the preset is working correctly by deleting the existing build
  393. folder before you configure, this will ensure you're not reusing the existing
  394. CMake Cache for configuration.
  395. .. note::
  396. On CMake 3.24 and newer, the same effect can be achieved by configuring with
  397. :option:`cmake --fresh`.
  398. All future configuration changes will be via the ``CMakePresets.json`` file.
  399. Build and Run
  400. -------------
  401. We can now use the preset file to manage our configuration.
  402. .. code-block:: console
  403. cmake --preset tutorial
  404. Presets are capable of running the build step for us, but for this tutorial
  405. we'll continue to run the build ourselves.
  406. .. code-block:: console
  407. cmake --build build
  408. Solution
  409. --------
  410. There are two changes we need to make, first we want to set the build
  411. directory (also called the "binary directory") to the ``build`` subdirectory
  412. of our project folder, and second we need to set the ``CMAKE_CXX_STANDARD`` to
  413. ``20``.
  414. .. raw:: html
  415. <details><summary>TODO 8-9: Click to show/hide answer</summary>
  416. .. code-block:: json
  417. :caption: TODO 8-9: CMakePresets.json
  418. :name: CMakePresets.json-initial
  419. {
  420. "version": 4,
  421. "configurePresets": [
  422. {
  423. "name": "tutorial",
  424. "displayName": "Tutorial Preset",
  425. "description": "Preset to use with the tutorial",
  426. "binaryDir": "${sourceDir}/build",
  427. "cacheVariables": {
  428. "CMAKE_CXX_STANDARD": "20"
  429. }
  430. }
  431. ]
  432. }
  433. .. raw:: html
  434. </details>