Adding a Library.rst 5.3 KB

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