You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
cmake/Help/guide/tutorial/Adding a Library.rst

137 lines
5.3 KiB

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``?