Tests: Update CMake tutorial

Latest material from data.kitware.com -> Collections -> Courses -> CMake.
This commit is contained in:
Betsy McPhail
2019-01-20 11:28:39 -05:00
parent 438651506a
commit f2ddedfa58
112 changed files with 3118 additions and 623 deletions
+52 -54
View File
@@ -1,78 +1,76 @@
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)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
# 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)
include(CheckSymbolExists)
set(CMAKE_REQUIRED_LIBRARIES "m")
check_symbol_exists(log "math.h" HAVE_LOG)
check_symbol_exists(exp "math.h" HAVE_EXP)
# should we use our own math functions
option(USE_MYMATH "Use tutorial provided math implementation" ON)
# 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)
# enable testing
enable_testing ()
# does the application run
add_test (TutorialRuns Tutorial 25)
# does the usage message work?
add_test (TutorialUsage Tutorial)
set_tests_properties (TutorialUsage
PROPERTIES
PASS_REGULAR_EXPRESSION "Usage:.*number"
install(TARGETS Tutorial DESTINATION bin)
install(FILES "${PROJECT_BINARY_DIR}/TutorialConfig.h"
DESTINATION include
)
#define a macro to simplify adding tests
macro (do_test arg result)
add_test (TutorialComp${arg} Tutorial ${arg})
set_tests_properties (TutorialComp${arg}
# enable testing
enable_testing()
# does the application run
add_test(NAME Runs COMMAND Tutorial 25)
# does the usage message work?
add_test(NAME Usage COMMAND Tutorial)
set_tests_properties(Usage
PROPERTIES PASS_REGULAR_EXPRESSION "Usage:.*number"
)
# 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")
# build a CPack driven installer package
include (InstallRequiredSystemLibraries)
set (CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/License.txt")
set (CPACK_PACKAGE_VERSION_MAJOR "${Tutorial_VERSION_MAJOR}")
set (CPACK_PACKAGE_VERSION_MINOR "${Tutorial_VERSION_MINOR}")
include (CPack)
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")
-2
View File
@@ -1,2 +0,0 @@
This is the open source License.txt file introduced in
CMake/Tests/Tutorial/Step6...
@@ -1,24 +1,14 @@
# first we add the executable that generates the table
add_executable(MakeTable MakeTable.cxx)
# add the command to generate the source code
add_custom_command (
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Table.h
DEPENDS MakeTable
COMMAND MakeTable
ARGS ${CMAKE_CURRENT_BINARY_DIR}/Table.h
)
set_source_files_properties (
mysqrt.cxx PROPERTIES
OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/Table.h
)
# add the binary tree directory to the search path for include files
include_directories( ${CMAKE_CURRENT_BINARY_DIR} )
# add the main library
add_library(MathFunctions mysqrt.cxx)
install (TARGETS MathFunctions DESTINATION bin)
install (FILES MathFunctions.h DESTINATION include)
# state that anybody linking to us needs to include the current source dir
# to find MathFunctions.h, while we don't.
# state that we depend on Tutorial_BINARY_DIR but consumers don't, as the
# TutorialConfig.h include is an implementation detail
target_include_directories(MathFunctions
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
PRIVATE ${Tutorial_BINARY_DIR}
)
install(TARGETS MathFunctions DESTINATION lib)
install(FILES MathFunctions.h DESTINATION include)
@@ -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
}
+12 -19
View File
@@ -1,11 +1,8 @@
#include "MathFunctions.h"
#include "TutorialConfig.h"
#include <stdio.h>
#include <iostream>
// include the generated table
#include "Table.h"
#include <math.h>
#include <cmath>
// a hack square root calculation using simple operations
double mysqrt(double x)
@@ -14,27 +11,23 @@ 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)];
}
#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
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;
}
#endif
return result;
}
+111
View File
@@ -0,0 +1,111 @@
# Adding a Custom Command and Generated File #
In this section we will show how you can add a generated source file into the
build process of an application. For this example, we will create a table of
precomputed square roots as part of the build process, and then compile that
table into our application.
To accomplish this, we first need a program that will generate the table. In the
MathFunctions subdirectory a new source file named MakeTable.cxx will do just that.
// A simple program that builds a sqrt table
#include <iostream>
#include <fstream>
#include <cmath>
int main (int argc, char *argv[])
{
// make sure we have enough arguments
if (argc < 2)
{
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();
}
return fileOpen ? 0 : 1; // return 0 if wrote the file
}
Note that the table is produced as valid C++ code and that the output filename
is passed in as an argument.
The next step is to add the appropriate commands to MathFunctions CMakeLists
file to build the MakeTable executable and then run it as part of the build
process. A few commands are needed to accomplish this, as shown below:
# first we add the executable that generates the table
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
)
# add the main library
add_library(MathFunctions
mysqrt.cxx
${CMAKE_CURRENT_BINARY_DIR}/Table.h
)
target_include_directories(MathFunctions
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
PUBLIC ${Tutorial_BINARY_DIR}
# add the binary tree directory to the search path for include files
${CMAKE_CURRENT_BINARY_DIR}
)
install(TARGETS MathFunctions DESTINATION lib)
install(FILES MathFunctions.h DESTINATION include)
First, the executable for MakeTable is added as any other executable would be
added. Then we add a custom command that specifies how to produce Table.h by
running MakeTable. Next we have to let CMake know that mysqrt.cxx depends on
the generated file Table.h. This is done by adding the generated Table.h to the
list of sources for the library MathFunctions. We also have to add the current
binary directory to the list of include directories so that Table.h can be
found and included by mysqrt.cxx.
Now let's use the generated table. First, modify mysqrt.cxx to include Table.h.
Next, we can rewrite the mysqrt function to use the table:
if (x <= 0)
{
return 0;
}
// use the table to help find an initial value
double result = x;
if (x >= 1 && x < 10)
{
result = sqrtTable[static_cast<int>(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;
}
Run cmake or cmake-gui to configure the project and then build it with your
chosen build tool. When this project is built it will first build the MakeTable
executable. It will then run MakeTable to produce Table.h. Finally, it will
compile mysqrt.cxx which includes Table.h to produce the MathFunctions library.
+12 -13
View File
@@ -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;
}