| Step 7: Adding System Introspection | |
| =================================== | |
| Let us consider adding some code to our project that depends on features the | |
| target platform may not have. For this example, we will add some code that | |
| depends on whether or not the target platform has the ``log`` and ``exp`` | |
| functions. Of course almost every platform has these functions but for this | |
| tutorial assume that they are not common. | |
| Exercise 1 - Assessing Dependency Availability | |
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| Goal | |
| ---- | |
| Change implementation based on available system dependencies. | |
| Helpful Resources | |
| ----------------- | |
| * :module:`CheckCXXSourceCompiles` | |
| * :command:`target_compile_definitions` | |
| Files to Edit | |
| ------------- | |
| * ``MathFunctions/CMakeLists.txt`` | |
| * ``MathFunctions/mysqrt.cxx`` | |
| Getting Started | |
| --------------- | |
| The starting source code is provided in the ``Step7`` directory. In this | |
| exercise, complete ``TODO 1`` through ``TODO 5``. | |
| Start by editing ``MathFunctions/CMakeLists.txt``. Include the | |
| :module:`CheckCXXSourceCompiles` module. Then, use | |
| ``check_cxx_source_compiles`` to determine whether ``log`` and ``exp`` are | |
| available from ``cmath``. If they are available, use | |
| :command:`target_compile_definitions` to specify ``HAVE_LOG`` and ``HAVE_EXP`` | |
| as compile definitions. | |
| In the ``MathFunctions/mysqrt.cxx``, include ``cmath``. Then, if the system has | |
| ``log`` and ``exp``, use them to compute the square root. | |
| Build and Run | |
| ------------- | |
| Make a new directory called ``Step7_build``. 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 and run the ``Tutorial`` executable. | |
| This can look like the following: | |
| .. code-block:: console | |
| mkdir Step7_build | |
| cd Step7_build | |
| cmake ../Step7 | |
| cmake --build . | |
| Which function gives better results now, ``sqrt`` or ``mysqrt``? | |
| Solution | |
| -------- | |
| In this exercise we will use functions from the | |
| :module:`CheckCXXSourceCompiles` module so first we must include it in | |
| ``MathFunctions/CMakeLists.txt``. | |
| .. raw:: html | |
| <details><summary>TODO 1: Click to show/hide answer</summary> | |
| .. literalinclude:: Step8/MathFunctions/CMakeLists.txt | |
| :caption: TODO 1: MathFunctions/CMakeLists.txt | |
| :name: MathFunctions/CMakeLists.txt-include-check_cxx_source_compiles | |
| :language: cmake | |
| :start-after: # does this system provide the log and exp functions? | |
| :end-before: check_cxx_source_compiles | |
| .. raw:: html | |
| </details> | |
| Then test for the availability of | |
| ``log`` and ``exp`` using ``check_cxx_compiles_source``. This function | |
| lets us try compiling simple code with the required dependency prior to | |
| the true source code compilation. The resulting variables ``HAVE_LOG`` | |
| and ``HAVE_EXP`` represent whether those dependencies are available. | |
| .. raw:: html | |
| <details><summary>TODO 2: Click to show/hide answer</summary> | |
| .. literalinclude:: Step8/MathFunctions/CMakeLists.txt | |
| :caption: TODO 2: MathFunctions/CMakeLists.txt | |
| :name: MathFunctions/CMakeLists.txt-check_cxx_source_compiles | |
| :language: cmake | |
| :start-after: include(CheckCXXSourceCompiles) | |
| :end-before: # add compile definitions | |
| .. raw:: html | |
| </details> | |
| Next, we need to pass these CMake variables to our source code. This way, | |
| our source code can tell what resources are available. If both ``log`` and | |
| ``exp`` are available, use :command:`target_compile_definitions` to specify | |
| ``HAVE_LOG`` and ``HAVE_EXP`` as ``PRIVATE`` compile definitions. | |
| .. raw:: html | |
| <details><summary>TODO 3: Click to show/hide answer</summary> | |
| .. literalinclude:: Step8/MathFunctions/CMakeLists.txt | |
| :caption: TODO 3: MathFunctions/CMakeLists.txt | |
| :name: MathFunctions/CMakeLists.txt-target_compile_definitions | |
| :language: cmake | |
| :start-after: # add compile definitions | |
| :end-before: # state | |
| .. raw:: html | |
| </details> | |
| Since we may be using ``log`` and ``exp``, we need to modify | |
| ``mysqrt.cxx`` to include ``cmath``. | |
| .. raw:: html | |
| <details><summary>TODO 4: Click to show/hide answer</summary> | |
| .. literalinclude:: Step8/MathFunctions/mysqrt.cxx | |
| :caption: TODO 4: MathFunctions/mysqrt.cxx | |
| :name: MathFunctions/mysqrt.cxx-include-cmath | |
| :language: c++ | |
| :start-after: #include "mysqrt.h" | |
| :end-before: include <iostream> | |
| .. raw:: html | |
| </details> | |
| If ``log`` and ``exp`` are available on the system, then use them to | |
| compute the square root in the ``mysqrt`` function. The ``mysqrt`` function in | |
| ``MathFunctions/mysqrt.cxx`` will look as follows: | |
| .. raw:: html | |
| <details><summary>TODO 5: Click to show/hide answer</summary> | |
| .. literalinclude:: Step8/MathFunctions/mysqrt.cxx | |
| :caption: TODO 5: MathFunctions/mysqrt.cxx | |
| :name: MathFunctions/mysqrt.cxx-ifdef | |
| :language: c++ | |
| :start-after: // if we have both log and exp then use them | |
| :end-before: return result; | |
| .. raw:: html | |
| </details> |