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¶
Files to Edit¶
MathFunctions/CMakeLists.txtMathFunctions/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
CheckCXXSourceCompiles module. Then, use
check_cxx_source_compiles to determine whether log and exp are
available from cmath. If they are available, use
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
cmake executable or the
cmake-gui to configure the project and then build it
with your chosen build tool and run the Tutorial executable.
This can look like the following:
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
CheckCXXSourceCompiles module so first we must include it in
MathFunctions/CMakeLists.txt.
TODO 1: Click to show/hide answer
include(CheckCXXSourceCompiles)
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.
TODO 2: Click to show/hide answer
check_cxx_source_compiles("
#include <cmath>
int main() {
std::log(1.0);
return 0;
}
" HAVE_LOG)
check_cxx_source_compiles("
#include <cmath>
int main() {
std::exp(1.0);
return 0;
}
" HAVE_EXP)
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 target_compile_definitions() to specify
HAVE_LOG and HAVE_EXP as PRIVATE compile definitions.
TODO 3: Click to show/hide answer
if(HAVE_LOG AND HAVE_EXP)
target_compile_definitions(SqrtLibrary
PRIVATE "HAVE_LOG" "HAVE_EXP"
)
endif()
target_link_libraries(MathFunctions PRIVATE SqrtLibrary)
endif()
Since we may be using log and exp, we need to modify
mysqrt.cxx to include cmath.
TODO 4: Click to show/hide answer
#include <cmath>
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:
TODO 5: Click to show/hide answer
#if defined(HAVE_LOG) && defined(HAVE_EXP)
double result = std::exp(std::log(x) * 0.5);
std::cout << "Computing sqrt of " << x << " to be " << result
<< " using log and exp" << std::endl;
#else
double result = x;
// do ten iterations
for (int i = 0; i < 10; ++i) {
if (result <= 0) {
result = 0.1;
}
double delta = x - (result * result);
result = result + 0.5 * delta / result;
std::cout << "Computing sqrt of " << x << " to be " << result << std::endl;
}
#endif