1
0

Adding a Library.rst 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  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 the header files
  41. ``MathFunctions.h`` and ``mysqrt.h``. Their respective source files
  42. ``MathFunctions.cxx`` and ``mysqrt.cxx`` are also provided. We will not need
  43. to modify any of these files. ``mysqrt.cxx`` has one function called
  44. ``mysqrt`` that provides similar functionality to the compiler's ``sqrt``
  45. function. ``MathFunctions.cxx`` contains one function ``sqrt`` which serves
  46. to hide the implementation details of ``sqrt``.
  47. From the ``Help/guide/tutorial/Step2`` directory, start with ``TODO 1`` and
  48. complete through ``TODO 6``.
  49. First, fill in the one line ``CMakeLists.txt`` in the ``MathFunctions``
  50. subdirectory.
  51. Next, edit the top level ``CMakeLists.txt``.
  52. Finally, use the newly created ``MathFunctions`` library in ``tutorial.cxx``
  53. Build and Run
  54. -------------
  55. Run the :manual:`cmake <cmake(1)>` executable or the
  56. :manual:`cmake-gui <cmake-gui(1)>` to configure the project and then build it
  57. with your chosen build tool.
  58. Below is a refresher of what that looks like from the command line:
  59. .. code-block:: console
  60. mkdir Step2_build
  61. cd Step2_build
  62. cmake ../Step2
  63. cmake --build .
  64. Try to use the newly built ``Tutorial`` and ensure that it is still
  65. producing accurate square root values.
  66. Solution
  67. --------
  68. In the ``CMakeLists.txt`` file in the ``MathFunctions`` directory, we create
  69. a library target called ``MathFunctions`` with :command:`add_library`. The
  70. source files for the library are passed as an argument to
  71. :command:`add_library`. This looks like the following line:
  72. .. raw:: html
  73. <details><summary>TODO 1: Click to show/hide answer</summary>
  74. .. code-block:: cmake
  75. :caption: TODO 1: MathFunctions/CMakeLists.txt
  76. :name: MathFunctions/CMakeLists.txt-add_library
  77. add_library(MathFunctions MathFunctions.cxx mysqrt.cxx)
  78. .. raw:: html
  79. </details>
  80. To make use of the new library we will add an :command:`add_subdirectory`
  81. call in the top-level ``CMakeLists.txt`` file so that the library will get
  82. built.
  83. .. raw:: html
  84. <details><summary>TODO 2: Click to show/hide answer</summary>
  85. .. code-block:: cmake
  86. :caption: TODO 2: CMakeLists.txt
  87. :name: CMakeLists.txt-add_subdirectory
  88. add_subdirectory(MathFunctions)
  89. .. raw:: html
  90. </details>
  91. Next, the new library target is linked to the executable target using
  92. :command:`target_link_libraries`.
  93. .. raw:: html
  94. <details><summary>TODO 3: Click to show/hide answer</summary>
  95. .. code-block:: cmake
  96. :caption: TODO 3: CMakeLists.txt
  97. :name: CMakeLists.txt-target_link_libraries
  98. target_link_libraries(Tutorial PUBLIC MathFunctions)
  99. .. raw:: html
  100. </details>
  101. Finally we need to specify the library's header file location.
  102. Modify the existing :command:`target_include_directories` call
  103. to add the ``MathFunctions`` subdirectory as an include directory
  104. so that the ``MathFunctions.h`` header file can be found.
  105. .. raw:: html
  106. <details><summary>TODO 4: Click to show/hide answer</summary>
  107. .. code-block:: cmake
  108. :caption: TODO 4: CMakeLists.txt
  109. :name: CMakeLists.txt-target_include_directories-step2
  110. target_include_directories(Tutorial PUBLIC
  111. "${PROJECT_BINARY_DIR}"
  112. "${PROJECT_SOURCE_DIR}/MathFunctions"
  113. )
  114. .. raw:: html
  115. </details>
  116. Now let's use our library. In ``tutorial.cxx``, include ``MathFunctions.h``:
  117. .. raw:: html
  118. <details><summary>TODO 5: Click to show/hide answer</summary>
  119. .. literalinclude:: Step3/tutorial.cxx
  120. :caption: TODO 5: tutorial.cxx
  121. :name: CMakeLists.txt-include-MathFunctions.h
  122. :language: cmake
  123. :start-after: #include <string>
  124. :end-before: #include "TutorialConfig.h"
  125. .. raw:: html
  126. </details>
  127. Lastly, replace ``sqrt`` with the wrapper function ``mathfunctions::sqrt``.
  128. .. raw:: html
  129. <details><summary>TODO 6: Click to show/hide answer</summary>
  130. .. literalinclude:: Step3/tutorial.cxx
  131. :caption: TODO 6: tutorial.cxx
  132. :name: CMakeLists.txt-option
  133. :language: cmake
  134. :start-after: double const inputValue = std::stod(argv[1]);
  135. :end-before: std::cout
  136. .. raw:: html
  137. </details>
  138. Exercise 2 - Adding an Option
  139. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  140. Now let us add an option in the MathFunctions library to allow developers to
  141. select either the custom square root implementation or the built in standard
  142. implementation. While for the tutorial
  143. there really isn't any need to do so, for larger projects this is a common
  144. occurrence.
  145. CMake can do this using the :command:`option` command. This gives users a
  146. variable which they can change when configuring their cmake build. This
  147. setting will be stored in the cache so that the user does not need to set
  148. the value each time they run CMake on a build directory.
  149. Goal
  150. ----
  151. Add the option to build without ``MathFunctions``.
  152. Helpful Resources
  153. -----------------
  154. * :command:`if`
  155. * :command:`option`
  156. * :command:`target_compile_definitions`
  157. Files to Edit
  158. -------------
  159. * ``MathFunctions/CMakeLists.txt``
  160. * ``MathFunctions/MathFunctions.cxx``
  161. Getting Started
  162. ---------------
  163. Start with the resulting files from Exercise 1. Complete ``TODO 7`` through
  164. ``TODO 14``.
  165. First create a variable ``USE_MYMATH`` using the :command:`option` command
  166. in ``MathFunctions/CMakeLists.txt``. In that same file, use that option
  167. to pass a compile definition to the ``MathFunctions`` library.
  168. Then, update ``MathFunctions.cxx`` to redirect compilation based on
  169. ``USE_MYMATH``.
  170. Lastly, prevent ``mysqrt.cxx`` from being compiled when ``USE_MYMATH`` is on
  171. by making it its own library inside of the ``USE_MYMATH`` block of
  172. ``MathFunctions/CMakeLists.txt``.
  173. Build and Run
  174. -------------
  175. Since we have our build directory already configured from Exercise 1, we can
  176. rebuild by simply calling the following:
  177. .. code-block:: console
  178. cd ../Step2_build
  179. cmake --build .
  180. Next, run the ``Tutorial`` executable on a few numbers to verify that it's
  181. still correct.
  182. Now let's update the value of ``USE_MYMATH`` to ``OFF``. The easiest way is to
  183. use the :manual:`cmake-gui <cmake-gui(1)>` or :manual:`ccmake <ccmake(1)>`
  184. if you're in the terminal. Or, alternatively, if you want to change the
  185. option from the command-line, try:
  186. .. code-block:: console
  187. cmake ../Step2 -DUSE_MYMATH=OFF
  188. Now, rebuild the code with the following:
  189. .. code-block:: console
  190. cmake --build .
  191. Then, run the executable again to ensure that it still works with
  192. ``USE_MYMATH`` set to ``OFF``. Which function gives better results, ``sqrt``
  193. or ``mysqrt``?
  194. Solution
  195. --------
  196. The first step is to add an option to ``MathFunctions/CMakeLists.txt``.
  197. This option will be displayed in the :manual:`cmake-gui <cmake-gui(1)>` and
  198. :manual:`ccmake <ccmake(1)>` with a default value of ``ON`` that can be
  199. changed by the user.
  200. .. raw:: html
  201. <details><summary>TODO 7: Click to show/hide answer</summary>
  202. .. literalinclude:: Step3/MathFunctions/CMakeLists.txt
  203. :caption: TODO 7: MathFunctions/CMakeLists.txt
  204. :name: CMakeLists.txt-option-library-level
  205. :language: cmake
  206. :start-after: # should we use our own math functions
  207. :end-before: if (USE_MYMATH)
  208. .. raw:: html
  209. </details>
  210. Next, make building and linking our library with ``mysqrt`` function
  211. conditional using this new option.
  212. Create an :command:`if` statement which checks the value of
  213. ``USE_MYMATH``. Inside the :command:`if` block, put the
  214. :command:`target_compile_definitions` command with the compile
  215. definition ``USE_MYMATH``.
  216. .. raw:: html
  217. <details><summary>TODO 8: Click to show/hide answer</summary>
  218. .. code-block:: cmake
  219. :caption: TODO 8: MathFunctions/CMakeLists.txt
  220. :name: CMakeLists.txt-USE_MYMATH
  221. if (USE_MYMATH)
  222. target_compile_definitions(MathFunctions PRIVATE "USE_MYMATH")
  223. endif()
  224. .. raw:: html
  225. </details>
  226. When ``USE_MYMATH`` is ``ON``, the compile definition ``USE_MYMATH`` will
  227. be set. We can then use this compile definition to enable or disable
  228. sections of our source code.
  229. The corresponding changes to the source code are fairly straightforward.
  230. In ``MathFunctions.cxx``, we make ``USE_MYMATH`` control which square root
  231. function is used:
  232. .. raw:: html
  233. <details><summary>TODO 9: Click to show/hide answer</summary>
  234. .. literalinclude:: Step3/MathFunctions/MathFunctions.cxx
  235. :caption: TODO 9: MathFunctions/MathFunctions.cxx
  236. :name: MathFunctions-USE_MYMATH-if
  237. :language: c++
  238. :start-after: which square root function should we use?
  239. :end-before: }
  240. .. raw:: html
  241. </details>
  242. Next, we need to include ``mysqrt.h`` if ``USE_MYMATH`` is defined.
  243. .. raw:: html
  244. <details><summary>TODO 10: Click to show/hide answer</summary>
  245. .. literalinclude:: Step3/MathFunctions/MathFunctions.cxx
  246. :caption: TODO 10: MathFunctions/MathFunctions.cxx
  247. :name: MathFunctions-USE_MYMATH-if-include
  248. :language: c++
  249. :start-after: include <cmath>
  250. :end-before: namespace mathfunctions
  251. .. raw:: html
  252. </details>
  253. Finally, we need to include ``cmath`` now that we are using ``std::sqrt``.
  254. .. raw:: html
  255. <details><summary>TODO 11: Click to show/hide answer</summary>
  256. .. code-block:: c++
  257. :caption: TODO 11 : MathFunctions/MathFunctions.cxx
  258. :name: tutorial.cxx-include_cmath
  259. #include <cmath>
  260. .. raw:: html
  261. </details>
  262. At this point, if ``USE_MYMATH`` is ``OFF``, ``mysqrt.cxx`` would not be used
  263. but it will still be compiled because the ``MathFunctions`` target has
  264. ``mysqrt.cxx`` listed under sources.
  265. There are a few ways to fix this. The first option is to use
  266. :command:`target_sources` to add ``mysqrt.cxx`` from within the ``USE_MYMATH``
  267. block. Another option is to create an additional library within the
  268. ``USE_MYMATH`` block which is responsible for compiling ``mysqrt.cxx``. For
  269. the sake of this tutorial, we are going to create an additional library.
  270. First, from within ``USE_MYMATH`` create a library called ``SqrtLibrary``
  271. that has sources ``mysqrt.cxx``.
  272. .. raw:: html
  273. <details><summary>TODO 12: Click to show/hide answer</summary>
  274. .. literalinclude:: Step3/MathFunctions/CMakeLists.txt
  275. :caption: TODO 12 : MathFunctions/CMakeLists.txt
  276. :name: MathFunctions/CMakeLists.txt-add_library-SqrtLibrary
  277. :language: cmake
  278. :start-after: # library that just does sqrt
  279. :end-before: # TODO 7: Link
  280. .. raw:: html
  281. </details>
  282. Next, we link ``SqrtLibrary`` onto ``MathFunctions`` when ``USE_MYMATH`` is
  283. enabled.
  284. .. raw:: html
  285. <details><summary>TODO 13: Click to show/hide answer</summary>
  286. .. literalinclude:: Step3/MathFunctions/CMakeLists.txt
  287. :caption: TODO 13 : MathFunctions/CMakeLists.txt
  288. :name: MathFunctions/CMakeLists.txt-target_link_libraries-SqrtLibrary
  289. :language: cmake
  290. :start-after: to tutorial_compiler_flags
  291. :end-before: endif()
  292. .. raw:: html
  293. </details>
  294. Finally, we can remove ``mysqrt.cxx`` from our ``MathFunctions`` library
  295. source list because it will be pulled in when ``SqrtLibrary`` is included.
  296. .. raw:: html
  297. <details><summary>TODO 14: Click to show/hide answer</summary>
  298. .. literalinclude:: Step3/MathFunctions/CMakeLists.txt
  299. :caption: TODO 14 : MathFunctions/CMakeLists.txt
  300. :name: MathFunctions/CMakeLists.txt-remove-mysqrt.cxx-MathFunctions
  301. :language: cmake
  302. :end-before: # TODO 1:
  303. .. raw:: html
  304. </details>
  305. With these changes, the ``mysqrt`` function is now completely optional to
  306. whoever is building and using the ``MathFunctions`` library. Users can toggle
  307. ``USE_MYMATH`` to manipulate what library is used in the build.