mirror of
https://github.com/Kitware/CMake.git
synced 2026-01-06 05:40:54 -06:00
Help/guide/tutorial: Adopt tutorial code
This commit is contained in:
committed by
Betsy McPhail
parent
d2fde94809
commit
862cfc0e6c
80
Help/guide/tutorial/Step9/CMakeLists.txt
Normal file
80
Help/guide/tutorial/Step9/CMakeLists.txt
Normal file
@@ -0,0 +1,80 @@
|
||||
cmake_minimum_required(VERSION 3.3)
|
||||
project(Tutorial)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
|
||||
# the version number.
|
||||
set(Tutorial_VERSION_MAJOR 1)
|
||||
set(Tutorial_VERSION_MINOR 0)
|
||||
|
||||
# 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)
|
||||
|
||||
# should we use our own math functions
|
||||
option(USE_MYMATH "Use tutorial provided math implementation" ON)
|
||||
|
||||
# configure a header file to pass the version number only
|
||||
configure_file(
|
||||
"${PROJECT_SOURCE_DIR}/TutorialConfig.h.in"
|
||||
"${PROJECT_BINARY_DIR}/TutorialConfig.h"
|
||||
)
|
||||
|
||||
# add the MathFunctions library?
|
||||
if(USE_MYMATH)
|
||||
add_subdirectory(MathFunctions)
|
||||
list(APPEND EXTRA_LIBS MathFunctions)
|
||||
endif()
|
||||
|
||||
# add the executable
|
||||
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
|
||||
include(CTest)
|
||||
|
||||
# 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}
|
||||
)
|
||||
endfunction(do_test)
|
||||
|
||||
# do a bunch of result based tests
|
||||
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")
|
||||
|
||||
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)
|
||||
15
Help/guide/tutorial/Step9/CTestConfig.cmake
Normal file
15
Help/guide/tutorial/Step9/CTestConfig.cmake
Normal file
@@ -0,0 +1,15 @@
|
||||
## This file should be placed in the root directory of your project.
|
||||
## Then modify the CMakeLists.txt file in the root directory of your
|
||||
## project to incorporate the testing dashboard.
|
||||
##
|
||||
## # The following are required to submit to the CDash dashboard:
|
||||
## ENABLE_TESTING()
|
||||
## INCLUDE(CTest)
|
||||
|
||||
set(CTEST_PROJECT_NAME "CMakeTutorial")
|
||||
set(CTEST_NIGHTLY_START_TIME "00:00:00 EST")
|
||||
|
||||
set(CTEST_DROP_METHOD "http")
|
||||
set(CTEST_DROP_SITE "my.cdash.org")
|
||||
set(CTEST_DROP_LOCATION "/submit.php?project=CMakeTutorial")
|
||||
set(CTEST_DROP_SITE_CDASH TRUE)
|
||||
2
Help/guide/tutorial/Step9/License.txt
Normal file
2
Help/guide/tutorial/Step9/License.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
This is the open source License.txt file introduced in
|
||||
CMake/Tutorial/Step7...
|
||||
35
Help/guide/tutorial/Step9/MathFunctions/CMakeLists.txt
Normal file
35
Help/guide/tutorial/Step9/MathFunctions/CMakeLists.txt
Normal file
@@ -0,0 +1,35 @@
|
||||
# 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
|
||||
)
|
||||
|
||||
# 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 our binary dir to find Table.h
|
||||
target_include_directories(MathFunctions
|
||||
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
|
||||
)
|
||||
|
||||
# use compile definitions to state if we have enabled USE_MYMATH
|
||||
# and that anything that links to use will get this define
|
||||
target_compile_definitions(MathFunctions INTERFACE "USE_MYMATH")
|
||||
|
||||
if(HAVE_LOG AND HAVE_EXP)
|
||||
target_compile_definitions(MathFunctions
|
||||
PRIVATE "HAVE_LOG" "HAVE_EXP")
|
||||
endif()
|
||||
|
||||
install(TARGETS MathFunctions DESTINATION lib)
|
||||
install(FILES MathFunctions.h DESTINATION include)
|
||||
25
Help/guide/tutorial/Step9/MathFunctions/MakeTable.cxx
Normal file
25
Help/guide/tutorial/Step9/MathFunctions/MakeTable.cxx
Normal file
@@ -0,0 +1,25 @@
|
||||
// A simple program that builds a sqrt table
|
||||
#include <cmath>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
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
|
||||
}
|
||||
18
Help/guide/tutorial/Step9/MathFunctions/MathFunctions.cxx
Normal file
18
Help/guide/tutorial/Step9/MathFunctions/MathFunctions.cxx
Normal file
@@ -0,0 +1,18 @@
|
||||
|
||||
#include "MathFunctions.h"
|
||||
#include <cmath>
|
||||
|
||||
#ifdef USE_MYMATH
|
||||
# include "mysqrt.h"
|
||||
#endif
|
||||
|
||||
namespace mathfunctions {
|
||||
double sqrt(double x)
|
||||
{
|
||||
#ifdef USE_MYMATH
|
||||
return detail::mysqrt(x);
|
||||
#else
|
||||
return std::sqrt(x);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
1
Help/guide/tutorial/Step9/MathFunctions/MathFunctions.h
Normal file
1
Help/guide/tutorial/Step9/MathFunctions/MathFunctions.h
Normal file
@@ -0,0 +1 @@
|
||||
double mysqrt(double x);
|
||||
41
Help/guide/tutorial/Step9/MathFunctions/mysqrt.cxx
Normal file
41
Help/guide/tutorial/Step9/MathFunctions/mysqrt.cxx
Normal file
@@ -0,0 +1,41 @@
|
||||
#include "MathFunctions.h"
|
||||
#include <iostream>
|
||||
|
||||
// include the generated table
|
||||
#include "Table.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
// a hack square root calculation using simple operations
|
||||
double mysqrt(double x)
|
||||
{
|
||||
if (x <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 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
|
||||
// use the table to help find an initial value
|
||||
double result = x;
|
||||
if (x >= 1 && x < 10) {
|
||||
result = sqrtTable[static_cast<int>(x)];
|
||||
}
|
||||
|
||||
// if we have both log and exp then use them
|
||||
|
||||
// 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
|
||||
return result;
|
||||
}
|
||||
6
Help/guide/tutorial/Step9/MathFunctions/mysqrt.h
Normal file
6
Help/guide/tutorial/Step9/MathFunctions/mysqrt.h
Normal file
@@ -0,0 +1,6 @@
|
||||
|
||||
namespace mathfunctions {
|
||||
namespace detail {
|
||||
double mysqrt(double x);
|
||||
}
|
||||
}
|
||||
3
Help/guide/tutorial/Step9/TutorialConfig.h.in
Normal file
3
Help/guide/tutorial/Step9/TutorialConfig.h.in
Normal file
@@ -0,0 +1,3 @@
|
||||
// the configured version number
|
||||
#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
|
||||
#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@
|
||||
166
Help/guide/tutorial/Step9/directions.txt
Normal file
166
Help/guide/tutorial/Step9/directions.txt
Normal file
@@ -0,0 +1,166 @@
|
||||
# Mixing Static and Shared #
|
||||
|
||||
In this section we will show how by using the BUILD_SHARED_LIBS variable we can
|
||||
control the default behavior of add_library, and allow control over how
|
||||
libraries without an explicit type ( STATIC/SHARED/MODULE/OBJECT ) are built.
|
||||
|
||||
To accomplish this we need to add BUILD_SHARED_LIBS to the top level
|
||||
CMakeLists.txt. We use the option command as it allows users to optionally
|
||||
select if the value should be On or Off.
|
||||
|
||||
Next we are going to refactor MathFunctions to become a real library that
|
||||
encapsulates using mysqrt or sqrt, instead of requiring the calling code
|
||||
to do this logic. This will also mean that USE_MYMATH will not control building
|
||||
MathFuctions, but instead will control the behavior of this library.
|
||||
|
||||
The first step is to update the starting section of the top level CMakeLists.txt
|
||||
to look like:
|
||||
|
||||
cmake_minimum_required(VERSION 3.3)
|
||||
project(Tutorial)
|
||||
|
||||
# control where the static and shared libraries are built so that on windows
|
||||
# we don't need to tinker with the path to run the executable
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
|
||||
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
||||
|
||||
option(BUILD_SHARED_LIBS "Build using shared libraries" ON)
|
||||
|
||||
# the version number.
|
||||
set(Tutorial_VERSION_MAJOR 1)
|
||||
set(Tutorial_VERSION_MINOR 0)
|
||||
|
||||
# configure a header file to pass the version number only
|
||||
configure_file(
|
||||
"${PROJECT_SOURCE_DIR}/TutorialConfig.h.in"
|
||||
"${PROJECT_BINARY_DIR}/TutorialConfig.h"
|
||||
)
|
||||
|
||||
# add the MathFunctions library
|
||||
add_subdirectory(MathFunctions)
|
||||
|
||||
# add the executable
|
||||
add_executable(Tutorial tutorial.cxx)
|
||||
target_link_libraries(Tutorial PUBLIC MathFunctions)
|
||||
|
||||
Now that we have made MathFunctions always be used, we will need to update
|
||||
the logic of that library. So, in MathFunctions/CMakeLists.txt we need to
|
||||
create a SqrtLibrary that will conditionally be built when USE_MYMATH is
|
||||
enabled. Now, since this is a tutorial, we are going to explicitly require
|
||||
that SqrtLibrary is built statically.
|
||||
|
||||
The end result is that MathFunctions/CMakeLists.txt should look like:
|
||||
|
||||
# add the library that runs
|
||||
add_library(MathFunctions MathFunctions.cxx)
|
||||
|
||||
# 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}
|
||||
)
|
||||
|
||||
# should we use our own math functions
|
||||
option(USE_MYMATH "Use tutorial provided math implementation" ON)
|
||||
if(USE_MYMATH)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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
|
||||
)
|
||||
|
||||
# library that just does sqrt
|
||||
add_library(SqrtLibrary STATIC
|
||||
mysqrt.cxx
|
||||
${CMAKE_CURRENT_BINARY_DIR}/Table.h
|
||||
)
|
||||
|
||||
# state that we depend on our binary dir to find Table.h
|
||||
target_include_directories(SqrtLibrary PRIVATE
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
)
|
||||
|
||||
target_compile_definitions(MathFunctions PRIVATE "USE_MYMATH")
|
||||
if(HAVE_LOG AND HAVE_EXP)
|
||||
target_compile_definitions(SqrtLibrary
|
||||
PRIVATE "HAVE_LOG" "HAVE_EXP")
|
||||
endif()
|
||||
|
||||
target_link_libraries(MathFunctions PRIVATE SqrtLibrary)
|
||||
endif()
|
||||
|
||||
# define the symbol stating we are using the declspec(dllexport) when
|
||||
# building on windows
|
||||
target_compile_definitions(MathFunctions PRIVATE "EXPORTING_MYMATH")
|
||||
|
||||
install(TARGETS MathFunctions DESTINATION lib)
|
||||
install(FILES MathFunctions.h DESTINATION include)
|
||||
|
||||
Next, update MathFunctions/mysqrt.cxx to use the mathfunctions and detail namespaces:
|
||||
|
||||
#include <iostream>
|
||||
#include "MathFunctions.h"
|
||||
|
||||
// include the generated table
|
||||
#include "Table.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace mathfunctions {
|
||||
namespace detail {
|
||||
// a hack square root calculation using simple operations
|
||||
double mysqrt(double x)
|
||||
{
|
||||
...
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
We also need to make some changes in tutorial.cxx, so that it no longer uses USE_MYMATH:
|
||||
1. Always include MathFunctions.h
|
||||
2. Always use mathfunctions::sqrt
|
||||
|
||||
Finally, update MathFunctions/MathFunctions.h to use dll export defines:
|
||||
|
||||
#if defined(_WIN32)
|
||||
#if defined(EXPORTING_MYMATH)
|
||||
#define DECLSPEC __declspec(dllexport)
|
||||
#else
|
||||
#define DECLSPEC __declspec(dllimport)
|
||||
#endif
|
||||
#else //non windows
|
||||
#define DECLSPEC
|
||||
#endif
|
||||
|
||||
namespace mathfunctions
|
||||
{
|
||||
double DECLSPEC sqrt(double x);
|
||||
}
|
||||
|
||||
At this point, if you build everything, you will notice that linking fails
|
||||
as we are combining a static library without position enabled code with a
|
||||
library that has position enabled code. This solution to this is to explicitly
|
||||
set the POSITION_INDEPENDENT_CODE target property of SqrtLibrary to be True no
|
||||
matter the build type.
|
||||
|
||||
Exercise: We modified MathFunctions.h to use dll export defines. Using CMake
|
||||
documentation can you find a helper module to simplify this?
|
||||
|
||||
Exercise: Determine what command is enabling PIC for SqrtLibrary.
|
||||
What happens if we remove said command?
|
||||
33
Help/guide/tutorial/Step9/tutorial.cxx
Normal file
33
Help/guide/tutorial/Step9/tutorial.cxx
Normal file
@@ -0,0 +1,33 @@
|
||||
// A simple program that computes the square root of a number
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include "TutorialConfig.h"
|
||||
|
||||
#ifdef USE_MYMATH
|
||||
# include "MathFunctions.h"
|
||||
#endif
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
if (argc < 2) {
|
||||
std::cout << argv[0] << " Version " << Tutorial_VERSION_MAJOR << "."
|
||||
<< Tutorial_VERSION_MINOR << std::endl;
|
||||
std::cout << "Usage: " << argv[0] << " number" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
double inputValue = std::stod(argv[1]);
|
||||
|
||||
#ifdef USE_MYMATH
|
||||
double outputValue = mysqrt(inputValue);
|
||||
#else
|
||||
double outputValue = sqrt(inputValue);
|
||||
#endif
|
||||
|
||||
std::cout << "The square root of " << inputValue << " is " << outputValue
|
||||
<< std::endl;
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user