mirror of
https://github.com/Kitware/CMake.git
synced 2025-10-21 14:40:48 +08:00
Tutorial: Update step 2 style
This commit is contained in:
@@ -160,7 +160,7 @@ The last command to call for a basic project is
|
|||||||
:name: CMakeLists.txt-add_executable
|
:name: CMakeLists.txt-add_executable
|
||||||
:language: cmake
|
:language: cmake
|
||||||
:start-after: # add the executable
|
:start-after: # add the executable
|
||||||
:end-before: # add the binary tree to the search path for include files
|
:end-before: # TODO 9:
|
||||||
|
|
||||||
.. raw:: html
|
.. raw:: html
|
||||||
|
|
||||||
@@ -240,7 +240,7 @@ the following:
|
|||||||
:name: tutorial.cxx-cxx11
|
:name: tutorial.cxx-cxx11
|
||||||
:language: c++
|
:language: c++
|
||||||
:start-after: // convert input to double
|
:start-after: // convert input to double
|
||||||
:end-before: // calculate square root
|
:end-before: // TODO 12:
|
||||||
|
|
||||||
.. raw:: html
|
.. raw:: html
|
||||||
|
|
||||||
@@ -265,7 +265,7 @@ add the :variable:`CMAKE_CXX_STANDARD` declarations above the call to
|
|||||||
:name: CMakeLists.txt-CXX_STANDARD
|
:name: CMakeLists.txt-CXX_STANDARD
|
||||||
:language: cmake
|
:language: cmake
|
||||||
:start-after: # specify the C++ standard
|
:start-after: # specify the C++ standard
|
||||||
:end-before: # configure a header file to pass some of the CMake settings
|
:end-before: # TODO 7:
|
||||||
|
|
||||||
.. raw:: html
|
.. raw:: html
|
||||||
|
|
||||||
@@ -345,7 +345,7 @@ lets us maintain a single source of data for the version number.
|
|||||||
|
|
||||||
First, we modify the ``CMakeLists.txt`` file to use the
|
First, we modify the ``CMakeLists.txt`` file to use the
|
||||||
:command:`project` command to set both the project name and version number.
|
:command:`project` command to set both the project name and version number.
|
||||||
When the command:`project` command is called, CMake defines
|
When the :command:`project` command is called, CMake defines
|
||||||
``Tutorial_VERSION_MAJOR`` and ``Tutorial_VERSION_MINOR`` behind the scenes.
|
``Tutorial_VERSION_MAJOR`` and ``Tutorial_VERSION_MINOR`` behind the scenes.
|
||||||
|
|
||||||
.. raw:: html
|
.. raw:: html
|
||||||
@@ -375,7 +375,7 @@ specified CMake variables replaced:
|
|||||||
:name: CMakeLists.txt-configure_file
|
:name: CMakeLists.txt-configure_file
|
||||||
:language: cmake
|
:language: cmake
|
||||||
:start-after: # to the source code
|
:start-after: # to the source code
|
||||||
:end-before: # add the executable
|
:end-before: # TODO 8:
|
||||||
|
|
||||||
.. raw:: html
|
.. raw:: html
|
||||||
|
|
||||||
@@ -420,6 +420,7 @@ be replaced with the corresponding version numbers from the project in
|
|||||||
:caption: TODO 10: TutorialConfig.h.in
|
:caption: TODO 10: TutorialConfig.h.in
|
||||||
:name: TutorialConfig.h.in
|
:name: TutorialConfig.h.in
|
||||||
:language: c++
|
:language: c++
|
||||||
|
:end-before: // TODO 13:
|
||||||
|
|
||||||
.. raw:: html
|
.. raw:: html
|
||||||
|
|
||||||
|
@@ -1,136 +1,457 @@
|
|||||||
Step 2: Adding a Library
|
Step 2: Adding a Library
|
||||||
========================
|
========================
|
||||||
|
|
||||||
Now we will add a library to our project. This library will contain our own
|
At this point, we have seen how to create a basic project using CMake. In this
|
||||||
|
step, we will learn how to create and use a library in our project. We will
|
||||||
|
also see how to make the use of our library optional.
|
||||||
|
|
||||||
|
Exercise 1 - Creating a Library
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
To add a library in CMake, use the :command:`add_library` command and specify
|
||||||
|
which source files should make up the library.
|
||||||
|
|
||||||
|
Rather than placing all of the source files in one directory, we can organize
|
||||||
|
our project with one or more subdirectories. In this case, we will create a
|
||||||
|
subdirectory specifically for our library. Here, we can add a new
|
||||||
|
``CMakeLists.txt`` file and one or more source files. In the top level
|
||||||
|
``CMakeLists.txt`` file, we will use the :command:`add_subdirectory` command
|
||||||
|
to add the subdirectory to the build.
|
||||||
|
|
||||||
|
Once the library is created, it is connected to our executable target with
|
||||||
|
:command:`target_include_directories` and :command:`target_link_libraries`.
|
||||||
|
|
||||||
|
Goal
|
||||||
|
----
|
||||||
|
|
||||||
|
Add and use a library.
|
||||||
|
|
||||||
|
Helpful Resources
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
* :command:`add_library`
|
||||||
|
* :command:`add_subdirectory`
|
||||||
|
* :command:`target_include_directories`
|
||||||
|
* :command:`target_link_libraries`
|
||||||
|
* :variable:`PROJECT_SOURCE_DIR`
|
||||||
|
|
||||||
|
Files to Edit
|
||||||
|
-------------
|
||||||
|
|
||||||
|
* ``CMakeLists.txt``
|
||||||
|
* ``tutorial.cxx``
|
||||||
|
* ``MathFunctions/CMakeLists.txt``
|
||||||
|
|
||||||
|
Getting Started
|
||||||
|
---------------
|
||||||
|
|
||||||
|
In this exercise, we will add a library to our project that contains our own
|
||||||
implementation for computing the square root of a number. The executable can
|
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
|
then use this library instead of the standard square root function provided by
|
||||||
the compiler.
|
the compiler.
|
||||||
|
|
||||||
For this tutorial we will put the library into a subdirectory
|
For this tutorial we will put the library into a subdirectory called
|
||||||
called ``MathFunctions``. This directory already contains a header file,
|
``MathFunctions``. This directory already contains a header file,
|
||||||
``MathFunctions.h``, and a source file ``mysqrt.cxx``. The source file has one
|
``MathFunctions.h``, and a source file ``mysqrt.cxx``. We will not need to
|
||||||
function called ``mysqrt`` that provides similar functionality to the
|
modify either of these files. The source file has one function called
|
||||||
compiler's ``sqrt`` function.
|
``mysqrt`` that provides similar functionality to the compiler's ``sqrt``
|
||||||
|
function.
|
||||||
|
|
||||||
Add the following one line ``CMakeLists.txt`` file to the ``MathFunctions``
|
From the ``Help/guide/tutorial/Step2`` directory, start with ``TODO 1`` and
|
||||||
directory:
|
complete through ``TODO 6``.
|
||||||
|
|
||||||
|
First, fill in the one line ``CMakeLists.txt`` in the ``MathFunctions``
|
||||||
|
subdirectory.
|
||||||
|
|
||||||
|
Next, edit the top level ``CMakeLists.txt``.
|
||||||
|
|
||||||
|
Finally, use the newly created ``MathFunctions`` library in ``tutorial.cxx``
|
||||||
|
|
||||||
|
Build and Run
|
||||||
|
-------------
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
Below is a refresher of what that looks like from the command line:
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
mkdir Step2_build
|
||||||
|
cd Step2_build
|
||||||
|
cmake ../Step2
|
||||||
|
cmake --build .
|
||||||
|
|
||||||
|
Try to use the newly built ``Tutorial`` and ensure that it is still
|
||||||
|
producing accurate square root values.
|
||||||
|
|
||||||
|
Solution
|
||||||
|
--------
|
||||||
|
|
||||||
|
In the ``CMakeLists.txt`` file in the ``MathFunctions`` directory, we create
|
||||||
|
a library target called ``MathFunctions`` with :command:`add_library`. The
|
||||||
|
source file for the library is passed as an argument to
|
||||||
|
:command:`add_library`. This looks like the following line:
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
<details><summary>TODO 1: Click to show/hide answer</summary>
|
||||||
|
|
||||||
.. literalinclude:: Step3/MathFunctions/CMakeLists.txt
|
.. literalinclude:: Step3/MathFunctions/CMakeLists.txt
|
||||||
:caption: MathFunctions/CMakeLists.txt
|
:caption: TODO 1: MathFunctions/CMakeLists.txt
|
||||||
:name: MathFunctions/CMakeLists.txt
|
:name: MathFunctions/CMakeLists.txt-add_library
|
||||||
:language: cmake
|
:language: cmake
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
To make use of the new library we will add an :command:`add_subdirectory`
|
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
|
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
|
built.
|
||||||
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
|
.. raw:: html
|
||||||
like:
|
|
||||||
|
<details><summary>TODO 2: Click to show/hide answer</summary>
|
||||||
|
|
||||||
.. code-block:: cmake
|
.. code-block:: cmake
|
||||||
:caption: CMakeLists.txt
|
:caption: TODO 2: CMakeLists.txt
|
||||||
:name: CMakeLists.txt-add_subdirectory
|
:name: CMakeLists.txt-add_subdirectory
|
||||||
|
|
||||||
# add the MathFunctions library
|
|
||||||
add_subdirectory(MathFunctions)
|
add_subdirectory(MathFunctions)
|
||||||
|
|
||||||
# add the executable
|
.. raw:: html
|
||||||
add_executable(Tutorial tutorial.cxx)
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
Next, the new library target is linked to the executable target using
|
||||||
|
:command:`target_link_libraries`.
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
<details><summary>TODO 3: Click to show/hide answer</summary>
|
||||||
|
|
||||||
|
.. code-block:: cmake
|
||||||
|
:caption: TODO 3: CMakeLists.txt
|
||||||
|
:name: CMakeLists.txt-target_link_libraries
|
||||||
|
|
||||||
target_link_libraries(Tutorial PUBLIC MathFunctions)
|
target_link_libraries(Tutorial PUBLIC MathFunctions)
|
||||||
|
|
||||||
# add the binary tree to the search path for include files
|
.. raw:: html
|
||||||
# so that we will find TutorialConfig.h
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
Finally we need to specify the library's header file location. Modify
|
||||||
|
:command:`target_include_directories` to add the ``MathFunctions`` subdirectory
|
||||||
|
as an include directory so that the ``MathFunctions.h`` header file can be
|
||||||
|
found.
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
<details><summary>TODO 4: Click to show/hide answer</summary>
|
||||||
|
|
||||||
|
.. code-block:: cmake
|
||||||
|
:caption: TODO 4: CMakeLists.txt
|
||||||
|
:name: CMakeLists.txt-target_include_directories-step2
|
||||||
|
|
||||||
target_include_directories(Tutorial PUBLIC
|
target_include_directories(Tutorial PUBLIC
|
||||||
"${PROJECT_BINARY_DIR}"
|
"${PROJECT_BINARY_DIR}"
|
||||||
"${PROJECT_SOURCE_DIR}/MathFunctions"
|
"${PROJECT_SOURCE_DIR}/MathFunctions"
|
||||||
)
|
)
|
||||||
|
|
||||||
Now let us make the ``MathFunctions`` library optional. While for the tutorial
|
.. raw:: html
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
Now let's use our library. In ``tutorial.cxx``, include ``MathFunctions.h``:
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
<details><summary>TODO 5: Click to show/hide answer</summary>
|
||||||
|
|
||||||
|
.. code-block:: c++
|
||||||
|
:caption: TODO 5 : tutorial.cxx
|
||||||
|
:name: tutorial.cxx-include_MathFunctions.h
|
||||||
|
|
||||||
|
#include "MathFunctions.h"
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
Lastly, replace ``sqrt`` with our library function ``mysqrt``.
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
<details><summary>TODO 6: Click to show/hide answer</summary>
|
||||||
|
|
||||||
|
.. code-block:: c++
|
||||||
|
:caption: TODO 6 : tutorial.cxx
|
||||||
|
:name: tutorial.cxx-call_mysqrt
|
||||||
|
|
||||||
|
const double outputValue = mysqrt(inputValue);
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
Exercise 2 - Making Our Library Optional
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
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
|
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
|
occurrence.
|
||||||
``CMakeLists.txt`` file.
|
|
||||||
|
|
||||||
.. literalinclude:: Step3/CMakeLists.txt
|
CMake can do this using the :command:`option` command. This gives users a
|
||||||
:caption: CMakeLists.txt
|
variable which they can change when configuring their cmake build. This
|
||||||
:name: CMakeLists.txt-option
|
setting will be stored in the cache so that the user does not need to set
|
||||||
:language: cmake
|
the value each time they run CMake on a build directory.
|
||||||
: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
|
Goal
|
||||||
: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
|
Add the option to build without ``MathFunctions``.
|
||||||
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
|
Helpful Resources
|
||||||
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.
|
* :command:`if`
|
||||||
First, in ``tutorial.cxx``, include the ``MathFunctions.h`` header if we
|
* :command:`list`
|
||||||
need it:
|
* :command:`option`
|
||||||
|
* :command:`cmakedefine <configure_file>`
|
||||||
|
|
||||||
.. literalinclude:: Step3/tutorial.cxx
|
Files to Edit
|
||||||
: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
|
* ``CMakeLists.txt``
|
||||||
function is used:
|
* ``tutorial.cxx``
|
||||||
|
* ``TutorialConfig.h.in``
|
||||||
|
|
||||||
.. literalinclude:: Step3/tutorial.cxx
|
Getting Started
|
||||||
: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
|
Start with the resulting files from Exercise 1. Complete ``TODO 7`` through
|
||||||
``TutorialConfig.h.in`` with the following line:
|
``TODO 13``.
|
||||||
|
|
||||||
.. literalinclude:: Step3/TutorialConfig.h.in
|
First create a variable ``MY_MATH`` using the :command:`option` command
|
||||||
:caption: TutorialConfig.h.in
|
in the top-level ``CMakeLists.txt`` file. In that same file, use that option
|
||||||
:name: TutorialConfig.h.in-cmakedefine
|
to determine whether to build and use the ``MathFunctions`` library.
|
||||||
:language: c++
|
|
||||||
:lines: 4
|
|
||||||
|
|
||||||
**Exercise**: Why is it important that we configure ``TutorialConfig.h.in``
|
Then, update ``tutorial.cxx`` and ``TutorialConfig.h.in`` to use ``MY_MATH``.
|
||||||
after the option for ``USE_MYMATH``? What would happen if we inverted the two?
|
|
||||||
|
|
||||||
Run the :manual:`cmake <cmake(1)>` executable or the
|
Build and Run
|
||||||
: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
|
Since we have our build directory already configured from Exercise 1, we can
|
||||||
:manual:`cmake-gui <cmake-gui(1)>` or :manual:`ccmake <ccmake(1)>` if you're
|
rebuild by simply calling the following:
|
||||||
in the terminal. Or, alternatively, if you want to change the option from the
|
|
||||||
command-line, try:
|
.. code-block:: console
|
||||||
|
|
||||||
|
cd ../Step2_build
|
||||||
|
cmake --build .
|
||||||
|
|
||||||
|
Next, run the ``Tutorial`` executable on a few numbers to verify that it's
|
||||||
|
still correct.
|
||||||
|
|
||||||
|
Now let's update the value of ``USE_MYMATH`` to ``OFF``. 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
|
.. code-block:: console
|
||||||
|
|
||||||
cmake ../Step2 -DUSE_MYMATH=OFF
|
cmake ../Step2 -DUSE_MYMATH=OFF
|
||||||
|
|
||||||
Rebuild and run the tutorial again.
|
Now, rebuild the code with the following:
|
||||||
|
|
||||||
Which function gives better results, ``sqrt`` or ``mysqrt``?
|
.. code-block:: console
|
||||||
|
|
||||||
|
cmake --build .
|
||||||
|
|
||||||
|
Then, run the executable again to ensure that it still works with
|
||||||
|
``USE_MYMATH`` set to ``OFF``. Which function gives better results, ``sqrt``
|
||||||
|
or ``mysqrt``?
|
||||||
|
|
||||||
|
Solution
|
||||||
|
--------
|
||||||
|
|
||||||
|
The first step is to add an option to the top-level ``CMakeLists.txt`` file.
|
||||||
|
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.
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
<details><summary>TODO 7: Click to show/hide answer</summary>
|
||||||
|
|
||||||
|
.. literalinclude:: Step3/CMakeLists.txt
|
||||||
|
:caption: TODO 7: CMakeLists.txt
|
||||||
|
:name: CMakeLists.txt-option
|
||||||
|
:language: cmake
|
||||||
|
:start-after: # should we use our own math functions
|
||||||
|
:end-before: # configure a header file to pass some of the CMake settings
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
Next, make building and linking the ``MathFunctions`` library
|
||||||
|
conditional.
|
||||||
|
|
||||||
|
Start by creating a :command:`list` of the optional library targets for our
|
||||||
|
project. At the moment, it is just ``MathFunctions``. Let's name our list
|
||||||
|
``EXTRA_LIBS``.
|
||||||
|
|
||||||
|
Similarly, we need to make a :command:`list` for the optional includes which
|
||||||
|
we will call ``EXTRA_INCLUDES``. In this list, we will ``APPEND`` the path of
|
||||||
|
the header file needed for our library.
|
||||||
|
|
||||||
|
Next, create an :command:`if` statement which checks the value of
|
||||||
|
``USE_MYMATH``. Inside the :command:`if` block, put the
|
||||||
|
:command:`add_subdirectory` command from Exercise 1 with the additional
|
||||||
|
:command:`list` commands.
|
||||||
|
|
||||||
|
When ``MY_MATH`` is ``ON``, the lists will be generated and will be added to
|
||||||
|
our project. When ``MY_MATH`` is ``OFF``, the lists stay empty. With this
|
||||||
|
strategy, we allow users to toggle ``MY_MATH`` to manipulate what library is
|
||||||
|
used in the build.
|
||||||
|
|
||||||
|
The top-level CMakeLists.txt file will now look like the following:
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
<details><summary>TODO 8: Click to show/hide answer</summary>
|
||||||
|
|
||||||
|
.. literalinclude:: Step3/CMakeLists.txt
|
||||||
|
:caption: TODO 8: CMakeLists.txt
|
||||||
|
:name: CMakeLists.txt-USE_MYMATH
|
||||||
|
:language: cmake
|
||||||
|
:start-after: # add the MathFunctions library
|
||||||
|
:end-before: # add the executable
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
Now that we have these two lists, we need to update
|
||||||
|
:command:`target_link_libraries` and :command:`target_include_directories` to
|
||||||
|
use them. Changing them is fairly straightforward.
|
||||||
|
|
||||||
|
For :command:`target_link_libraries`, we replace the written out
|
||||||
|
library names with ``EXTRA_LIBS``. This looks like the following:
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
<details><summary>TODO 9: Click to show/hide answer</summary>
|
||||||
|
|
||||||
|
.. literalinclude:: Step3/CMakeLists.txt
|
||||||
|
:caption: TODO 9: CMakeLists.txt
|
||||||
|
:name: CMakeLists.txt-target_link_libraries-EXTRA_LIBS
|
||||||
|
:language: cmake
|
||||||
|
:start-after: add_executable(Tutorial tutorial.cxx)
|
||||||
|
:end-before: # add the binary tree to the search path for include files
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
Then, we do the same thing with :command:`target_include_directories` and
|
||||||
|
``EXTRA_INCLUDES``.
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
<details><summary>TODO 10: Click to show/hide answer</summary>
|
||||||
|
|
||||||
|
.. literalinclude:: Step3/CMakeLists.txt
|
||||||
|
:caption: TODO 10 : CMakeLists.txt
|
||||||
|
:name: CMakeLists.txt-target_link_libraries-EXTRA_INCLUDES
|
||||||
|
:language: cmake
|
||||||
|
:start-after: # so that we will find TutorialConfig.h
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
Note that this is a classic approach when dealing with many components. We
|
||||||
|
will cover the modern approach in the Step 3 of the tutorial.
|
||||||
|
|
||||||
|
The corresponding changes to the source code are fairly straightforward.
|
||||||
|
First, in ``tutorial.cxx``, we include the ``MathFunctions.h`` header if
|
||||||
|
``MY_MATH`` is defined.
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
<details><summary>TODO 11: Click to show/hide answer</summary>
|
||||||
|
|
||||||
|
.. literalinclude:: Step3/tutorial.cxx
|
||||||
|
:caption: TODO 11 : tutorial.cxx
|
||||||
|
:name: tutorial.cxx-ifdef-include
|
||||||
|
:language: c++
|
||||||
|
:start-after: // should we include the MathFunctions header
|
||||||
|
:end-before: int main
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
Then, in the same file, we make ``USE_MYMATH`` control which square root
|
||||||
|
function is used:
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
<details><summary>TODO 12: Click to show/hide answer</summary>
|
||||||
|
|
||||||
|
.. literalinclude:: Step3/tutorial.cxx
|
||||||
|
:caption: TODO 12 : 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
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
Since the source code now requires ``USE_MYMATH`` we can add it to
|
||||||
|
``TutorialConfig.h.in`` with the following line:
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
<details><summary>TODO 13: Click to show/hide answer</summary>
|
||||||
|
|
||||||
|
.. literalinclude:: Step3/TutorialConfig.h.in
|
||||||
|
:caption: TODO 13 : TutorialConfig.h.in
|
||||||
|
:name: TutorialConfig.h.in-cmakedefine
|
||||||
|
:language: c++
|
||||||
|
:lines: 4
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
With these changes, our library is now completely optional to whoever is
|
||||||
|
building and using it.
|
||||||
|
|
||||||
|
Bonus Question
|
||||||
|
--------------
|
||||||
|
|
||||||
|
Why is it important that we configure ``TutorialConfig.h.in``
|
||||||
|
after the option for ``USE_MYMATH``? What would happen if we inverted the two?
|
||||||
|
|
||||||
|
Answer
|
||||||
|
------
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
<details><summary>Click to show/hide answer</summary>
|
||||||
|
|
||||||
|
We configure after because ``TutorialConfig.h.in`` uses the value of
|
||||||
|
``USE_MYMATH``. If we configure the file before
|
||||||
|
calling :command:`option`, we won't be using the expected value of
|
||||||
|
``USE_MYMATH``.
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
</details>
|
||||||
|
@@ -7,13 +7,36 @@ project(Tutorial VERSION 1.0)
|
|||||||
set(CMAKE_CXX_STANDARD 11)
|
set(CMAKE_CXX_STANDARD 11)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
||||||
|
|
||||||
|
# TODO 7: Create a variable MY_MATH using option and set default to ON
|
||||||
|
|
||||||
# configure a header file to pass some of the CMake settings
|
# configure a header file to pass some of the CMake settings
|
||||||
# to the source code
|
# to the source code
|
||||||
configure_file(TutorialConfig.h.in TutorialConfig.h)
|
configure_file(TutorialConfig.h.in TutorialConfig.h)
|
||||||
|
|
||||||
|
# TODO 8: Use list() and APPEND to create a list of optional libraries
|
||||||
|
# called EXTRA_LIBS and a list of optional include directories called
|
||||||
|
# EXTRA_INCLUDES. Add the MathFunctions library and source directory to
|
||||||
|
# the appropriate lists.
|
||||||
|
#
|
||||||
|
# Only call add_subdirectory and only add MathFunctions specific values
|
||||||
|
# to EXTRA_LIBS and EXTRA_INCLUDES if USE_MYMATH is true.
|
||||||
|
|
||||||
|
# TODO 2: Use add_subdirectory() to add MathFunctions to this project
|
||||||
|
|
||||||
# add the executable
|
# add the executable
|
||||||
add_executable(Tutorial tutorial.cxx)
|
add_executable(Tutorial tutorial.cxx)
|
||||||
|
|
||||||
|
# TODO 9: Use EXTRA_LIBS instead of the MathFunctions specific values
|
||||||
|
# in target_link_libraries.
|
||||||
|
|
||||||
|
# TODO 3: Use target_link_libraries to link the library to our executable
|
||||||
|
|
||||||
|
# TODO 4: Add MathFunctions to Tutorial's target_include_directories()
|
||||||
|
# Hint: ${PROJECT_SOURCE_DIR} is a path to the project source. AKA This folder!
|
||||||
|
|
||||||
|
# TODO 10: Use EXTRA_INCLUDES instead of the MathFunctions specific values
|
||||||
|
# in target_include_directories.
|
||||||
|
|
||||||
# add the binary tree to the search path for include files
|
# add the binary tree to the search path for include files
|
||||||
# so that we will find TutorialConfig.h
|
# so that we will find TutorialConfig.h
|
||||||
target_include_directories(Tutorial PUBLIC
|
target_include_directories(Tutorial PUBLIC
|
||||||
|
2
Help/guide/tutorial/Step2/MathFunctions/CMakeLists.txt
Normal file
2
Help/guide/tutorial/Step2/MathFunctions/CMakeLists.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# TODO 1: Add a library called MathFunctions
|
||||||
|
# Hint: You will need the add_library command
|
@@ -1,3 +1,5 @@
|
|||||||
// the configured options and settings for Tutorial
|
// the configured options and settings for Tutorial
|
||||||
#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
|
#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
|
||||||
#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@
|
#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@
|
||||||
|
|
||||||
|
// TODO 13: use cmakedefine to define MY_MATH
|
||||||
|
@@ -5,6 +5,10 @@
|
|||||||
|
|
||||||
#include "TutorialConfig.h"
|
#include "TutorialConfig.h"
|
||||||
|
|
||||||
|
// TODO 11: Only include MathFunctions if MY_MATH is defined
|
||||||
|
|
||||||
|
// TODO 5: Include MathFunctions.h
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
@@ -18,6 +22,10 @@ int main(int argc, char* argv[])
|
|||||||
// convert input to double
|
// convert input to double
|
||||||
const double inputValue = std::stod(argv[1]);
|
const double inputValue = std::stod(argv[1]);
|
||||||
|
|
||||||
|
// TODO 12: Use mysqrt if MY_MATH is defined and sqrt otherwise
|
||||||
|
|
||||||
|
// TODO 6: Replace sqrt with mysqrt
|
||||||
|
|
||||||
// calculate square root
|
// calculate square root
|
||||||
const double outputValue = sqrt(inputValue);
|
const double outputValue = sqrt(inputValue);
|
||||||
std::cout << "The square root of " << inputValue << " is " << outputValue
|
std::cout << "The square root of " << inputValue << " is " << outputValue
|
||||||
|
Reference in New Issue
Block a user