diff options
author | Betsy McPhail <betsy.mcphail@kitware.com> | 2019-01-20 16:28:39 (GMT) |
---|---|---|
committer | Betsy McPhail <betsy.mcphail@kitware.com> | 2019-01-27 21:03:00 (GMT) |
commit | f2ddedfa5802c8aece994bb643b5139212d87777 (patch) | |
tree | f1dc800bf22bbfccbde4e1deb0c235986731e2cd /Tests/Tutorial/Step5 | |
parent | 438651506a5417be70e71f54f4ed7add0c2604d3 (diff) | |
download | CMake-f2ddedfa5802c8aece994bb643b5139212d87777.zip CMake-f2ddedfa5802c8aece994bb643b5139212d87777.tar.gz CMake-f2ddedfa5802c8aece994bb643b5139212d87777.tar.bz2 |
Tests: Update CMake tutorial
Latest material from data.kitware.com -> Collections -> Courses -> CMake.
Diffstat (limited to 'Tests/Tutorial/Step5')
-rw-r--r-- | Tests/Tutorial/Step5/CMakeLists.txt | 86 | ||||
-rw-r--r-- | Tests/Tutorial/Step5/MathFunctions/CMakeLists.txt | 23 | ||||
-rw-r--r-- | Tests/Tutorial/Step5/MathFunctions/MakeTable.cxx | 35 | ||||
-rw-r--r-- | Tests/Tutorial/Step5/MathFunctions/mysqrt.cxx | 27 | ||||
-rw-r--r-- | Tests/Tutorial/Step5/TutorialConfig.h.in | 4 | ||||
-rw-r--r-- | Tests/Tutorial/Step5/directions.txt | 69 | ||||
-rw-r--r-- | Tests/Tutorial/Step5/tutorial.cxx | 25 |
7 files changed, 150 insertions, 119 deletions
diff --git a/Tests/Tutorial/Step5/CMakeLists.txt b/Tests/Tutorial/Step5/CMakeLists.txt index e40b676..63e5410 100644 --- a/Tests/Tutorial/Step5/CMakeLists.txt +++ b/Tests/Tutorial/Step5/CMakeLists.txt @@ -1,72 +1,70 @@ -cmake_minimum_required (VERSION 2.6) -project (Tutorial) +cmake_minimum_required(VERSION 3.3) +project(Tutorial) -# The version number. -set (Tutorial_VERSION_MAJOR 1) -set (Tutorial_VERSION_MINOR 0) - -# does this system provide the log and exp functions? -include (${CMAKE_ROOT}/Modules/CheckFunctionExists.cmake) -check_function_exists (log HAVE_LOG) -check_function_exists (exp HAVE_EXP) +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED True) # should we use our own math functions option(USE_MYMATH "Use tutorial provided math implementation" ON) +# the version number. +set(Tutorial_VERSION_MAJOR 1) +set(Tutorial_VERSION_MINOR 0) + # configure a header file to pass some of the CMake settings # to the source code -configure_file ( +configure_file( "${PROJECT_SOURCE_DIR}/TutorialConfig.h.in" "${PROJECT_BINARY_DIR}/TutorialConfig.h" ) -# add the binary tree to the search path for include files -# so that we will find TutorialConfig.h -include_directories ("${PROJECT_BINARY_DIR}") - # add the MathFunctions library? -if (USE_MYMATH) - include_directories ("${PROJECT_SOURCE_DIR}/MathFunctions") - add_subdirectory (MathFunctions) - set (EXTRA_LIBS ${EXTRA_LIBS} MathFunctions) -endif () +if(USE_MYMATH) + add_subdirectory(MathFunctions) + list(APPEND EXTRA_LIBS MathFunctions) +endif() # add the executable -add_executable (Tutorial tutorial.cxx) -target_link_libraries (Tutorial ${EXTRA_LIBS}) +add_executable(Tutorial tutorial.cxx) +target_link_libraries(Tutorial PUBLIC ${EXTRA_LIBS}) + +# add the binary tree to the search path for include files +# so that we will find TutorialConfig.h +target_include_directories(Tutorial PUBLIC + "${PROJECT_BINARY_DIR}" + ) # add the install targets -install (TARGETS Tutorial DESTINATION bin) -install (FILES "${PROJECT_BINARY_DIR}/TutorialConfig.h" - DESTINATION include) +install(TARGETS Tutorial DESTINATION bin) +install(FILES "${PROJECT_BINARY_DIR}/TutorialConfig.h" + DESTINATION include + ) # enable testing -enable_testing () +enable_testing() # does the application run -add_test (TutorialRuns Tutorial 25) +add_test(NAME Runs COMMAND Tutorial 25) # does the usage message work? -add_test (TutorialUsage Tutorial) -set_tests_properties (TutorialUsage - PROPERTIES - PASS_REGULAR_EXPRESSION "Usage:.*number" +add_test(NAME Usage COMMAND Tutorial) +set_tests_properties(Usage + PROPERTIES PASS_REGULAR_EXPRESSION "Usage:.*number" ) -#define a macro to simplify adding tests -macro (do_test arg result) - add_test (TutorialComp${arg} Tutorial ${arg}) - set_tests_properties (TutorialComp${arg} +# define a function to simplify adding tests +function(do_test target arg result) + add_test(NAME Comp${arg} COMMAND ${target} ${arg}) + set_tests_properties(Comp${arg} PROPERTIES PASS_REGULAR_EXPRESSION ${result} ) -endmacro () +endfunction(do_test) # do a bunch of result based tests -do_test (4 "4 is 2") -do_test (9 "9 is 3") -do_test (5 "5 is 2.236") -do_test (7 "7 is 2.645") -do_test (25 "25 is 5") -do_test (-25 "-25 is 0") -do_test (0.0001 "0.0001 is 0.01") - +do_test(Tutorial 4 "4 is 2") +do_test(Tutorial 9 "9 is 3") +do_test(Tutorial 5 "5 is 2.236") +do_test(Tutorial 7 "7 is 2.645") +do_test(Tutorial 25 "25 is 5") +do_test(Tutorial -25 "-25 is [-nan|nan|0]") +do_test(Tutorial 0.0001 "0.0001 is 0.01") diff --git a/Tests/Tutorial/Step5/MathFunctions/CMakeLists.txt b/Tests/Tutorial/Step5/MathFunctions/CMakeLists.txt index 453a463..11cf412 100644 --- a/Tests/Tutorial/Step5/MathFunctions/CMakeLists.txt +++ b/Tests/Tutorial/Step5/MathFunctions/CMakeLists.txt @@ -1,17 +1,10 @@ -# first we add the executable that generates the table -# add the binary tree directory to the search path for include files -include_directories( ${CMAKE_CURRENT_BINARY_DIR} ) +add_library(MathFunctions mysqrt.cxx) -add_executable(MakeTable MakeTable.cxx ) -# add the command to generate the source code -add_custom_command ( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Table.h - COMMAND MakeTable ${CMAKE_CURRENT_BINARY_DIR}/Table.h - DEPENDS MakeTable - ) +# state that anybody linking to us needs to include the current source dir +# to find MathFunctions.h, while we don't. +target_include_directories(MathFunctions + INTERFACE ${CMAKE_CURRENT_SOURCE_DIR} + ) -# add the main library -add_library(MathFunctions mysqrt.cxx ${CMAKE_CURRENT_BINARY_DIR}/Table.h ) - -install (TARGETS MathFunctions DESTINATION bin) -install (FILES MathFunctions.h DESTINATION include) +install(TARGETS MathFunctions DESTINATION lib) +install(FILES MathFunctions.h DESTINATION include) diff --git a/Tests/Tutorial/Step5/MathFunctions/MakeTable.cxx b/Tests/Tutorial/Step5/MathFunctions/MakeTable.cxx index cebd50f..ee58556 100644 --- a/Tests/Tutorial/Step5/MathFunctions/MakeTable.cxx +++ b/Tests/Tutorial/Step5/MathFunctions/MakeTable.cxx @@ -1,32 +1,25 @@ // A simple program that builds a sqrt table -#include <math.h> -#include <stdio.h> +#include <cmath> +#include <fstream> +#include <iostream> int main(int argc, char* argv[]) { - int i; - double result; - // make sure we have enough arguments if (argc < 2) { return 1; } - // open the output file - FILE* fout = fopen(argv[1], "w"); - if (!fout) { - return 1; + std::ofstream fout(argv[1], std::ios_base::out); + const bool fileOpen = fout.is_open(); + if (fileOpen) { + fout << "double sqrtTable[] = {" << std::endl; + for (int i = 0; i < 10; ++i) { + fout << sqrt(static_cast<double>(i)) << "," << std::endl; + } + // close the table with a zero + fout << "0};" << std::endl; + fout.close(); } - - // create a source file with a table of square roots - fprintf(fout, "double sqrtTable[] = {\n"); - for (i = 0; i < 10; ++i) { - result = sqrt(static_cast<double>(i)); - fprintf(fout, "%g,\n", result); - } - - // close the table with a zero - fprintf(fout, "0};\n"); - fclose(fout); - return 0; + return fileOpen ? 0 : 1; // return 0 if wrote the file } diff --git a/Tests/Tutorial/Step5/MathFunctions/mysqrt.cxx b/Tests/Tutorial/Step5/MathFunctions/mysqrt.cxx index 458ed63..7d9379e 100644 --- a/Tests/Tutorial/Step5/MathFunctions/mysqrt.cxx +++ b/Tests/Tutorial/Step5/MathFunctions/mysqrt.cxx @@ -1,11 +1,5 @@ #include "MathFunctions.h" -#include "TutorialConfig.h" -#include <stdio.h> - -// include the generated table -#include "Table.h" - -#include <math.h> +#include <iostream> // a hack square root calculation using simple operations double mysqrt(double x) @@ -14,27 +8,16 @@ double mysqrt(double x) return 0; } - double result; - - // if we have both log and exp then use them - double delta; - - // use the table to help find an initial value - result = x; - if (x >= 1 && x < 10) { - result = sqrtTable[static_cast<int>(x)]; - } + double result = x; // do ten iterations - int i; - for (i = 0; i < 10; ++i) { + for (int i = 0; i < 10; ++i) { if (result <= 0) { result = 0.1; } - delta = x - (result * result); + double delta = x - (result * result); result = result + 0.5 * delta / result; - fprintf(stdout, "Computing sqrt of %g to be %g\n", x, result); + std::cout << "Computing sqrt of " << x << " to be " << result << std::endl; } - return result; } diff --git a/Tests/Tutorial/Step5/TutorialConfig.h.in b/Tests/Tutorial/Step5/TutorialConfig.h.in index a091265..25a0602 100644 --- a/Tests/Tutorial/Step5/TutorialConfig.h.in +++ b/Tests/Tutorial/Step5/TutorialConfig.h.in @@ -3,7 +3,3 @@ #define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@ #cmakedefine USE_MYMATH -// does the platform provide exp and log functions? -#cmakedefine HAVE_LOG -#cmakedefine HAVE_EXP - diff --git a/Tests/Tutorial/Step5/directions.txt b/Tests/Tutorial/Step5/directions.txt new file mode 100644 index 0000000..e6f5197 --- /dev/null +++ b/Tests/Tutorial/Step5/directions.txt @@ -0,0 +1,69 @@ +# 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? diff --git a/Tests/Tutorial/Step5/tutorial.cxx b/Tests/Tutorial/Step5/tutorial.cxx index 37f6ac4..1d5742d 100644 --- a/Tests/Tutorial/Step5/tutorial.cxx +++ b/Tests/Tutorial/Step5/tutorial.cxx @@ -1,8 +1,9 @@ // A simple program that computes the square root of a number +#include <cmath> +#include <iostream> +#include <string> + #include "TutorialConfig.h" -#include <math.h> -#include <stdio.h> -#include <stdlib.h> #ifdef USE_MYMATH # include "MathFunctions.h" @@ -11,23 +12,21 @@ int main(int argc, char* argv[]) { if (argc < 2) { - fprintf(stdout, "%s Version %d.%d\n", argv[0], Tutorial_VERSION_MAJOR, - Tutorial_VERSION_MINOR); - fprintf(stdout, "Usage: %s number\n", argv[0]); + std::cout << argv[0] << " Version " << Tutorial_VERSION_MAJOR << "." + << Tutorial_VERSION_MAJOR << std::endl; + std::cout << "Usage: " << argv[0] << " number" << std::endl; return 1; } - double inputValue = atof(argv[1]); - double outputValue = 0; + double inputValue = std::stod(argv[1]); - if (inputValue >= 0) { #ifdef USE_MYMATH - outputValue = mysqrt(inputValue); + double outputValue = mysqrt(inputValue); #else - outputValue = sqrt(inputValue); + double outputValue = sqrt(inputValue); #endif - } - fprintf(stdout, "The square root of %g is %g\n", inputValue, outputValue); + std::cout << "The square root of " << inputValue << " is " << outputValue + << std::endl; return 0; } |