Adding a Library.rst 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. Step 2: Adding a Library
  2. ========================
  3. Now we will add a library to our project. This library will contain our own
  4. implementation for computing the square root of a number. The executable can
  5. then use this library instead of the standard square root function provided by
  6. the compiler.
  7. For this tutorial we will put the library into a subdirectory
  8. called ``MathFunctions``. This directory already contains a header file,
  9. ``MathFunctions.h``, and a source file ``mysqrt.cxx``. The source file has one
  10. function called ``mysqrt`` that provides similar functionality to the
  11. compiler's ``sqrt`` function.
  12. Add the following one line ``CMakeLists.txt`` file to the ``MathFunctions``
  13. directory:
  14. .. literalinclude:: Step3/MathFunctions/CMakeLists.txt
  15. :caption: MathFunctions/CMakeLists.txt
  16. :name: MathFunctions/CMakeLists.txt
  17. :language: cmake
  18. To make use of the new library we will add an :command:`add_subdirectory`
  19. call in the top-level ``CMakeLists.txt`` file so that the library will get
  20. built. We add the new library to the executable, and add ``MathFunctions`` as
  21. an include directory so that the ``MathFunctions.h`` header file can be found.
  22. The last few lines of the top-level ``CMakeLists.txt`` file should now look
  23. like:
  24. .. code-block:: cmake
  25. :caption: CMakeLists.txt
  26. :name: CMakeLists.txt-add_subdirectory
  27. # add the MathFunctions library
  28. add_subdirectory(MathFunctions)
  29. # add the executable
  30. add_executable(Tutorial tutorial.cxx)
  31. target_link_libraries(Tutorial PUBLIC MathFunctions)
  32. # add the binary tree to the search path for include files
  33. # so that we will find TutorialConfig.h
  34. target_include_directories(Tutorial PUBLIC
  35. "${PROJECT_BINARY_DIR}"
  36. "${PROJECT_SOURCE_DIR}/MathFunctions"
  37. )
  38. Now let us make the ``MathFunctions`` library optional. While for the tutorial
  39. there really isn't any need to do so, for larger projects this is a common
  40. occurrence. The first step is to add an option to the top-level
  41. ``CMakeLists.txt`` file.
  42. .. literalinclude:: Step3/CMakeLists.txt
  43. :caption: CMakeLists.txt
  44. :name: CMakeLists.txt-option
  45. :language: cmake
  46. :start-after: # should we use our own math functions
  47. :end-before: # add the MathFunctions library
  48. This option will be displayed in the :manual:`cmake-gui <cmake-gui(1)>` and
  49. :manual:`ccmake <ccmake(1)>`
  50. with a default value of ``ON`` that can be changed by the user. This setting
  51. will be stored in the cache so that the user does not need to set the value
  52. each time they run CMake on a build directory.
  53. The next change is to make building and linking the ``MathFunctions`` library
  54. conditional. To do this, we will create an ``if`` statement which checks the
  55. value of the option. Inside the ``if`` block, put the
  56. :command:`add_subdirectory` command from above with some additional list
  57. commands to store information needed to link to the library and add the
  58. subdirectory as an include directory in the ``Tutorial`` target.
  59. The end of the top-level ``CMakeLists.txt`` file will now look like the
  60. following:
  61. .. literalinclude:: Step3/CMakeLists.txt
  62. :caption: CMakeLists.txt
  63. :name: CMakeLists.txt-target_link_libraries-EXTRA_LIBS
  64. :language: cmake
  65. :start-after: # add the MathFunctions library
  66. Note the use of the variable ``EXTRA_LIBS`` to collect up any optional
  67. libraries to later be linked into the executable. The variable
  68. ``EXTRA_INCLUDES`` is used similarly for optional header files. This is a
  69. classic approach when dealing with many optional components, we will cover
  70. the modern approach in the next step.
  71. The corresponding changes to the source code are fairly straightforward.
  72. First, in ``tutorial.cxx``, include the ``MathFunctions.h`` header if we
  73. need it:
  74. .. literalinclude:: Step3/tutorial.cxx
  75. :caption: tutorial.cxx
  76. :name: tutorial.cxx-ifdef-include
  77. :language: c++
  78. :start-after: // should we include the MathFunctions header
  79. :end-before: int main
  80. Then, in the same file, make ``USE_MYMATH`` control which square root
  81. function is used:
  82. .. literalinclude:: Step3/tutorial.cxx
  83. :caption: tutorial.cxx
  84. :name: tutorial.cxx-ifdef-const
  85. :language: c++
  86. :start-after: // which square root function should we use?
  87. :end-before: std::cout << "The square root of
  88. Since the source code now requires ``USE_MYMATH`` we can add it to
  89. ``TutorialConfig.h.in`` with the following line:
  90. .. literalinclude:: Step3/TutorialConfig.h.in
  91. :caption: TutorialConfig.h.in
  92. :name: TutorialConfig.h.in-cmakedefine
  93. :language: c++
  94. :lines: 4
  95. **Exercise**: Why is it important that we configure ``TutorialConfig.h.in``
  96. after the option for ``USE_MYMATH``? What would happen if we inverted the two?
  97. Run the :manual:`cmake <cmake(1)>` executable or the
  98. :manual:`cmake-gui <cmake-gui(1)>` to configure the project and then build it
  99. with your chosen build tool. Then run the built Tutorial executable.
  100. Now let's update the value of ``USE_MYMATH``. The easiest way is to use the
  101. :manual:`cmake-gui <cmake-gui(1)>` or :manual:`ccmake <ccmake(1)>` if you're
  102. in the terminal. Or, alternatively, if you want to change the option from the
  103. command-line, try:
  104. .. code-block:: console
  105. cmake ../Step2 -DUSE_MYMATH=OFF
  106. Rebuild and run the tutorial again.
  107. Which function gives better results, ``sqrt`` or ``mysqrt``?