Adding a Library.rst 12 KB

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