In-Depth CMake Target Commands.rst 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545
  1. Step 4: In-Depth CMake Target Commands
  2. ======================================
  3. There are several target commands within CMake we can use to describe
  4. requirements. As a reminder, a target command is one which modifies the
  5. properties of the target it is applied to. These properties describe
  6. requirements needed to build the software, such as sources, compile flags,
  7. and output names; or properties necessary to consume the target, such as header
  8. includes, library directories, and linkage rules.
  9. .. note::
  10. As discussed in ``Step1``, properties required to build a target should be
  11. described with the ``PRIVATE`` :ref:`scope keyword <Target Command Scope>`,
  12. those required to consume the target with ``INTERFACE``, and properties needed
  13. for both are described with ``PUBLIC``.
  14. In this step we will go over all the available target commands in CMake. Not all
  15. target commands are created equal. We have already discussed the two most
  16. important target commands, :command:`target_sources` and
  17. :command:`target_link_libraries`. Of the remaining commands, some are almost
  18. as common as these two, others have more advanced applications, and a couple
  19. should only be used as a last resort when other options are not available.
  20. Background
  21. ^^^^^^^^^^
  22. Before going any further, let's name all of the CMake target commands. We'll
  23. split these into three groups: the recommended and generally useful commands,
  24. the advanced and cautionary commands, and the "footgun" commands which should
  25. be avoided unless necessary.
  26. +-----------------------------------------+--------------------------------------+---------------------------------------+
  27. | Common/Recommended | Advanced/Caution | Esoteric/Footguns |
  28. +=========================================+======================================+=======================================+
  29. | :command:`target_compile_definitions` | :command:`get_target_property` | :command:`target_include_directories` |
  30. | :command:`target_compile_features` | :command:`set_target_properties` | :command:`target_link_directories` |
  31. | :command:`target_link_libraries` | :command:`target_compile_options` | |
  32. | :command:`target_sources` | :command:`target_link_options` | |
  33. | | :command:`target_precompile_headers` | |
  34. +-----------------------------------------+--------------------------------------+---------------------------------------+
  35. .. note::
  36. There's no such thing as a "bad" CMake target command. They all have valid
  37. use cases. This categorization is provided to give newcomers a simple
  38. intuition about which commands they should consider first when tackling
  39. a problem.
  40. We'll demonstrate most of these in the following exercises. The three we won't
  41. be using are :command:`get_target_property`, :command:`set_target_properties`
  42. and :command:`target_precompile_headers`, so we will briefly discuss their
  43. purpose here.
  44. The :command:`get_target_property` and :command:`set_target_properties` commands
  45. give direct access to a target's properties by name. They can even be used
  46. to attach arbitrary property names to a target.
  47. .. code-block:: cmake
  48. add_library(Example)
  49. set_target_properties(Example
  50. PROPERTIES
  51. Key Value
  52. Hello World
  53. )
  54. get_target_property(KeyVar Example Key)
  55. get_target_property(HelloVar Example Hello)
  56. message("Key: ${KeyVar}")
  57. message("Hello: ${HelloVar}")
  58. .. code-block:: console
  59. $ cmake -B build
  60. ...
  61. Key: Value
  62. Hello: World
  63. The full list of target properties which are semantically meaningful to CMake
  64. are documented at :manual:`cmake-properties(7)`, however most of these should
  65. be modified with their dedicated commands. For example, it is unnecessary to
  66. directly manipulate ``LINK_LIBRARIES`` and ``INTERFACE_LINK_LIBRARIES``, as
  67. these are handled by :command:`target_link_libraries`.
  68. Conversely, some lesser-used properties are only accessible via these commands.
  69. The :prop_tgt:`DEPRECATION` property, used to attach deprecation notices to
  70. targets, can only be set via :command:`set_target_properties`; as can the
  71. :prop_tgt:`ADDITIONAL_CLEAN_FILES`, for describing additional files to be
  72. removed by CMake's ``clean`` target; and other properties of this sort.
  73. The :command:`target_precompile_headers` command takes a list of header files,
  74. similar to :command:`target_sources`, and creates a precompiled header from
  75. them. This precompiled header is then force included into all translation
  76. units in the target. This can be useful for build performance.
  77. Exercise 1 - Features and Definitions
  78. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  79. In earlier steps we cautioned against globally setting
  80. :variable:`CMAKE_<LANG>_STANDARD` and overriding packagers' decision concerning
  81. which language standard to use. On the other hand, many libraries have a
  82. minimum required feature set they need in order to build, and for these it
  83. is appropriate to use the :command:`target_compile_features` command to
  84. communicate those requirements.
  85. .. code-block:: cmake
  86. target_compile_features(MyApp PRIVATE cxx_std_20)
  87. The :command:`target_compile_features` command describes a minimum language
  88. standard as a target property. If the :variable:`CMAKE_<LANG>_STANDARD` is above
  89. this version, or the compiler default already provides this language standard,
  90. no action is taken. If additional flags are necessary to enable the standard,
  91. these will be added by CMake.
  92. .. note::
  93. :command:`target_compile_features` manipulates the same style of interface and
  94. non-interface properties as the other target commands. This means it is
  95. possible to *inherit* a language standard requirement specified with
  96. ``INTERFACE`` or ``PUBLIC`` scope keywords.
  97. If language features are used only in implementation files, then the
  98. respective compile features should be ``PRIVATE``. If the target's headers
  99. use the features, then ``PUBLIC`` or ``INTERFACE`` should be used.
  100. For C++, the compile features are of the form ``cxx_std_YY`` where ``YY`` is
  101. the standardization year, e.g. ``14``, ``17``, ``20``, etc.
  102. The :command:`target_compile_definitions` command describes compile definitions
  103. as target properties. It is the most common mechanism for communicating build
  104. configuration information to the source code itself. As with all properties,
  105. the scope keywords apply as we have discussed.
  106. .. code-block:: cmake
  107. target_compile_definitions(MyLibrary
  108. PRIVATE
  109. MYLIBRARY_USE_EXPERIMENTAL_IMPLEMENTATION
  110. PUBLIC
  111. MYLIBRARY_EXCLUDE_DEPRECATED_FUNCTIONS
  112. )
  113. It is neither required nor desired that we attach ``-D`` prefixes to compile
  114. definitions described with :command:`target_compile_definitions`. CMake will
  115. determine the correct flag for the current compiler.
  116. Goal
  117. ----
  118. Use :command:`target_compile_features` and :command:`target_compile_definitions`
  119. to communicate language standard and compile definition requirements.
  120. Helpful Resources
  121. -----------------
  122. * :command:`target_compile_features`
  123. * :command:`target_compile_definitions`
  124. * :command:`option`
  125. * :command:`if`
  126. Files to Edit
  127. -------------
  128. * ``CMakeLists.txt``
  129. * ``Tutorial/CMakeLists.txt``
  130. * ``MathFunctions/CMakeLists.txt``
  131. * ``MathFunctions/MathFunctions.cxx``
  132. * ``CMakePresets.json``
  133. Getting Started
  134. ---------------
  135. The ``Help/guide/tutorial/Step4`` directory contains the complete, recommended
  136. solution to ``Step3`` and relevant ``TODOs`` for this step. Complete ``TODO 1``
  137. through ``TODO 8``.
  138. Build and Run
  139. -------------
  140. We can run CMake using our ``tutorial`` preset, and then build as usual.
  141. .. code-block:: console
  142. cmake --preset tutorial
  143. cmake --build build
  144. Verify that the output of ``Tutorial`` is what we would expect for ``std::sqrt``.
  145. Solution
  146. --------
  147. First we add a new option to the top-level CML.
  148. .. raw:: html
  149. <details><summary>TODO 1: Click to show/hide answer</summary>
  150. .. literalinclude:: Step5/CMakeLists.txt
  151. :caption: TODO 1: CMakeLists.txt
  152. :name: CMakeLists.txt-TUTORIAL_USE_STD_SQRT
  153. :language: cmake
  154. :start-at: option(TUTORIAL_BUILD_UTILITIES
  155. :end-at: option(TUTORIAL_USE_STD_SQRT
  156. .. raw:: html
  157. </details>
  158. Then we add the compile feature and definitions to ``MathFunctions``.
  159. .. raw:: html
  160. <details><summary>TODO 2-3: Click to show/hide answer</summary>
  161. .. literalinclude:: Step5/MathFunctions/CMakeLists.txt
  162. :caption: TODO 2-3: MathFunctions/CMakeLists.txt
  163. :name: MathFunctions/CMakeLists.txt-target_compile_features
  164. :language: cmake
  165. :start-at: target_compile_features
  166. :end-at: endif()
  167. .. raw:: html
  168. </details>
  169. And the compile feature for ``Tutorial``.
  170. .. raw:: html
  171. <details><summary>TODO 4: Click to show/hide answer</summary>
  172. .. literalinclude:: Step5/Tutorial/CMakeLists.txt
  173. :caption: TODO 4: Tutorial/CMakeLists.txt
  174. :name: Tutorial/CMakeLists.txt-target_compile_features
  175. :language: cmake
  176. :start-at: target_compile_features
  177. :end-at: target_compile_features
  178. .. raw:: html
  179. </details>
  180. Now we can modify ``MathFunctions`` to take advantage of the new definition.
  181. .. raw:: html
  182. <details><summary>TODO 5-6: Click to show/hide answer</summary>
  183. .. literalinclude:: Step5/MathFunctions/MathFunctions.cxx
  184. :caption: TODO 5: MathFunctions/MathFunctions.cxx
  185. :name: MathFunctions/MathFunctions.cxx-cmath
  186. :language: c++
  187. :start-at: cmath
  188. :end-at: format
  189. :append: #include <iostream>
  190. .. literalinclude:: Step5/MathFunctions/MathFunctions.cxx
  191. :caption: TODO 6: MathFunctions/MathFunctions.cxx
  192. :name: MathFunctions/MathFunctions.cxx-std-sqrt
  193. :language: c++
  194. :start-at: double sqrt(double x)
  195. :end-at: }
  196. .. raw:: html
  197. </details>
  198. Finally we can update our ``CMakePresets.json``. We don't need to set
  199. ``CMAKE_CXX_STANDARD`` anymore, but we do want to try out our new
  200. compile definition.
  201. .. raw:: html
  202. <details><summary>TODO 7-8: Click to show/hide answer</summary>
  203. .. code-block:: json
  204. :caption: TODO 7-8: CMakePresets.json
  205. :name: CMakePresets.json-std-sqrt
  206. "cacheVariables": {
  207. "TUTORIAL_USE_STD_SQRT": "ON"
  208. }
  209. .. raw:: html
  210. </details>
  211. Exercise 2 - Compile and Link Options
  212. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  213. Sometimes, we need to exercise specific control over the exact options being
  214. passed on the compile and link line. These situations are addressed by
  215. :command:`target_compile_options` and :command:`target_link_options`.
  216. .. code:: cmake
  217. target_compile_options(MyApp PRIVATE -Wall -Werror)
  218. target_link_options(MyApp PRIVATE -T LinksScript.ld)
  219. There are several problems with unconditionally calling
  220. :command:`target_compile_options` or :command:`target_link_options`. The primary
  221. problem is compiler flags are specific to the compiler frontend being used. In
  222. order to ensure that our project supports multiple compiler frontends, we must
  223. only pass compatible flags to the compiler.
  224. We can achieve this by checking the :variable:`CMAKE_<LANG>_COMPILER_FRONTEND_VARIANT`
  225. variable which tells us the style of flags supported by the compiler frontend.
  226. .. note::
  227. Prior to CMake 3.26, :variable:`CMAKE_<LANG>_COMPILER_FRONTEND_VARIANT` was
  228. only set for compilers with multiple frontend variants. In versions after
  229. CMake 3.26 checking this variable alone is sufficient.
  230. However this tutorial targets CMake 3.23. As such, the logic is more
  231. complicated than we have time for here. This tutorial step already includes
  232. correct logic for checking the compiler variant for MSVC, GCC, Clang, and
  233. AppleClang on CMake 3.23.
  234. Even if a compiler accepts the flags we pass, the semantics of compiler flags
  235. change over time. This is especially true with regards to warnings. Projects
  236. should not turn warnings-as-error flags by default, as this can break their
  237. build on otherwise innocuous compiler warnings included in later releases.
  238. .. note::
  239. For errors and warnings, consider placing flags in :variable:`CMAKE_<LANG>_FLAGS`
  240. for local development builds and during CI runs (via preset or
  241. :option:`-D <cmake -D>` flags). We know exactly which compiler and
  242. toolchain are being used in these contexts, so we can customize the behavior
  243. precisely without risking build breakages on other platforms.
  244. Goal
  245. ----
  246. Add appropriate warning flags to the ``Tutorial`` executable for MSVC-style and
  247. GNU-style compiler frontends.
  248. Helpful Resources
  249. -----------------
  250. * :command:`target_compile_options`
  251. Files to Edit
  252. -------------
  253. * ``Tutorial/CMakeLists.txt``
  254. Getting Started
  255. ---------------
  256. Continue editing files in the ``Step4`` directory. The conditional for checking
  257. the frontend variant has already been written. Complete ``TODO 9`` and
  258. ``TODO 10`` to add warning flags to ``Tutorial``.
  259. Build and Run
  260. -------------
  261. Since we have already configured for this step, we can build with the usual
  262. command.
  263. .. code-block:: cmake
  264. cmake --build build
  265. This should reveal a simple warning in the build. You can go ahead and fix it.
  266. Solution
  267. --------
  268. We need to add two compile options to ``Tutorial``, one MSVC-style flag and
  269. one GNU-style flag.
  270. .. raw:: html
  271. <details><summary>TODO 9-10: Click to show/hide answer</summary>
  272. .. literalinclude:: Step5/Tutorial/CMakeLists.txt
  273. :caption: TODO 9-10: Tutorial/CMakeLists.txt
  274. :name: Tutorial/CMakeLists.txt-target_compile_options
  275. :language: cmake
  276. :start-at: if(
  277. :end-at: endif()
  278. .. raw:: html
  279. </details>
  280. Exercise 3 - Include and Link Directories
  281. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  282. .. note::
  283. This exercise requires building an archive using a compiler directly on the
  284. command line. It is not used in later steps. It is included only to
  285. demonstrate a use case for :command:`target_include_directories` and
  286. :command:`target_link_directories`.
  287. If you cannot complete this exercise for whatever reason feel free to treat
  288. it as informational-only, or skip it entirely.
  289. It is generally unnecessary to directly describe include and link directories,
  290. as these requirements are inherited when linking together targets generated
  291. within CMake, or from external dependencies imported into CMake with commands
  292. we will cover in later steps.
  293. If we happen to have some libraries or header files which are not described
  294. by a CMake target which we need to bring into the build, perhaps pre-compiled
  295. binaries provided by a vendor, we can incorporate with the
  296. :command:`target_link_directories` and :command:`target_include_directories`
  297. commands.
  298. .. code-block:: cmake
  299. target_link_directories(MyApp PRIVATE Vendor/lib)
  300. target_include_directories(MyApp PRIVATE Vendor/include)
  301. These commands use properties which map to the ``-L`` and ``-I`` compiler flags
  302. (or whatever flags the compiler uses for link and include directories).
  303. Of course, passing a link directory doesn't tell the compiler to link anything
  304. into the build. For that we need :command:`target_link_libraries`. When
  305. :command:`target_link_libraries` is given an argument which does not map to
  306. a target name, it will add the string directly to the link line as a library
  307. to be linked into the build (prepending any appropriate flags, such a ``-l``).
  308. Goal
  309. ----
  310. Describe a pre-compiled, vendored, static library and its headers inside a
  311. project using :command:`target_link_directories` and
  312. :command:`target_include_directories`.
  313. Helpful Resources
  314. -----------------
  315. * :command:`target_link_directories`
  316. * :command:`target_include_directories`
  317. * :command:`target_link_libraries`
  318. Files to Edit
  319. -------------
  320. * ``Vendor/CMakeLists.txt``
  321. * ``Tutorial/CMakeLists.txt``
  322. Getting Started
  323. ---------------
  324. You will need to build the vendor library into a static archive to complete this
  325. exercise. Navigate to the ``Help/guide/tutorial/Step4/Vendor/lib`` directory
  326. and build the code as appropriate for your platform.
  327. Typical commands for a GCC toolchain on Unix-like systems are:
  328. .. code-block:: console
  329. g++ -c Vendor.cxx
  330. ar rvs libVendor.a Vendor.o
  331. Likewise, sample commands for an MSVC toolchain on Windows are:
  332. .. code-block:: console
  333. cl -c Vendor.cxx
  334. lib -out:Vendor.lib Vendor.obj
  335. Here, since you're directly invoking ``cl`` and ``lib``, make sure to use a
  336. Developer Command Prompt for your version of Visual Studio with the same
  337. target architecture used by this CMake project.
  338. Then complete ``TODO 11`` through ``TODO 14``.
  339. .. note::
  340. ``VendorLib`` is an ``INTERFACE`` library, meaning it has no build requirements
  341. (because it has already been built). All of its properties should also be
  342. interface properties.
  343. We'll discuss ``INTERFACE`` libraries in greater depth during the next step.
  344. Build and Run
  345. -------------
  346. If you have successfully built ``libVendor``, you can rebuild ``Tutorial``
  347. using the normal command.
  348. .. code-block:: console
  349. cmake --build build
  350. Running ``Tutorial`` should now output a message about the acceptability of the
  351. result to the vendor.
  352. Solution
  353. --------
  354. We need to use the target link and include commands to describe the archive
  355. and its headers as ``INTERFACE`` requirements of ``VendorLib``.
  356. .. raw:: html
  357. <details><summary>TODO 11-13: Click to show/hide answer</summary>
  358. .. code-block:: cmake
  359. :caption: TODO 11-13: Vendor/CMakeLists.txt
  360. :name: Vendor/CMakeLists.txt
  361. target_include_directories(VendorLib
  362. INTERFACE
  363. include
  364. )
  365. target_link_directories(VendorLib
  366. INTERFACE
  367. lib
  368. )
  369. target_link_libraries(VendorLib
  370. INTERFACE
  371. Vendor
  372. )
  373. .. raw:: html
  374. </details>
  375. Then we can add ``VendorLib`` to ``Tutorial``'s linked libraries.
  376. .. raw:: html
  377. <details><summary>TODO 14: Click to show/hide answer</summary>
  378. .. code-block:: cmake
  379. :caption: TODO 14: Tutorial/CMakeLists.txt
  380. :name: Tutorial/CMakeLists.txt-VendorLib
  381. target_link_libraries(Tutorial
  382. PRIVATE
  383. MathFunctions
  384. VendorLib
  385. )
  386. .. raw:: html
  387. </details>