1
0

Adding a Library.rst 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  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 change the end of the top-level ``CMakeLists.txt``
  54. file to look like the following:
  55. .. literalinclude:: Step3/CMakeLists.txt
  56. :caption: CMakeLists.txt
  57. :name: CMakeLists.txt-target_link_libraries-EXTRA_LIBS
  58. :language: cmake
  59. :start-after: # add the MathFunctions library
  60. Note the use of the variable ``EXTRA_LIBS`` to collect up any optional
  61. libraries to later be linked into the executable. The variable
  62. ``EXTRA_INCLUDES`` is used similarly for optional header files. This is a
  63. classic approach when dealing with many optional components, we will cover
  64. the modern approach in the next step.
  65. The corresponding changes to the source code are fairly straightforward.
  66. First, in ``tutorial.cxx``, include the ``MathFunctions.h`` header if we
  67. need it:
  68. .. literalinclude:: Step3/tutorial.cxx
  69. :caption: tutorial.cxx
  70. :name: tutorial.cxx-ifdef-include
  71. :language: c++
  72. :start-after: // should we include the MathFunctions header
  73. :end-before: int main
  74. Then, in the same file, make ``USE_MYMATH`` control which square root
  75. function is used:
  76. .. literalinclude:: Step3/tutorial.cxx
  77. :caption: tutorial.cxx
  78. :name: tutorial.cxx-ifdef-const
  79. :language: c++
  80. :start-after: // which square root function should we use?
  81. :end-before: std::cout << "The square root of
  82. Since the source code now requires ``USE_MYMATH`` we can add it to
  83. ``TutorialConfig.h.in`` with the following line:
  84. .. literalinclude:: Step3/TutorialConfig.h.in
  85. :caption: TutorialConfig.h.in
  86. :name: TutorialConfig.h.in-cmakedefine
  87. :language: c++
  88. :lines: 4
  89. **Exercise**: Why is it important that we configure ``TutorialConfig.h.in``
  90. after the option for ``USE_MYMATH``? What would happen if we inverted the two?
  91. Run the :manual:`cmake <cmake(1)>` executable or the
  92. :manual:`cmake-gui <cmake-gui(1)>` to configure the project and then build it
  93. with your chosen build tool. Then run the built Tutorial executable.
  94. Now let's update the value of ``USE_MYMATH``. The easiest way is to use the
  95. :manual:`cmake-gui <cmake-gui(1)>` or :manual:`ccmake <ccmake(1)>` if you're
  96. in the terminal. Or, alternatively, if you want to change the option from the
  97. command-line, try:
  98. .. code-block:: console
  99. cmake ../Step2 -DUSE_MYMATH=OFF
  100. Rebuild and run the tutorial again.
  101. Which function gives better results, ``sqrt`` or ``mysqrt``?