Adding Usage Requirements for a Library.rst 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. Step 3: Adding Usage Requirements for a Library
  2. ===============================================
  3. Exercise 1 - Adding Usage Requirements for a Library
  4. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  5. Usage requirements allow for far better control over a library or
  6. executable's link and include line while also giving more control over the
  7. transitive property of targets inside CMake. The primary commands that
  8. leverage usage requirements are:
  9. * :command:`target_compile_definitions`
  10. * :command:`target_compile_options`
  11. * :command:`target_include_directories`
  12. * :command:`target_link_libraries`
  13. Goal
  14. ----
  15. Add usage requirements for a library.
  16. Helpful Materials
  17. -----------------
  18. * :command:`target_include_directories`
  19. * :variable:`CMAKE_CURRENT_SOURCE_DIR`
  20. Files to Edit
  21. -------------
  22. * ``MathFunctions/CMakeLists.txt``
  23. * ``CMakeLists.txt``
  24. Getting Started
  25. ---------------
  26. In this exercise, we will refactor our code from
  27. :guide:`tutorial/Adding a Library` to use the modern CMake approach. We will
  28. let our library define its own usage requirements so they are passed
  29. transitively to other targets as necessary. In this case, ``MathFunctions``
  30. will specify any needed include directories itself. Then, the consuming target
  31. ``Tutorial`` simply needs to link to ``MathFunctions`` and not worry about
  32. any additional include directories.
  33. The starting source code is provided in the ``Step3`` directory. In this
  34. exercise, complete ``TODO 1`` through ``TODO 3``.
  35. First, add a call to :command:`target_include_directories` in
  36. ``MathFunctions/CMakeLists``. Remember that
  37. :variable:`CMAKE_CURRENT_SOURCE_DIR` is the path to the source directory
  38. currently being processed.
  39. Then, update (and simplify!) the call to
  40. :command:`target_include_directories` in the top-level ``CMakeLists.txt``.
  41. Build and Run
  42. -------------
  43. Make a new directory called ``Step3_build``, run the :manual:`cmake
  44. <cmake(1)>` executable or the :manual:`cmake-gui <cmake-gui(1)>` to
  45. configure the project and then build it with your chosen build tool or by
  46. using ``cmake --build .`` from the build directory. Here's a refresher of
  47. what that looks like from the command line:
  48. .. code-block:: console
  49. mkdir Step3_build
  50. cd Step3_build
  51. cmake ../Step3
  52. cmake --build .
  53. Next, use the newly built ``Tutorial`` and verify that it is working as
  54. expected.
  55. Solution
  56. --------
  57. Let's update the code from the previous step to use the modern CMake
  58. approach of usage requirements.
  59. We want to state that anybody linking to ``MathFunctions`` needs to include
  60. the current source directory, while ``MathFunctions`` itself doesn't. This
  61. can be expressed with an ``INTERFACE`` usage requirement. Remember
  62. ``INTERFACE`` means things that consumers require but the producer doesn't.
  63. At the end of ``MathFunctions/CMakeLists.txt``, use
  64. :command:`target_include_directories` with the ``INTERFACE`` keyword, as
  65. follows:
  66. .. raw:: html
  67. <details><summary>TODO 1: Click to show/hide answer</summary>
  68. .. literalinclude:: Step4/MathFunctions/CMakeLists.txt
  69. :caption: TODO 1: MathFunctions/CMakeLists.txt
  70. :name: MathFunctions/CMakeLists.txt-target_include_directories-INTERFACE
  71. :language: cmake
  72. :start-after: # to find MathFunctions.h
  73. :end-before: # TODO 3: Link to
  74. .. raw:: html
  75. </details>
  76. Now that we've specified usage requirements for ``MathFunctions`` we can
  77. safely remove our uses of the ``EXTRA_INCLUDES`` variable from the top-level
  78. ``CMakeLists.txt``, here:
  79. .. raw:: html
  80. <details><summary>TODO 2: Click to show/hide answer</summary>
  81. .. literalinclude:: Step4/CMakeLists.txt
  82. :caption: TODO 2: CMakeLists.txt
  83. :name: CMakeLists.txt-remove-EXTRA_INCLUDES
  84. :language: cmake
  85. :start-after: # add the MathFunctions library
  86. :end-before: # add the executable
  87. .. raw:: html
  88. </details>
  89. And here:
  90. .. raw:: html
  91. <details><summary>TODO 3: Click to show/hide answer</summary>
  92. .. literalinclude:: Step4/CMakeLists.txt
  93. :caption: TODO 3: CMakeLists.txt
  94. :name: CMakeLists.txt-target_include_directories-remove-EXTRA_INCLUDES
  95. :language: cmake
  96. :start-after: # so that we will find TutorialConfig.h
  97. .. raw:: html
  98. </details>
  99. Notice that with this technique, the only thing our executable target does to
  100. use our library is call :command:`target_link_libraries` with the name
  101. of the library target. In larger projects, the classic method of specifying
  102. library dependencies manually becomes very complicated very quickly.