# 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.

If the platform has log and exp then we will use them to compute the square
root in the mysqrt function. We first test for the availability of these
functions using the CheckSymbolExists.cmake macro in the top-level CMakeLists
file as follows:

  # does this system provide the log and exp functions?
  include(CheckSymbolExists)
  set(CMAKE_REQUIRED_LIBRARIES "m")
  check_symbol_exists(log "math.h" HAVE_LOG)
  check_symbol_exists(exp "math.h" HAVE_EXP)

Now let's add these defines to TutorialConfig.h.in so that we can use them
from mysqrt.cxx:

  // does the platform provide exp and log functions?
  #cmakedefine HAVE_LOG
  #cmakedefine HAVE_EXP

Modify mysqrt.cxx to include math.h. Next, in the mysqrt function we can
provide an alternate implementation based on log and exp if they are available
on the system using the following code:

  // if we have both log and exp then use them
  #if defined(HAVE_LOG) && defined (HAVE_EXP)
    double result = exp(log(x)*0.5);
    std::cout << "Computing sqrt of " << x << " to be " << result << " using log" << std::endl;
  #else
    ...

Run cmake or cmake-gui to configure the project and then build it with your
chosen build tool.

You will notice that even though HAVE_LOG and HAVE_EXP are both defined mysqrt
isn't using them. We should realize quickly that we have forgotten to include
TutorialConfig.h in mysqrt.cxx. We will also need to update
MathFunctions/CMakeLists.txt with where it is located.

So let's go ahead and update MathFunctions/CMakeLists.txt to look like:

  add_library(MathFunctions mysqrt.cxx)

  target_include_directories(MathFunctions
            INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
            PRIVATE ${Tutorial_BINARY_DIR}
            )

  install(TARGETS MathFunctions DESTINATION lib)
  install(FILES MathFunctions.h DESTINATION include)

Now all we need to do is include TutorialConfig.h in mysqrt.cxx

At this point you should go ahead and build the project again.

Run the built Tutorial executable. Which function gives better results now,
Step1’s sqrt or Step5’s mysqrt?

Exercise: Why is it important that we configure TutorialConfig.h.in after the
checks for HAVE_LOG and HAVE_EXP? What would happen if we inverted the two?

Exercise: Is there a better place for us to save the HAVE_LOG and HAVE_EXP
values other than in TutorialConfig.h?
