Custom Commands and Generated Files.rst 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. Step 7: Custom Commands and Generated Files
  2. ===========================================
  3. Code generation is a ubiquitous mechanism for extending programming languages
  4. beyond the bounds of their language model. CMake has first-class support for
  5. Qt's Meta-Object Compiler, but very few other code generators are notable
  6. enough to warrant that kind of effort.
  7. Instead, code generators tend to be bespoke and usage specific. CMake provides
  8. facilities for describing the usage of a code generator, so projects can
  9. add support for their individual needs.
  10. In this step, we will use :command:`add_custom_command` to add support for a
  11. code generator within the tutorial project.
  12. Background
  13. ^^^^^^^^^^
  14. Any step in the build process can generally be described in terms of its inputs
  15. and outputs. CMake assumes that code generators and other custom processes
  16. operate on the same principle. In this way, the code generator acts identically
  17. to compilers, linkers, and other elements of the toolchain; when the inputs are
  18. newer than the outputs (or the outputs don't exist), a user-specified command
  19. will be run to update the outputs.
  20. .. note::
  21. This model assumes the outputs of a process are known before it is run. CMake
  22. lacks the ability to describe code generators where the name and location of
  23. the outputs depends on the *content* of the input. Various hacks exist to
  24. shim this functionality into CMake, but they are outside the scope of this
  25. tutorial.
  26. Describing a code generator (or any custom process) is usually performed in
  27. two parts. First, the inputs and outputs are described independently of the
  28. CMake target model, concerned only with the generation process itself. Second,
  29. the outputs are associated with a CMake target to insert them into the CMake
  30. target model.
  31. For sources, this is as simple as adding the generated files to the source list
  32. of a ``STATIC``, ``SHARED``, or ``OBJECT`` library. For header-only generators,
  33. it's often necessary to use an intermediary target created via
  34. :command:`add_custom_target` to add the header file generation to the
  35. build stage (because ``INTERFACE`` libraries have no build step).
  36. Exercise 1 - Using a Code Generator
  37. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  38. The primary mechanism for describing a code generator is the
  39. :command:`add_custom_command` command. A "command", for the purpose of
  40. :command:`add_custom_command` is either an executable available in the build
  41. environment or a CMake executable target name.
  42. .. code-block:: cmake
  43. add_executable(Tool)
  44. # ...
  45. add_custom_command(
  46. OUTPUT Generated.cxx
  47. COMMAND Tool -i input.txt -o Generated.cxx
  48. DEPENDS Tool input.txt
  49. VERBATIM
  50. )
  51. # ...
  52. add_library(GeneratedObject OBJECT)
  53. target_sources(GeneratedObject
  54. PRIVATE
  55. Generated.cxx
  56. )
  57. Most of the keywords are self-explanatory, with the exception of ``VERBATIM``.
  58. This argument is effectively mandatory for legacy reasons that are uninteresting
  59. to explain in a modern context. The curious should consult the
  60. :command:`add_custom_command` documentation for additional details.
  61. The ``Tool`` executable target appears both in the ``COMMAND`` and ``DEPENDS``
  62. parameters. While ``COMMAND`` is sufficient for the code to build correctly,
  63. adding the ``Tool`` itself as a dependency of the custom command ensure that
  64. if ``Tool`` is updated, the custom command will be rerun.
  65. For header-only file generation, additional commands are necessary because the
  66. library itself has no build step. We can use :command:`add_custom_target` to
  67. create an "artificial" build step for the library. We then force the custom
  68. target to be run before any targets which link the library with the command
  69. :command:`add_dependencies`.
  70. .. code-block:: cmake
  71. add_custom_target(RunGenerator DEPENDS Generated.h)
  72. add_library(GeneratedLib INTERFACE)
  73. target_sources(GeneratedLib
  74. INTERFACE
  75. FILE_SET HEADERS
  76. BASE_DIRS
  77. ${CMAKE_CURRENT_BINARY_DIR}
  78. FILES
  79. ${CMAKE_CURRENT_BINARY_DIR}/Generated.h
  80. )
  81. add_dependencies(GeneratedLib RunGenerator)
  82. .. note::
  83. We add the :variable:`CMAKE_CURRENT_BINARY_DIR`, a variable which names the
  84. current location in the build tree where our artifacts are being placed, to
  85. the base directories because that's the working directory our code generator
  86. will be run inside of. Listing the ``FILES`` is unnecessary for the build and
  87. done so here only for clarity.
  88. Goal
  89. ----
  90. Add a generated table of pre-computed square roots to the ``MathFunctions``
  91. library.
  92. Helpful Resources
  93. -----------------
  94. * :command:`add_executable`
  95. * :command:`add_library`
  96. * :command:`target_sources`
  97. * :command:`add_custom_command`
  98. * :command:`add_custom_target`
  99. * :command:`add_dependencies`
  100. Files to Edit
  101. -------------
  102. * ``MathFunctions/CMakeLists.txt``
  103. * ``MathFunctions/MakeTable/CMakeLists.txt``
  104. * ``MathFunctions/MathFunctions.cxx``
  105. Getting Started
  106. ---------------
  107. The ``MathFunctions`` library has been edited to use a pre-computed table when
  108. given a number less than 10. However, the hardcoded table is not particularly
  109. accurate, containing only the nearest truncated integer value.
  110. The ``MakeTable.cxx`` source file describes a program which will generate a
  111. better table. It takes a single argument as input, the file name of the table
  112. to be generated.
  113. Complete ``TODO 1`` through ``TODO 10``.
  114. Build and Run
  115. -------------
  116. No special configuration is needed, configure and build as usual. Note that
  117. the ``MakeTable`` executable is sequenced before ``MathFunctions``.
  118. .. code-block:: console
  119. cmake --preset tutorial
  120. cmake --build build
  121. Verify the output of ``Tutorial`` now uses the pre-computed table for values
  122. less than 10.
  123. Solution
  124. --------
  125. First we add a new executable to generate the tables, adding the
  126. ``MakeTable.cxx`` file as a source.
  127. .. raw:: html
  128. <details><summary>TODO 1-2: Click to show/hide answer</summary>
  129. .. literalinclude:: Step8/MathFunctions/MakeTable/CMakeLists.txt
  130. :caption: TODO 1-2: MathFunctions/MakeTable/CMakeLists.txt
  131. :name: MathFunctions/MakeTable/CMakeLists.txt-add_executable
  132. :language: cmake
  133. :start-at: add_executable
  134. :end-at: MakeTable.cxx
  135. :append: )
  136. .. raw:: html
  137. </details>
  138. Then we add a custom command which produces the table, and custom target which
  139. depends on the table.
  140. .. raw:: html
  141. <details><summary>TODO 3-4: Click to show/hide answer</summary>
  142. .. literalinclude:: Step8/MathFunctions/MakeTable/CMakeLists.txt
  143. :caption: TODO 3-4: MathFunctions/MakeTable/CMakeLists.txt
  144. :name: MathFunctions/MakeTable/CMakeLists.txt-add_custom_command
  145. :language: cmake
  146. :start-at: add_custom_command
  147. :end-at: add_custom_target
  148. .. raw:: html
  149. </details>
  150. We need to add an interface library which describes the output which will
  151. appear in :variable:`CMAKE_CURRENT_BINARY_DIR`. The ``FILES`` parameter is
  152. optional.
  153. .. raw:: html
  154. <details><summary>TODO 5-6: Click to show/hide answer</summary>
  155. .. literalinclude:: Step8/MathFunctions/MakeTable/CMakeLists.txt
  156. :caption: TODO 5-6: MathFunctions/MakeTable/CMakeLists.txt
  157. :name: MathFunctions/MakeTable/CMakeLists.txt-add_library
  158. :language: cmake
  159. :start-at: add_library
  160. :end-at: SqrtTable.h
  161. :append: )
  162. .. raw:: html
  163. </details>
  164. Now that all the targets are described, we can force the custom target to run
  165. before any dependents of the interface library by associating them with
  166. :command:`add_dependencies`.
  167. .. raw:: html
  168. <details><summary>TODO 7: Click to show/hide answer</summary>
  169. .. literalinclude:: Step8/MathFunctions/MakeTable/CMakeLists.txt
  170. :caption: TODO 7: MathFunctions/MakeTable/CMakeLists.txt
  171. :name: MathFunctions/MakeTable/CMakeLists.txt-add_dependencies
  172. :language: cmake
  173. :start-at: add_dependencies
  174. :end-at: add_dependencies
  175. .. raw:: html
  176. </details>
  177. We are ready to add the interface library to the linked libraries of
  178. ``MathFunctions``, and add the entire ``MakeTable`` folder to the project.
  179. .. raw:: html
  180. <details><summary>TODO 8-9: Click to show/hide answer</summary>
  181. .. literalinclude:: Step8/MathFunctions/CMakeLists.txt
  182. :caption: TODO 8: MathFunctions/CMakeLists.txt
  183. :name: MathFunctions/CMakeLists.txt-link-sqrttable
  184. :language: cmake
  185. :start-at: target_link_libraries(MathFunctions
  186. :end-at: )
  187. .. literalinclude:: Step8/MathFunctions/CMakeLists.txt
  188. :caption: TODO 9: MathFunctions/CMakeLists.txt
  189. :name: MathFunctions/CMakeLists.txt-add-maketable
  190. :language: cmake
  191. :start-at: add_subdirectory(MakeTable
  192. :end-at: add_subdirectory(MakeTable
  193. .. raw:: html
  194. </details>
  195. Finally, we update the ``MathFunctions`` library itself to take advantage of
  196. the generated table.
  197. .. raw:: html
  198. <details><summary>TODO 10: Click to show/hide answer</summary>
  199. .. literalinclude:: Step8/MathFunctions/MathFunctions.cxx
  200. :caption: TODO 10: MathFunctions/MathFunctions.cxx
  201. :name: MathFunctions/MathFunctions.cxx-include-sqrttable
  202. :language: c++
  203. :start-at: #include <SqrtTable.h>
  204. :end-at: {
  205. .. raw:: html
  206. </details>