Adding a Library.rst 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. Step 2: Adding a Library
  2. ========================
  3. At this point, we have seen how to create a basic project using CMake. In this
  4. step, we will learn how to create and use a library in our project. We will
  5. also see how to make the use of our library optional.
  6. Exercise 1 - Creating a Library
  7. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  8. To add a library in CMake, use the :command:`add_library` command and specify
  9. which source files should make up the library.
  10. Rather than placing all of the source files in one directory, we can organize
  11. our project with one or more subdirectories. In this case, we will create a
  12. subdirectory specifically for our library. Here, we can add a new
  13. ``CMakeLists.txt`` file and one or more source files. In the top level
  14. ``CMakeLists.txt`` file, we will use the :command:`add_subdirectory` command
  15. to add the subdirectory to the build.
  16. Once the library is created, it is connected to our executable target with
  17. :command:`target_include_directories` and :command:`target_link_libraries`.
  18. Goal
  19. ----
  20. Add and use a library.
  21. Helpful Resources
  22. -----------------
  23. * :command:`add_library`
  24. * :command:`add_subdirectory`
  25. * :command:`target_include_directories`
  26. * :command:`target_link_libraries`
  27. * :variable:`PROJECT_SOURCE_DIR`
  28. Files to Edit
  29. -------------
  30. * ``CMakeLists.txt``
  31. * ``tutorial.cxx``
  32. * ``MathFunctions/CMakeLists.txt``
  33. Getting Started
  34. ---------------
  35. In this exercise, we will add a library to our project that contains our own
  36. implementation for computing the square root of a number. The executable can
  37. then use this library instead of the standard square root function provided by
  38. the compiler.
  39. For this tutorial we will put the library into a subdirectory called
  40. ``MathFunctions``. This directory already contains a header file,
  41. ``MathFunctions.h``, and a source file ``mysqrt.cxx``. We will not need to
  42. modify either of these files. The source file has one function called
  43. ``mysqrt`` that provides similar functionality to the compiler's ``sqrt``
  44. function.
  45. From the ``Help/guide/tutorial/Step2`` directory, start with ``TODO 1`` and
  46. complete through ``TODO 6``.
  47. First, fill in the one line ``CMakeLists.txt`` in the ``MathFunctions``
  48. subdirectory.
  49. Next, edit the top level ``CMakeLists.txt``.
  50. Finally, use the newly created ``MathFunctions`` library in ``tutorial.cxx``
  51. Build and Run
  52. -------------
  53. Run the :manual:`cmake <cmake(1)>` executable or the
  54. :manual:`cmake-gui <cmake-gui(1)>` to configure the project and then build it
  55. with your chosen build tool.
  56. Below is a refresher of what that looks like from the command line:
  57. .. code-block:: console
  58. mkdir Step2_build
  59. cd Step2_build
  60. cmake ../Step2
  61. cmake --build .
  62. Try to use the newly built ``Tutorial`` and ensure that it is still
  63. producing accurate square root values.
  64. Solution
  65. --------
  66. In the ``CMakeLists.txt`` file in the ``MathFunctions`` directory, we create
  67. a library target called ``MathFunctions`` with :command:`add_library`. The
  68. source file for the library is passed as an argument to
  69. :command:`add_library`. This looks like the following line:
  70. .. raw:: html
  71. <details><summary>TODO 1: Click to show/hide answer</summary>
  72. .. literalinclude:: Step3/MathFunctions/CMakeLists.txt
  73. :caption: TODO 1: MathFunctions/CMakeLists.txt
  74. :name: MathFunctions/CMakeLists.txt-add_library
  75. :language: cmake
  76. .. raw:: html
  77. </details>
  78. To make use of the new library we will add an :command:`add_subdirectory`
  79. call in the top-level ``CMakeLists.txt`` file so that the library will get
  80. built.
  81. .. raw:: html
  82. <details><summary>TODO 2: Click to show/hide answer</summary>
  83. .. code-block:: cmake
  84. :caption: TODO 2: CMakeLists.txt
  85. :name: CMakeLists.txt-add_subdirectory
  86. add_subdirectory(MathFunctions)
  87. .. raw:: html
  88. </details>
  89. Next, the new library target is linked to the executable target using
  90. :command:`target_link_libraries`.
  91. .. raw:: html
  92. <details><summary>TODO 3: Click to show/hide answer</summary>
  93. .. code-block:: cmake
  94. :caption: TODO 3: CMakeLists.txt
  95. :name: CMakeLists.txt-target_link_libraries
  96. target_link_libraries(Tutorial PUBLIC MathFunctions)
  97. .. raw:: html
  98. </details>
  99. Finally we need to specify the library's header file location. Modify
  100. :command:`target_include_directories` to add the ``MathFunctions`` subdirectory
  101. as an include directory so that the ``MathFunctions.h`` header file can be
  102. found.
  103. .. raw:: html
  104. <details><summary>TODO 4: Click to show/hide answer</summary>
  105. .. code-block:: cmake
  106. :caption: TODO 4: CMakeLists.txt
  107. :name: CMakeLists.txt-target_include_directories-step2
  108. target_include_directories(Tutorial PUBLIC
  109. "${PROJECT_BINARY_DIR}"
  110. "${PROJECT_SOURCE_DIR}/MathFunctions"
  111. )
  112. .. raw:: html
  113. </details>
  114. Now let's use our library. In ``tutorial.cxx``, include ``MathFunctions.h``:
  115. .. raw:: html
  116. <details><summary>TODO 5: Click to show/hide answer</summary>
  117. .. code-block:: c++
  118. :caption: TODO 5 : tutorial.cxx
  119. :name: tutorial.cxx-include_MathFunctions.h
  120. #include "MathFunctions.h"
  121. .. raw:: html
  122. </details>
  123. Lastly, replace ``sqrt`` with our library function ``mysqrt``.
  124. .. raw:: html
  125. <details><summary>TODO 6: Click to show/hide answer</summary>
  126. .. code-block:: c++
  127. :caption: TODO 6 : tutorial.cxx
  128. :name: tutorial.cxx-call_mysqrt
  129. const double outputValue = mysqrt(inputValue);
  130. .. raw:: html
  131. </details>
  132. Exercise 2 - Making Our Library Optional
  133. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  134. Now let us make the MathFunctions library optional. While for the tutorial
  135. there really isn't any need to do so, for larger projects this is a common
  136. occurrence.
  137. CMake can do this using the :command:`option` command. This gives users a
  138. variable which they can change when configuring their cmake build. This
  139. setting will be stored in the cache so that the user does not need to set
  140. the value each time they run CMake on a build directory.
  141. Goal
  142. ----
  143. Add the option to build without ``MathFunctions``.
  144. Helpful Resources
  145. -----------------
  146. * :command:`if`
  147. * :command:`list`
  148. * :command:`option`
  149. * :command:`cmakedefine <configure_file>`
  150. Files to Edit
  151. -------------
  152. * ``CMakeLists.txt``
  153. * ``tutorial.cxx``
  154. * ``TutorialConfig.h.in``
  155. Getting Started
  156. ---------------
  157. Start with the resulting files from Exercise 1. Complete ``TODO 7`` through
  158. ``TODO 13``.
  159. First create a variable ``MY_MATH`` using the :command:`option` command
  160. in the top-level ``CMakeLists.txt`` file. In that same file, use that option
  161. to determine whether to build and use the ``MathFunctions`` library.
  162. Then, update ``tutorial.cxx`` and ``TutorialConfig.h.in`` to use ``MY_MATH``.
  163. Build and Run
  164. -------------
  165. Since we have our build directory already configured from Exercise 1, we can
  166. rebuild by simply calling the following:
  167. .. code-block:: console
  168. cd ../Step2_build
  169. cmake --build .
  170. Next, run the ``Tutorial`` executable on a few numbers to verify that it's
  171. still correct.
  172. Now let's update the value of ``USE_MYMATH`` to ``OFF``. The easiest way is to
  173. use the :manual:`cmake-gui <cmake-gui(1)>` or :manual:`ccmake <ccmake(1)>`
  174. if you're in the terminal. Or, alternatively, if you want to change the
  175. option from the command-line, try:
  176. .. code-block:: console
  177. cmake ../Step2 -DUSE_MYMATH=OFF
  178. Now, rebuild the code with the following:
  179. .. code-block:: console
  180. cmake --build .
  181. Then, run the executable again to ensure that it still works with
  182. ``USE_MYMATH`` set to ``OFF``. Which function gives better results, ``sqrt``
  183. or ``mysqrt``?
  184. Solution
  185. --------
  186. The first step is to add an option to the top-level ``CMakeLists.txt`` file.
  187. This option will be displayed in the :manual:`cmake-gui <cmake-gui(1)>` and
  188. :manual:`ccmake <ccmake(1)>` with a default value of ``ON`` that can be
  189. changed by the user.
  190. .. raw:: html
  191. <details><summary>TODO 7: Click to show/hide answer</summary>
  192. .. literalinclude:: Step3/CMakeLists.txt
  193. :caption: TODO 7: CMakeLists.txt
  194. :name: CMakeLists.txt-option
  195. :language: cmake
  196. :start-after: # should we use our own math functions
  197. :end-before: # configure a header file to pass some of the CMake settings
  198. .. raw:: html
  199. </details>
  200. Next, make building and linking the ``MathFunctions`` library
  201. conditional.
  202. Start by creating a :command:`list` of the optional library targets for our
  203. project. At the moment, it is just ``MathFunctions``. Let's name our list
  204. ``EXTRA_LIBS``.
  205. Similarly, we need to make a :command:`list` for the optional includes which
  206. we will call ``EXTRA_INCLUDES``. In this list, we will ``APPEND`` the path of
  207. the header file needed for our library.
  208. Next, create an :command:`if` statement which checks the value of
  209. ``USE_MYMATH``. Inside the :command:`if` block, put the
  210. :command:`add_subdirectory` command from Exercise 1 with the additional
  211. :command:`list` commands.
  212. When ``MY_MATH`` is ``ON``, the lists will be generated and will be added to
  213. our project. When ``MY_MATH`` is ``OFF``, the lists stay empty. With this
  214. strategy, we allow users to toggle ``MY_MATH`` to manipulate what library is
  215. used in the build.
  216. The top-level CMakeLists.txt file will now look like the following:
  217. .. raw:: html
  218. <details><summary>TODO 8: Click to show/hide answer</summary>
  219. .. literalinclude:: Step3/CMakeLists.txt
  220. :caption: TODO 8: CMakeLists.txt
  221. :name: CMakeLists.txt-USE_MYMATH
  222. :language: cmake
  223. :start-after: # add the MathFunctions library
  224. :end-before: # add the executable
  225. .. raw:: html
  226. </details>
  227. Now that we have these two lists, we need to update
  228. :command:`target_link_libraries` and :command:`target_include_directories` to
  229. use them. Changing them is fairly straightforward.
  230. For :command:`target_link_libraries`, we replace the written out
  231. library names with ``EXTRA_LIBS``. This looks like the following:
  232. .. raw:: html
  233. <details><summary>TODO 9: Click to show/hide answer</summary>
  234. .. literalinclude:: Step3/CMakeLists.txt
  235. :caption: TODO 9: CMakeLists.txt
  236. :name: CMakeLists.txt-target_link_libraries-EXTRA_LIBS
  237. :language: cmake
  238. :start-after: add_executable(Tutorial tutorial.cxx)
  239. :end-before: # add the binary tree to the search path for include files
  240. .. raw:: html
  241. </details>
  242. Then, we do the same thing with :command:`target_include_directories` and
  243. ``EXTRA_INCLUDES``.
  244. .. raw:: html
  245. <details><summary>TODO 10: Click to show/hide answer</summary>
  246. .. literalinclude:: Step3/CMakeLists.txt
  247. :caption: TODO 10 : CMakeLists.txt
  248. :name: CMakeLists.txt-target_link_libraries-EXTRA_INCLUDES
  249. :language: cmake
  250. :start-after: # so that we will find TutorialConfig.h
  251. .. raw:: html
  252. </details>
  253. Note that this is a classic approach when dealing with many components. We
  254. will cover the modern approach in the Step 3 of the tutorial.
  255. The corresponding changes to the source code are fairly straightforward.
  256. First, in ``tutorial.cxx``, we include the ``MathFunctions.h`` header if
  257. ``MY_MATH`` is defined.
  258. .. raw:: html
  259. <details><summary>TODO 11: Click to show/hide answer</summary>
  260. .. literalinclude:: Step3/tutorial.cxx
  261. :caption: TODO 11 : tutorial.cxx
  262. :name: tutorial.cxx-ifdef-include
  263. :language: c++
  264. :start-after: // should we include the MathFunctions header
  265. :end-before: int main
  266. .. raw:: html
  267. </details>
  268. Then, in the same file, we make ``USE_MYMATH`` control which square root
  269. function is used:
  270. .. raw:: html
  271. <details><summary>TODO 12: Click to show/hide answer</summary>
  272. .. literalinclude:: Step3/tutorial.cxx
  273. :caption: TODO 12 : tutorial.cxx
  274. :name: tutorial.cxx-ifdef-const
  275. :language: c++
  276. :start-after: // which square root function should we use?
  277. :end-before: std::cout << "The square root of
  278. .. raw:: html
  279. </details>
  280. Since the source code now requires ``USE_MYMATH`` we can add it to
  281. ``TutorialConfig.h.in`` with the following line:
  282. .. raw:: html
  283. <details><summary>TODO 13: Click to show/hide answer</summary>
  284. .. literalinclude:: Step3/TutorialConfig.h.in
  285. :caption: TODO 13 : TutorialConfig.h.in
  286. :name: TutorialConfig.h.in-cmakedefine
  287. :language: c++
  288. :lines: 4
  289. .. raw:: html
  290. </details>
  291. With these changes, our library is now completely optional to whoever is
  292. building and using it.
  293. Bonus Question
  294. --------------
  295. Why is it important that we configure ``TutorialConfig.h.in``
  296. after the option for ``USE_MYMATH``? What would happen if we inverted the two?
  297. Answer
  298. ------
  299. .. raw:: html
  300. <details><summary>Click to show/hide answer</summary>
  301. We configure after because ``TutorialConfig.h.in`` uses the value of
  302. ``USE_MYMATH``. If we configure the file before
  303. calling :command:`option`, we won't be using the expected value of
  304. ``USE_MYMATH``.
  305. .. raw:: html
  306. </details>