| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136 |
- Step 2: Adding a Library
- ========================
- Now we will add a library to our project. This library will contain our own
- implementation for computing the square root of a number. The executable can
- then use this library instead of the standard square root function provided by
- the compiler.
- For this tutorial we will put the library into a subdirectory
- called ``MathFunctions``. This directory already contains a header file,
- ``MathFunctions.h``, and a source file ``mysqrt.cxx``. The source file has one
- function called ``mysqrt`` that provides similar functionality to the
- compiler's ``sqrt`` function.
- Add the following one line ``CMakeLists.txt`` file to the ``MathFunctions``
- directory:
- .. literalinclude:: Step3/MathFunctions/CMakeLists.txt
- :caption: MathFunctions/CMakeLists.txt
- :name: MathFunctions/CMakeLists.txt
- :language: cmake
- To make use of the new library we will add an :command:`add_subdirectory`
- call in the top-level ``CMakeLists.txt`` file so that the library will get
- built. We add the new library to the executable, and add ``MathFunctions`` as
- an include directory so that the ``MathFunctions.h`` header file can be found.
- The last few lines of the top-level ``CMakeLists.txt`` file should now look
- like:
- .. code-block:: cmake
- :caption: CMakeLists.txt
- :name: CMakeLists.txt-add_subdirectory
- # add the MathFunctions library
- add_subdirectory(MathFunctions)
- # add the executable
- add_executable(Tutorial tutorial.cxx)
- target_link_libraries(Tutorial PUBLIC MathFunctions)
- # add the binary tree to the search path for include files
- # so that we will find TutorialConfig.h
- target_include_directories(Tutorial PUBLIC
- "${PROJECT_BINARY_DIR}"
- "${PROJECT_SOURCE_DIR}/MathFunctions"
- )
- Now let us make the ``MathFunctions`` library optional. While for the tutorial
- there really isn't any need to do so, for larger projects this is a common
- occurrence. The first step is to add an option to the top-level
- ``CMakeLists.txt`` file.
- .. literalinclude:: Step3/CMakeLists.txt
- :caption: CMakeLists.txt
- :name: CMakeLists.txt-option
- :language: cmake
- :start-after: # should we use our own math functions
- :end-before: # add the MathFunctions library
- This option will be displayed in the :manual:`cmake-gui <cmake-gui(1)>` and
- :manual:`ccmake <ccmake(1)>`
- with a default value of ``ON`` that can be changed by the user. This setting
- will be stored in the cache so that the user does not need to set the value
- each time they run CMake on a build directory.
- The next change is to make building and linking the ``MathFunctions`` library
- conditional. To do this, we will create an ``if`` statement which checks the
- value of the option. Inside the ``if`` block, put the
- :command:`add_subdirectory` command from above with some additional list
- commands to store information needed to link to the library and add the
- subdirectory as an include directory in the ``Tutorial`` target.
- The end of the top-level ``CMakeLists.txt`` file will now look like the
- following:
- .. literalinclude:: Step3/CMakeLists.txt
- :caption: CMakeLists.txt
- :name: CMakeLists.txt-target_link_libraries-EXTRA_LIBS
- :language: cmake
- :start-after: # add the MathFunctions library
- Note the use of the variable ``EXTRA_LIBS`` to collect up any optional
- libraries to later be linked into the executable. The variable
- ``EXTRA_INCLUDES`` is used similarly for optional header files. This is a
- classic approach when dealing with many optional components, we will cover
- the modern approach in the next step.
- The corresponding changes to the source code are fairly straightforward.
- First, in ``tutorial.cxx``, include the ``MathFunctions.h`` header if we
- need it:
- .. literalinclude:: Step3/tutorial.cxx
- :caption: tutorial.cxx
- :name: tutorial.cxx-ifdef-include
- :language: c++
- :start-after: // should we include the MathFunctions header
- :end-before: int main
- Then, in the same file, make ``USE_MYMATH`` control which square root
- function is used:
- .. literalinclude:: Step3/tutorial.cxx
- :caption: tutorial.cxx
- :name: tutorial.cxx-ifdef-const
- :language: c++
- :start-after: // which square root function should we use?
- :end-before: std::cout << "The square root of
- Since the source code now requires ``USE_MYMATH`` we can add it to
- ``TutorialConfig.h.in`` with the following line:
- .. literalinclude:: Step3/TutorialConfig.h.in
- :caption: TutorialConfig.h.in
- :name: TutorialConfig.h.in-cmakedefine
- :language: c++
- :lines: 4
- **Exercise**: Why is it important that we configure ``TutorialConfig.h.in``
- after the option for ``USE_MYMATH``? What would happen if we inverted the two?
- Run the :manual:`cmake <cmake(1)>` executable or the
- :manual:`cmake-gui <cmake-gui(1)>` to configure the project and then build it
- with your chosen build tool. Then run the built Tutorial executable.
- Now let's update the value of ``USE_MYMATH``. The easiest way is to use the
- :manual:`cmake-gui <cmake-gui(1)>` or :manual:`ccmake <ccmake(1)>` if you're
- in the terminal. Or, alternatively, if you want to change the option from the
- command-line, try:
- .. code-block:: console
- cmake ../Step2 -DUSE_MYMATH=OFF
- Rebuild and run the tutorial again.
- Which function gives better results, ``sqrt`` or ``mysqrt``?
|