1
0

Adding a Library.rst 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458
  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 ``MY_MATH`` 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 ``MY_MATH``.
  164. Build and Run
  165. -------------
  166. Since we have our build directory already configured from Exercise 1, we can
  167. rebuild by simply calling the following:
  168. .. code-block:: console
  169. cd ../Step2_build
  170. cmake --build .
  171. Next, run the ``Tutorial`` executable on a few numbers to verify that it's
  172. still correct.
  173. Now let's update the value of ``USE_MYMATH`` to ``OFF``. The easiest way is to
  174. use the :manual:`cmake-gui <cmake-gui(1)>` or :manual:`ccmake <ccmake(1)>`
  175. if you're in the terminal. Or, alternatively, if you want to change the
  176. option from the command-line, try:
  177. .. code-block:: console
  178. cmake ../Step2 -DUSE_MYMATH=OFF
  179. Now, rebuild the code with the following:
  180. .. code-block:: console
  181. cmake --build .
  182. Then, run the executable again to ensure that it still works with
  183. ``USE_MYMATH`` set to ``OFF``. Which function gives better results, ``sqrt``
  184. or ``mysqrt``?
  185. Solution
  186. --------
  187. The first step is to add an option to the top-level ``CMakeLists.txt`` file.
  188. This option will be displayed in the :manual:`cmake-gui <cmake-gui(1)>` and
  189. :manual:`ccmake <ccmake(1)>` with a default value of ``ON`` that can be
  190. changed by the user.
  191. .. raw:: html
  192. <details><summary>TODO 7: Click to show/hide answer</summary>
  193. .. literalinclude:: Step3/CMakeLists.txt
  194. :caption: TODO 7: CMakeLists.txt
  195. :name: CMakeLists.txt-option
  196. :language: cmake
  197. :start-after: # should we use our own math functions
  198. :end-before: # configure a header file to pass some of the CMake settings
  199. .. raw:: html
  200. </details>
  201. Next, make building and linking the ``MathFunctions`` library
  202. conditional.
  203. Start by creating a :command:`list` of the optional library targets for our
  204. project. At the moment, it is just ``MathFunctions``. Let's name our list
  205. ``EXTRA_LIBS``.
  206. Similarly, we need to make a :command:`list` for the optional includes which
  207. we will call ``EXTRA_INCLUDES``. In this list, we will ``APPEND`` the path of
  208. the header file needed for our library.
  209. Next, create an :command:`if` statement which checks the value of
  210. ``USE_MYMATH``. Inside the :command:`if` block, put the
  211. :command:`add_subdirectory` command from Exercise 1 with the additional
  212. :command:`list` commands.
  213. When ``MY_MATH`` is ``ON``, the lists will be generated and will be added to
  214. our project. When ``MY_MATH`` is ``OFF``, the lists stay empty. With this
  215. strategy, we allow users to toggle ``MY_MATH`` to manipulate what library is
  216. used in the build.
  217. The top-level CMakeLists.txt file will now look like the following:
  218. .. raw:: html
  219. <details><summary>TODO 8: Click to show/hide answer</summary>
  220. .. literalinclude:: Step3/CMakeLists.txt
  221. :caption: TODO 8: CMakeLists.txt
  222. :name: CMakeLists.txt-USE_MYMATH
  223. :language: cmake
  224. :start-after: # add the MathFunctions library
  225. :end-before: # add the executable
  226. .. raw:: html
  227. </details>
  228. Now that we have these two lists, we need to update
  229. :command:`target_link_libraries` and :command:`target_include_directories` to
  230. use them. Changing them is fairly straightforward.
  231. For :command:`target_link_libraries`, we replace the written out
  232. library names with ``EXTRA_LIBS``. This looks like the following:
  233. .. raw:: html
  234. <details><summary>TODO 9: Click to show/hide answer</summary>
  235. .. literalinclude:: Step3/CMakeLists.txt
  236. :caption: TODO 9: CMakeLists.txt
  237. :name: CMakeLists.txt-target_link_libraries-EXTRA_LIBS
  238. :language: cmake
  239. :start-after: add_executable(Tutorial tutorial.cxx)
  240. :end-before: # TODO 3
  241. .. raw:: html
  242. </details>
  243. Then, we do the same thing with :command:`target_include_directories` and
  244. ``EXTRA_INCLUDES``.
  245. .. raw:: html
  246. <details><summary>TODO 10: Click to show/hide answer</summary>
  247. .. literalinclude:: Step3/CMakeLists.txt
  248. :caption: TODO 10 : CMakeLists.txt
  249. :name: CMakeLists.txt-target_link_libraries-EXTRA_INCLUDES
  250. :language: cmake
  251. :start-after: # so that we will find TutorialConfig.h
  252. .. raw:: html
  253. </details>
  254. Note that this is a classic approach when dealing with many components. We
  255. will cover the modern approach in the Step 3 of the tutorial.
  256. The corresponding changes to the source code are fairly straightforward.
  257. First, in ``tutorial.cxx``, we include the ``MathFunctions.h`` header if
  258. ``MY_MATH`` is defined.
  259. .. raw:: html
  260. <details><summary>TODO 11: Click to show/hide answer</summary>
  261. .. literalinclude:: Step3/tutorial.cxx
  262. :caption: TODO 11 : tutorial.cxx
  263. :name: tutorial.cxx-ifdef-include
  264. :language: c++
  265. :start-after: // should we include the MathFunctions header
  266. :end-before: int main
  267. .. raw:: html
  268. </details>
  269. Then, in the same file, we make ``USE_MYMATH`` control which square root
  270. function is used:
  271. .. raw:: html
  272. <details><summary>TODO 12: Click to show/hide answer</summary>
  273. .. literalinclude:: Step3/tutorial.cxx
  274. :caption: TODO 12 : tutorial.cxx
  275. :name: tutorial.cxx-ifdef-const
  276. :language: c++
  277. :start-after: // which square root function should we use?
  278. :end-before: std::cout << "The square root of
  279. .. raw:: html
  280. </details>
  281. Since the source code now requires ``USE_MYMATH`` we can add it to
  282. ``TutorialConfig.h.in`` with the following line:
  283. .. raw:: html
  284. <details><summary>TODO 13: Click to show/hide answer</summary>
  285. .. literalinclude:: Step3/TutorialConfig.h.in
  286. :caption: TODO 13 : TutorialConfig.h.in
  287. :name: TutorialConfig.h.in-cmakedefine
  288. :language: c++
  289. :lines: 4
  290. .. raw:: html
  291. </details>
  292. With these changes, our library is now completely optional to whoever is
  293. building and using it.
  294. Bonus Question
  295. --------------
  296. Why is it important that we configure ``TutorialConfig.h.in``
  297. after the option for ``USE_MYMATH``? What would happen if we inverted the two?
  298. Answer
  299. ------
  300. .. raw:: html
  301. <details><summary>Click to show/hide answer</summary>
  302. We configure after because ``TutorialConfig.h.in`` uses the value of
  303. ``USE_MYMATH``. If we configure the file before
  304. calling :command:`option`, we won't be using the expected value of
  305. ``USE_MYMATH``.
  306. .. raw:: html
  307. </details>