diff options
Diffstat (limited to 'Help/guide/tutorial/Adding a Library.rst')
-rw-r--r-- | Help/guide/tutorial/Adding a Library.rst | 241 |
1 files changed, 118 insertions, 123 deletions
diff --git a/Help/guide/tutorial/Adding a Library.rst b/Help/guide/tutorial/Adding a Library.rst index a56c327..d606f30 100644 --- a/Help/guide/tutorial/Adding a Library.rst +++ b/Help/guide/tutorial/Adding a Library.rst @@ -51,11 +51,13 @@ 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``. We will not need to -modify either of these files. The source file has one function 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. +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``. @@ -91,18 +93,18 @@ 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 +source files for the library are passed as an argument to :command:`add_library`. This looks like the following line: -.. raw:: html +.. raw:: html/ <details><summary>TODO 1: Click to show/hide answer</summary> -.. literalinclude:: Step3/MathFunctions/CMakeLists.txt +.. code-block:: cmake :caption: TODO 1: MathFunctions/CMakeLists.txt :name: MathFunctions/CMakeLists.txt-add_library - :language: cmake - :end-before: # TODO 1 + + add_library(MathFunctions MathFunctions.cxx mysqrt.cxx) .. raw:: html @@ -171,36 +173,40 @@ Now let's use our library. In ``tutorial.cxx``, include ``MathFunctions.h``: <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" +.. 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 ``mysqrt``. +Lastly, replace ``sqrt`` with our library function ``mathfunctions::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); +.. literalinclude:: Step3/tutorial.cxx + :caption: TODO 6: 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 - Making Our Library Optional -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Exercise 2 - Adding an Option +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Now let us make the MathFunctions library optional. While for the tutorial +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. @@ -219,30 +225,32 @@ Helpful Resources ----------------- * :command:`if` -* :command:`list` * :command:`option` -* :command:`cmakedefine <configure_file>` +* :command:`target_compile_definitions` Files to Edit ------------- -* ``CMakeLists.txt`` -* ``tutorial.cxx`` -* ``TutorialConfig.h.in`` +* ``MathFunctions/CMakeLists.txt`` +* ``MathFunctions/MathFunctions.cxx`` Getting Started --------------- Start with the resulting files from Exercise 1. Complete ``TODO 7`` through -``TODO 13``. +``TODO 14``. First create a variable ``USE_MYMATH`` 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. +in ``MathFunctions/CMakeLists.txt``. In that same file, use that option +to pass a compile definition to the ``MathFunctions`` library. -Then, update ``tutorial.cxx`` and ``TutorialConfig.h.in`` to use +Then, update ``MathFunctions.cxx`` to redirect compilation based on ``USE_MYMATH``. +Lastly, prevent ``mysqrt.cxx`` from being compiled when ``USE_MYMATH`` is on +by making it its own library inside of the ``USE_MYMATH`` block of +``MathFunctions/CMakeLists.txt``. + Build and Run ------------- @@ -279,7 +287,7 @@ or ``mysqrt``? Solution -------- -The first step is to add an option to the top-level ``CMakeLists.txt`` file. +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. @@ -288,172 +296,159 @@ changed by the user. <details><summary>TODO 7: Click to show/hide answer</summary> -.. literalinclude:: Step3/CMakeLists.txt - :caption: TODO 7: CMakeLists.txt - :name: CMakeLists.txt-option +.. 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: # configure a header file to pass some of the CMake settings + :end-before: if (USE_MYMATH) .. 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``. +Next, make building and linking our library with ``mysqrt`` function +conditional using this new option. -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 +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 ``USE_MYMATH`` is ``ON``, the lists will be generated and will be added to -our project. When ``USE_MYMATH`` is ``OFF``, the lists stay empty. With this -strategy, we allow users to toggle ``USE_MYMATH`` to manipulate what library is -used in the build. - -The top-level CMakeLists.txt file will now look like the following: +: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/CMakeLists.txt - :caption: TODO 8: CMakeLists.txt +.. code-block:: cmake + :caption: TODO 8: MathFunctions/CMakeLists.txt :name: CMakeLists.txt-USE_MYMATH - :language: cmake - :start-after: # add the MathFunctions library - :end-before: # add the executable + + if (USE_MYMATH) + target_compile_definitions(MathFunctions PRIVATE "USE_MYMATH") + endif() .. 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. +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. -For :command:`target_link_libraries`, we replace the written out -library names with ``EXTRA_LIBS``. This looks like the following: +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/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: # TODO 3 +.. 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> -Then, we do the same thing with :command:`target_include_directories` and -``EXTRA_INCLUDES``. +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/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 +.. 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> -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 -``USE_MYMATH`` is defined. +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> -.. 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 +.. code-block:: c++ + :caption: TODO 11 : MathFunctions/MathFunctions.cxx + :name: tutorial.cxx-include_cmath + + #include <cmath> .. raw:: html </details> -Then, in the same file, we make ``USE_MYMATH`` control which square root -function is used: +At this point, if ``USE_MYMATH`` is ``OFF``, ``mysqrt.cxx`` would not be used +but it will still be compiled because the ``MathFunctions`` target has +``mysqrt.cxx`` listed under sources. + +There are a few ways to fix this. The first option is to use +:command:`target_sources` to add ``mysqrt.cxx`` from within the ``USE_MYMATH`` +block. Another option is to create an additional library within the +``USE_MYMATH`` block which is responsible for compiling ``mysqrt.cxx``. For +the sake of this tutorial, we are going to create an additional library. + +First, from within ``USE_MYMATH`` create a library called ``SqrtLibrary`` +that has sources ``mysqrt.cxx``. .. 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 +.. literalinclude:: Step3/MathFunctions/CMakeLists.txt + :caption: TODO 12 : MathFunctions/CMakeLists.txt + :name: MathFunctions/CMakeLists.txt-add_library-SqrtLibrary + :language: cmake + :start-after: # library that just does sqrt + :end-before: target_link_libraries(MathFunctions .. raw:: html </details> -Since the source code now requires ``USE_MYMATH`` we can add it to -``TutorialConfig.h.in`` with the following line: +Next, we link ``SqrtLibrary`` onto ``MathFunctions`` when ``USE_MYMATH`` is +enabled. .. 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 +.. literalinclude:: Step3/MathFunctions/CMakeLists.txt + :caption: TODO 13 : MathFunctions/CMakeLists.txt + :name: MathFunctions/CMakeLists.txt-target_link_libraries-SqrtLibrary + :language: cmake + :lines: 16-18 .. 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 ------- +Finally, we can remove ``mysqrt.cxx`` from our ``MathFunctions`` library +source list because it will be pulled in when ``SqrtLibrary`` is included. .. raw:: html - <details><summary>Click to show/hide answer</summary> + <details><summary>TODO 14: 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``. +.. literalinclude:: Step3/MathFunctions/CMakeLists.txt + :caption: TODO 14 : MathFunctions/CMakeLists.txt + :name: MathFunctions/CMakeLists.txt-remove-mysqrt.cxx-MathFunctions + :language: cmake + :end-before: # TODO 1: .. raw:: html </details> + +With these changes, the ``mysqrt`` function is now completely optional to +whoever is building and using the ``MathFunctions`` library. Users can toggle +``USE_MYMATH`` to manipulate what library is used in the build. |