summaryrefslogtreecommitdiffstats
path: root/Help/guide/tutorial/Adding a Library.rst
diff options
context:
space:
mode:
Diffstat (limited to 'Help/guide/tutorial/Adding a Library.rst')
-rw-r--r--Help/guide/tutorial/Adding a Library.rst386
1 files changed, 386 insertions, 0 deletions
diff --git a/Help/guide/tutorial/Adding a Library.rst b/Help/guide/tutorial/Adding a Library.rst
new file mode 100644
index 0000000..2dd731f
--- /dev/null
+++ b/Help/guide/tutorial/Adding a Library.rst
@@ -0,0 +1,386 @@
+Step 2: Adding a Library
+========================
+
+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 the header files
+``MathFunctions.h`` and ``mysqrt.h``. Their respective source files
+``MathFunctions.cxx`` and ``mysqrt.cxx`` are also provided. We will not need
+to modify any of these files. ``mysqrt.cxx`` has one function called
+``mysqrt`` that provides similar functionality to the compiler's ``sqrt``
+function. ``MathFunctions.cxx`` contains one function ``sqrt`` which serves
+to hide the implementation details of ``sqrt``.
+
+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 files for the library are 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
+ :caption: TODO 1: MathFunctions/CMakeLists.txt
+ :name: MathFunctions/CMakeLists.txt-add_library
+ :language: cmake
+ :end-before: # TODO 1
+
+.. 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.
+
+.. 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: 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>
+
+.. literalinclude:: Step3/tutorial.cxx
+ :caption: TODO 5: tutorial.cxx
+ :name: CMakeLists.txt-include-MathFunctions.h
+ :language: cmake
+ :start-after: #include <string>
+ :end-before: #include "TutorialConfig.h"
+
+.. raw:: html
+
+ </details>
+
+Lastly, replace ``sqrt`` with our library function ``mathfunctions::mysqrt``.
+
+.. raw:: html
+
+ <details><summary>TODO 6: Click to show/hide answer</summary>
+
+.. literalinclude:: Step3/tutorial.cxx
+ :caption: TODO 7: tutorial.cxx
+ :name: CMakeLists.txt-option
+ :language: cmake
+ :start-after: const double inputValue = std::stod(argv[1]);
+ :end-before: std::cout
+
+.. raw:: html
+
+ </details>
+
+Exercise 2 - Adding an Option
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Now let us add an option in the MathFunctions library to allow developers to
+select either the custom square root implementation or the built in standard
+implementation. While for the tutorial
+there really isn't any need to do so, for larger projects this is a common
+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:`option`
+* :command:`target_compile_definitions`
+
+Files to Edit
+-------------
+
+* ``MathFunctions/CMakeLists.txt``
+* ``MathFunctions/MathFunctions.cxx``
+
+Getting Started
+---------------
+
+Start with the resulting files from Exercise 1. Complete ``TODO 7`` through
+``TODO 9``.
+
+First create a variable ``USE_MYMATH`` using the :command:`option` command
+in ``MathFunctions/CMakeLists.txt``. In that same file, use that option
+to pass a compile definition to the ``MathFunctions`` library.
+
+Then, update ``MathFunctions.cxx`` to redirect compilation based on
+``USE_MYMATH``.
+
+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 ``MathFunctions/CMakeLists.txt``.
+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/MathFunctions/CMakeLists.txt
+ :caption: TODO 7: MathFunctions/CMakeLists.txt
+ :name: CMakeLists.txt-option-library-level
+ :language: cmake
+ :start-after: # should we use our own math functions
+ :end-before: if (USE_MYMATH)
+
+.. raw:: html
+
+ </details>
+
+Next, make building and linking our library with ``mysqrt`` function
+conditional using this new option.
+
+Create an :command:`if` statement which checks the value of
+``USE_MYMATH``. Inside the :command:`if` block, put the
+:command:`target_compile_definitions` command with the compile
+definition ``USE_MYMATH``.
+
+.. raw:: html
+
+ <details><summary>TODO 8: Click to show/hide answer</summary>
+
+.. literalinclude:: Step3/MathFunctions/CMakeLists.txt
+ :caption: TODO 8: MathFunctions/CMakeLists.txt
+ :name: CMakeLists.txt-USE_MYMATH
+ :language: cmake
+ :start-after: USE_MYMATH "Use tutorial provided math implementation" ON)
+
+.. raw:: html
+
+ </details>
+
+The corresponding changes to the source code are fairly straightforward.
+In ``MathFunctions.cxx``, we make ``USE_MYMATH`` control which square root
+function is used:
+
+.. raw:: html
+
+ <details><summary>TODO 9: Click to show/hide answer</summary>
+
+.. literalinclude:: Step3/MathFunctions/MathFunctions.cxx
+ :caption: TODO 9: MathFunctions/MathFunctions.cxx
+ :name: MathFunctions-USE_MYMATH-if
+ :language: c++
+ :start-after: which square root function should we use?
+ :end-before: }
+
+.. raw:: html
+
+ </details>
+
+Next, we need to include ``mysqrt.h`` if ``USE_MYMATH`` is defined.
+
+.. raw:: html
+
+ <details><summary>TODO 10: Click to show/hide answer</summary>
+
+.. literalinclude:: Step3/MathFunctions/MathFunctions.cxx
+ :caption: TODO 10: MathFunctions/MathFunctions.cxx
+ :name: MathFunctions-USE_MYMATH-if-include
+ :language: c++
+ :start-after: include <cmath>
+ :end-before: namespace mathfunctions
+
+.. raw:: html
+
+ </details>
+
+Finally, we need to include ``cmath`` now that we are using ``std::sqrt``.
+
+.. raw:: html
+
+ <details><summary>TODO 11: Click to show/hide answer</summary>
+
+.. code-block:: c++
+ :caption: TODO 11 : MathFunctions/MathFunctions.cxx
+ :name: tutorial.cxx-include_cmath
+
+ #include <cmath>
+
+.. raw:: html
+
+ </details>
+
+When ``USE_MYMATH`` is ``ON``, the compile definition ``USE_MYMATH`` will
+be set. We can then use this compile definition to enable or disable
+sections of our source code. With this strategy, we allow users to
+toggle ``USE_MYMATH`` to manipulate what library is used in the build.
+
+With these changes, the ``mysqrt`` function is now completely optional to
+whoever is building and using the ``MathFunctions`` library.