summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Help/guide/tutorial/A Basic Starting Point.rst11
-rw-r--r--Help/guide/tutorial/Adding a Library.rst463
-rw-r--r--Help/guide/tutorial/Step2/CMakeLists.txt23
-rw-r--r--Help/guide/tutorial/Step2/MathFunctions/CMakeLists.txt2
-rw-r--r--Help/guide/tutorial/Step2/TutorialConfig.h.in2
-rw-r--r--Help/guide/tutorial/Step2/tutorial.cxx8
6 files changed, 433 insertions, 76 deletions
diff --git a/Help/guide/tutorial/A Basic Starting Point.rst b/Help/guide/tutorial/A Basic Starting Point.rst
index 69f6748..3dac68a 100644
--- a/Help/guide/tutorial/A Basic Starting Point.rst
+++ b/Help/guide/tutorial/A Basic Starting Point.rst
@@ -160,7 +160,7 @@ The last command to call for a basic project is
:name: CMakeLists.txt-add_executable
:language: cmake
:start-after: # add the executable
- :end-before: # add the binary tree to the search path for include files
+ :end-before: # TODO 9:
.. raw:: html
@@ -240,7 +240,7 @@ the following:
:name: tutorial.cxx-cxx11
:language: c++
:start-after: // convert input to double
- :end-before: // calculate square root
+ :end-before: // TODO 12:
.. raw:: html
@@ -265,7 +265,7 @@ add the :variable:`CMAKE_CXX_STANDARD` declarations above the call to
:name: CMakeLists.txt-CXX_STANDARD
:language: cmake
: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
@@ -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
: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.
.. raw:: html
@@ -375,7 +375,7 @@ specified CMake variables replaced:
:name: CMakeLists.txt-configure_file
:language: cmake
:start-after: # to the source code
- :end-before: # add the executable
+ :end-before: # TODO 8:
.. raw:: html
@@ -420,6 +420,7 @@ be replaced with the corresponding version numbers from the project in
:caption: TODO 10: TutorialConfig.h.in
:name: TutorialConfig.h.in
:language: c++
+ :end-before: // TODO 13:
.. raw:: html
diff --git a/Help/guide/tutorial/Adding a Library.rst b/Help/guide/tutorial/Adding a Library.rst
index 71755be..9b81894 100644
--- a/Help/guide/tutorial/Adding a Library.rst
+++ b/Help/guide/tutorial/Adding a Library.rst
@@ -1,136 +1,457 @@
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
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.
+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``. We will not need to
+modify either of these files. The source file has one function called
+``mysqrt`` that provides similar functionality to the compiler's ``sqrt``
+function.
+
+From the ``Help/guide/tutorial/Step2`` directory, start with ``TODO 1`` and
+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:
-Add the following one line ``CMakeLists.txt`` file to the ``MathFunctions``
-directory:
+.. raw:: html
+
+ <details><summary>TODO 1: Click to show/hide answer</summary>
.. literalinclude:: Step3/MathFunctions/CMakeLists.txt
- :caption: MathFunctions/CMakeLists.txt
- :name: MathFunctions/CMakeLists.txt
+ :caption: TODO 1: MathFunctions/CMakeLists.txt
+ :name: MathFunctions/CMakeLists.txt-add_library
:language: cmake
+.. raw:: html
+
+ </details>
+
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:
+built.
+
+.. raw:: html
+
+ <details><summary>TODO 2: Click to show/hide answer</summary>
+
+.. code-block:: cmake
+ :caption: TODO 2: CMakeLists.txt
+ :name: CMakeLists.txt-add_subdirectory
+
+ add_subdirectory(MathFunctions)
+
+.. raw:: html
+
+ </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)
+
+.. raw:: html
+
+ </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: CMakeLists.txt
- :name: CMakeLists.txt-add_subdirectory
+ :caption: TODO 4: CMakeLists.txt
+ :name: CMakeLists.txt-target_include_directories-step2
+
+ target_include_directories(Tutorial PUBLIC
+ "${PROJECT_BINARY_DIR}"
+ "${PROJECT_SOURCE_DIR}/MathFunctions"
+ )
+
+.. 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>
- # add the MathFunctions library
- add_subdirectory(MathFunctions)
+.. code-block:: c++
+ :caption: TODO 5 : tutorial.cxx
+ :name: tutorial.cxx-include_MathFunctions.h
- # add the executable
- add_executable(Tutorial tutorial.cxx)
+ #include "MathFunctions.h"
- target_link_libraries(Tutorial PUBLIC MathFunctions)
+.. raw:: html
- # 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"
- )
+ </details>
-Now let us make the ``MathFunctions`` library optional. While for the tutorial
+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
-occurrence. The first step is to add an option to the top-level
-``CMakeLists.txt`` file.
+occurrence.
+
+CMake can do this using the :command:`option` command. This gives users a
+variable which they can change when configuring their cmake build. 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.
+
+Goal
+----
+
+Add the option to build without ``MathFunctions``.
+
+
+Helpful Resources
+-----------------
+
+* :command:`if`
+* :command:`list`
+* :command:`option`
+* :command:`cmakedefine <configure_file>`
+
+Files to Edit
+-------------
+
+* ``CMakeLists.txt``
+* ``tutorial.cxx``
+* ``TutorialConfig.h.in``
+
+Getting Started
+---------------
+
+Start with the resulting files from Exercise 1. Complete ``TODO 7`` through
+``TODO 13``.
+
+First create a variable ``MY_MATH`` using the :command:`option` command
+in the top-level ``CMakeLists.txt`` file. In that same file, use that option
+to determine whether to build and use the ``MathFunctions`` library.
+
+Then, update ``tutorial.cxx`` and ``TutorialConfig.h.in`` to use ``MY_MATH``.
+
+Build and Run
+-------------
+
+Since we have our build directory already configured from Exercise 1, we can
+rebuild by simply calling the following:
+
+.. 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
+
+ cmake ../Step2 -DUSE_MYMATH=OFF
+
+Now, rebuild the code with the following:
+
+.. 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: CMakeLists.txt
+ :caption: TODO 7: CMakeLists.txt
:name: CMakeLists.txt-option
:language: cmake
:start-after: # should we use our own math functions
- :end-before: # add the MathFunctions library
+ :end-before: # configure a header file to pass some of the CMake settings
-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:
+.. 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: CMakeLists.txt
- :name: CMakeLists.txt-target_link_libraries-EXTRA_LIBS
+ :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>
-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.
+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``, include the ``MathFunctions.h`` header if we
-need it:
+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: 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
-Then, in the same file, make ``USE_MYMATH`` control which square root
+.. 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: 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: TutorialConfig.h.in
+ :caption: TODO 13 : TutorialConfig.h.in
:name: TutorialConfig.h.in-cmakedefine
:language: c++
:lines: 4
-**Exercise**: Why is it important that we configure ``TutorialConfig.h.in``
+.. 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?
-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.
+Answer
+------
-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:
+.. raw:: html
-.. code-block:: console
+ <details><summary>Click to show/hide answer</summary>
- cmake ../Step2 -DUSE_MYMATH=OFF
+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``.
-Rebuild and run the tutorial again.
+.. raw:: html
-Which function gives better results, ``sqrt`` or ``mysqrt``?
+ </details>
diff --git a/Help/guide/tutorial/Step2/CMakeLists.txt b/Help/guide/tutorial/Step2/CMakeLists.txt
index 7aa59e9..2f7d56e 100644
--- a/Help/guide/tutorial/Step2/CMakeLists.txt
+++ b/Help/guide/tutorial/Step2/CMakeLists.txt
@@ -7,13 +7,36 @@ project(Tutorial VERSION 1.0)
set(CMAKE_CXX_STANDARD 11)
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
# to the source code
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_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
# so that we will find TutorialConfig.h
target_include_directories(Tutorial PUBLIC
diff --git a/Help/guide/tutorial/Step2/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step2/MathFunctions/CMakeLists.txt
new file mode 100644
index 0000000..b7779b7
--- /dev/null
+++ b/Help/guide/tutorial/Step2/MathFunctions/CMakeLists.txt
@@ -0,0 +1,2 @@
+# TODO 1: Add a library called MathFunctions
+# Hint: You will need the add_library command
diff --git a/Help/guide/tutorial/Step2/TutorialConfig.h.in b/Help/guide/tutorial/Step2/TutorialConfig.h.in
index 7e4d7fa..adb4c55 100644
--- a/Help/guide/tutorial/Step2/TutorialConfig.h.in
+++ b/Help/guide/tutorial/Step2/TutorialConfig.h.in
@@ -1,3 +1,5 @@
// the configured options and settings for Tutorial
#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@
+
+// TODO 13: use cmakedefine to define MY_MATH
diff --git a/Help/guide/tutorial/Step2/tutorial.cxx b/Help/guide/tutorial/Step2/tutorial.cxx
index 53b0810..f83aa7e 100644
--- a/Help/guide/tutorial/Step2/tutorial.cxx
+++ b/Help/guide/tutorial/Step2/tutorial.cxx
@@ -5,6 +5,10 @@
#include "TutorialConfig.h"
+// TODO 11: Only include MathFunctions if MY_MATH is defined
+
+// TODO 5: Include MathFunctions.h
+
int main(int argc, char* argv[])
{
if (argc < 2) {
@@ -18,6 +22,10 @@ int main(int argc, char* argv[])
// convert input to double
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
const double outputValue = sqrt(inputValue);
std::cout << "The square root of " << inputValue << " is " << outputValue