Adding a Library.rst 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  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. .. literalinclude:: Step3/MathFunctions/CMakeLists.txt
  75. :caption: TODO 1: MathFunctions/CMakeLists.txt
  76. :name: MathFunctions/CMakeLists.txt-add_library
  77. :language: cmake
  78. :end-before: # TODO 1
  79. .. raw:: html
  80. </details>
  81. To make use of the new library we will add an :command:`add_subdirectory`
  82. call in the top-level ``CMakeLists.txt`` file so that the library will get
  83. built.
  84. .. raw:: html
  85. <details><summary>TODO 2: Click to show/hide answer</summary>
  86. .. code-block:: cmake
  87. :caption: TODO 2: CMakeLists.txt
  88. :name: CMakeLists.txt-add_subdirectory
  89. add_subdirectory(MathFunctions)
  90. .. raw:: html
  91. </details>
  92. Next, the new library target is linked to the executable target using
  93. :command:`target_link_libraries`.
  94. .. raw:: html
  95. <details><summary>TODO 3: Click to show/hide answer</summary>
  96. .. code-block:: cmake
  97. :caption: TODO 3: CMakeLists.txt
  98. :name: CMakeLists.txt-target_link_libraries
  99. target_link_libraries(Tutorial PUBLIC MathFunctions)
  100. .. raw:: html
  101. </details>
  102. Finally we need to specify the library's header file location. Modify
  103. :command:`target_include_directories` to add the ``MathFunctions`` subdirectory
  104. as an include directory so that the ``MathFunctions.h`` header file can be
  105. found.
  106. .. raw:: html
  107. <details><summary>TODO 4: Click to show/hide answer</summary>
  108. .. code-block:: cmake
  109. :caption: TODO 4: CMakeLists.txt
  110. :name: CMakeLists.txt-target_include_directories-step2
  111. target_include_directories(Tutorial PUBLIC
  112. "${PROJECT_BINARY_DIR}"
  113. "${PROJECT_SOURCE_DIR}/MathFunctions"
  114. )
  115. .. raw:: html
  116. </details>
  117. Now let's use our library. In ``tutorial.cxx``, include ``MathFunctions.h``:
  118. .. raw:: html
  119. <details><summary>TODO 5: Click to show/hide answer</summary>
  120. .. literalinclude:: Step3/tutorial.cxx
  121. :caption: TODO 5: tutorial.cxx
  122. :name: CMakeLists.txt-include-MathFunctions.h
  123. :language: cmake
  124. :start-after: #include <string>
  125. :end-before: #include "TutorialConfig.h"
  126. .. raw:: html
  127. </details>
  128. Lastly, replace ``sqrt`` with our library function ``mathfunctions::mysqrt``.
  129. .. raw:: html
  130. <details><summary>TODO 6: Click to show/hide answer</summary>
  131. .. literalinclude:: Step3/tutorial.cxx
  132. :caption: TODO 7: tutorial.cxx
  133. :name: CMakeLists.txt-option
  134. :language: cmake
  135. :start-after: const double inputValue = std::stod(argv[1]);
  136. :end-before: std::cout
  137. .. raw:: html
  138. </details>
  139. Exercise 2 - Adding an Option
  140. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  141. Now let us add an option in the MathFunctions library to allow developers to
  142. select either the custom square root implementation or the built in standard
  143. implementation. While for the tutorial
  144. there really isn't any need to do so, for larger projects this is a common
  145. occurrence.
  146. CMake can do this using the :command:`option` command. This gives users a
  147. variable which they can change when configuring their cmake build. This
  148. setting will be stored in the cache so that the user does not need to set
  149. the value each time they run CMake on a build directory.
  150. Goal
  151. ----
  152. Add the option to build without ``MathFunctions``.
  153. Helpful Resources
  154. -----------------
  155. * :command:`if`
  156. * :command:`option`
  157. * :command:`target_compile_definitions`
  158. Files to Edit
  159. -------------
  160. * ``MathFunctions/CMakeLists.txt``
  161. * ``MathFunctions/MathFunctions.cxx``
  162. Getting Started
  163. ---------------
  164. Start with the resulting files from Exercise 1. Complete ``TODO 7`` through
  165. ``TODO 9``.
  166. First create a variable ``USE_MYMATH`` using the :command:`option` command
  167. in ``MathFunctions/CMakeLists.txt``. In that same file, use that option
  168. to pass a compile definition to the ``MathFunctions`` library.
  169. Then, update ``MathFunctions.cxx`` to redirect compilation based on
  170. ``USE_MYMATH``.
  171. Build and Run
  172. -------------
  173. Since we have our build directory already configured from Exercise 1, we can
  174. rebuild by simply calling the following:
  175. .. code-block:: console
  176. cd ../Step2_build
  177. cmake --build .
  178. Next, run the ``Tutorial`` executable on a few numbers to verify that it's
  179. still correct.
  180. Now let's update the value of ``USE_MYMATH`` to ``OFF``. The easiest way is to
  181. use the :manual:`cmake-gui <cmake-gui(1)>` or :manual:`ccmake <ccmake(1)>`
  182. if you're in the terminal. Or, alternatively, if you want to change the
  183. option from the command-line, try:
  184. .. code-block:: console
  185. cmake ../Step2 -DUSE_MYMATH=OFF
  186. Now, rebuild the code with the following:
  187. .. code-block:: console
  188. cmake --build .
  189. Then, run the executable again to ensure that it still works with
  190. ``USE_MYMATH`` set to ``OFF``. Which function gives better results, ``sqrt``
  191. or ``mysqrt``?
  192. Solution
  193. --------
  194. The first step is to add an option to ``MathFunctions/CMakeLists.txt``.
  195. This option will be displayed in the :manual:`cmake-gui <cmake-gui(1)>` and
  196. :manual:`ccmake <ccmake(1)>` with a default value of ``ON`` that can be
  197. changed by the user.
  198. .. raw:: html
  199. <details><summary>TODO 7: Click to show/hide answer</summary>
  200. .. literalinclude:: Step3/MathFunctions/CMakeLists.txt
  201. :caption: TODO 7: MathFunctions/CMakeLists.txt
  202. :name: CMakeLists.txt-option-library-level
  203. :language: cmake
  204. :start-after: # should we use our own math functions
  205. :end-before: if (USE_MYMATH)
  206. .. raw:: html
  207. </details>
  208. Next, make building and linking our library with ``mysqrt`` function
  209. conditional using this new option.
  210. Create an :command:`if` statement which checks the value of
  211. ``USE_MYMATH``. Inside the :command:`if` block, put the
  212. :command:`target_compile_definitions` command with the compile
  213. definition ``USE_MYMATH``.
  214. .. raw:: html
  215. <details><summary>TODO 8: Click to show/hide answer</summary>
  216. .. literalinclude:: Step3/MathFunctions/CMakeLists.txt
  217. :caption: TODO 8: MathFunctions/CMakeLists.txt
  218. :name: CMakeLists.txt-USE_MYMATH
  219. :language: cmake
  220. :start-after: USE_MYMATH "Use tutorial provided math implementation" ON)
  221. .. raw:: html
  222. </details>
  223. The corresponding changes to the source code are fairly straightforward.
  224. In ``MathFunctions.cxx``, we make ``USE_MYMATH`` control which square root
  225. function is used:
  226. .. raw:: html
  227. <details><summary>TODO 9: Click to show/hide answer</summary>
  228. .. literalinclude:: Step3/MathFunctions/MathFunctions.cxx
  229. :caption: TODO 9: MathFunctions/MathFunctions.cxx
  230. :name: MathFunctions-USE_MYMATH-if
  231. :language: c++
  232. :start-after: which square root function should we use?
  233. :end-before: }
  234. .. raw:: html
  235. </details>
  236. Next, we need to include ``mysqrt.h`` if ``USE_MYMATH`` is defined.
  237. .. raw:: html
  238. <details><summary>TODO 10: Click to show/hide answer</summary>
  239. .. literalinclude:: Step3/MathFunctions/MathFunctions.cxx
  240. :caption: TODO 10: MathFunctions/MathFunctions.cxx
  241. :name: MathFunctions-USE_MYMATH-if-include
  242. :language: c++
  243. :start-after: include <cmath>
  244. :end-before: namespace mathfunctions
  245. .. raw:: html
  246. </details>
  247. Finally, we need to include ``cmath`` now that we are using ``std::sqrt``.
  248. .. raw:: html
  249. <details><summary>TODO 11: Click to show/hide answer</summary>
  250. .. code-block:: c++
  251. :caption: TODO 11 : MathFunctions/MathFunctions.cxx
  252. :name: tutorial.cxx-include_cmath
  253. #include <cmath>
  254. .. raw:: html
  255. </details>
  256. When ``USE_MYMATH`` is ``ON``, the compile definition ``USE_MYMATH`` will
  257. be set. We can then use this compile definition to enable or disable
  258. sections of our source code. With this strategy, we allow users to
  259. toggle ``USE_MYMATH`` to manipulate what library is used in the build.
  260. With these changes, the ``mysqrt`` function is now completely optional to
  261. whoever is building and using the ``MathFunctions`` library.