// the configured options and settings for Tutorial #define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@ #define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@
// a hack square root calculation using simple operations doublemysqrt(double x) { if (x <= 0) { return0; }
double result; double delta; result = x;
// do ten iterations int i; for (i = 0; i < 10; ++i) { if (result <= 0) { result = 0.1; } delta = x - (result * result); result = result + 0.5 * delta / result; fprintf(stdout, "Computing sqrt of %g to be %g\n", x, result); } return result; }
# add the MathFunctions library add_subdirectory(MathFunctions)
# add the executable add_executable(Tutorial tutorial.cxx)
target_link_libraries(Tutorial PUBLIC MathFunctions)
# 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}" "${PROJECT_SOURCE_DIR}/MathFunctions" )
// A simple program that computes the square root of a number #include<cmath> // #include <cstdlib> #include<iostream> #include<string> #include"TutorialConfig.h" #include"MathFunctions.h"
./Tutorial 16 Computing sqrt of 16 to be 8.5 Computing sqrt of 16 to be 5.19118 Computing sqrt of 16 to be 4.13666 Computing sqrt of 16 to be 4.00226 Computing sqrt of 16 to be 4 Computing sqrt of 16 to be 4 Computing sqrt of 16 to be 4 Computing sqrt of 16 to be 4 Computing sqrt of 16 to be 4 Computing sqrt of 16 to be 4 The square root of 16 is 4
# 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}" ${EXTRA_INCLUDES} )
list(APPEND …) 命令用于将新的 element 添加到 list 中,我们定义两个 list 变量 EXTRA_LIBS 和 EXTRA_INCLUDES 分别用于存放链接库和库的头文件索引路径,之后使用 target_link_libraries() 和 target_include_directories() 传入这两个变量即可链接库文件和库的头文件。
./Tutorial 16 Computing sqrt of 16 to be 8.5 Computing sqrt of 16 to be 5.19118 Computing sqrt of 16 to be 4.13666 Computing sqrt of 16 to be 4.00226 Computing sqrt of 16 to be 4 Computing sqrt of 16 to be 4 Computing sqrt of 16 to be 4 Computing sqrt of 16 to be 4 Computing sqrt of 16 to be 4 Computing sqrt of 16 to be 4 The square root of 16 is 4
# 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}" # ${EXTRA_INCLUDES} )
重新 cmake 生成编译,运行 Tutorial 查看输出正常:
1 2 3 4 5 6 7 8 9 10 11 12
./Tutorial 16 Computing sqrt of 16 to be 8.5 Computing sqrt of 16 to be 5.19118 Computing sqrt of 16 to be 4.13666 Computing sqrt of 16 to be 4.00226 Computing sqrt of 16 to be 4 Computing sqrt of 16 to be 4 Computing sqrt of 16 to be 4 Computing sqrt of 16 to be 4 Computing sqrt of 16 to be 4 Computing sqrt of 16 to be 4 The square root of 16 is 4
# 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 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")
# does this system provide the log and exp functions? include(CheckCXXSourceCompiles) 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)
if(HAVE_LOG AND HAVE_EXP) target_compile_definitions(MathFunctions PRIVATE "HAVE_LOG" "HAVE_EXP") endif()
在 mysqrt.cxx 中添加 HAVE_LOG 和 HAVE_EXP 的判断:
1 2 3 4 5 6 7
#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; #endif
./Tutorial 16 Computing sqrt of 16 to be 4 using log and exp Computing sqrt of 16 to be 4 Computing sqrt of 16 to be 4 Computing sqrt of 16 to be 4 Computing sqrt of 16 to be 4 Computing sqrt of 16 to be 4 Computing sqrt of 16 to be 4 Computing sqrt of 16 to be 4 Computing sqrt of 16 to be 4 Computing sqrt of 16 to be 4 Computing sqrt of 16 to be 4 The square root of 16 is 4
// use the table to help find an initial value double result = x; if (x >= 1 && x < 10) { std::cout << "Use the table to help find an initial value " << std::endl; 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; }
./Tutorial 9 Use the table to help find an initial value Computing sqrt of 9 to be 3 Computing sqrt of 9 to be 3 Computing sqrt of 9 to be 3 Computing sqrt of 9 to be 3 Computing sqrt of 9 to be 3 Computing sqrt of 9 to be 3 Computing sqrt of 9 to be 3 Computing sqrt of 9 to be 3 Computing sqrt of 9 to be 3 Computing sqrt of 9 to be 3 The square root of 9 is 3
# set the project name and version project(Tutorial VERSION 1.0)
# specify the C++ standard set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED True)
# 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_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
option(BUILD_SHARED_LIBS "Build using shared libraries" ON)
# configure a header file to pass the version number only configure_file(TutorialConfig.h.in TutorialConfig.h)
# add the MathFunctions library add_subdirectory(MathFunctions)
# add the executable add_executable(Tutorial tutorial.cxx) target_link_libraries(Tutorial PUBLIC MathFunctions)
# add the library that runs add_library(MathFunctions MathFunctions.cxx)
# state that anybody linking to us needs to include the current sourcedir # 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)
# define the symbol stating we are using the declspec(dllexport) when # building on windows target_compile_definitions(MathFunctions PRIVATE "EXPORTING_MYMATH")
namespace mathfunctions { namespace detail { // a hack square root calculation using simple operations doublemysqrt(double x) { if (x <= 0) { return0; }
// use the table to help find an initial value double result = x; if (x >= 1 && x < 10) { std::cout << "Use the table to help find an initial value " << std::endl; 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; }
return result; } } }
我们还需要对 进行一些更改 tutorial.cxx,使其不再使用 USE_MYMATH:
始终引用 MathFunctions.h
始终使用 mathfunctions::sqrt
不包括 cmath
最后,更新 MathFunctions/MathFunctions.h 使用 dll 导出定义:
1 2 3 4 5 6 7 8 9 10 11 12 13
#if defined(_WIN32) # if defined(EXPORTING_MYMATH) # define DECLSPEC __declspec(dllexport) # else # define DECLSPEC __declspec(dllimport) # endif #else// non windows # define DECLSPEC #endif
# state that SqrtLibrary need PIC when the default is shared libraries set_target_properties(SqrtLibrary PROPERTIES POSITION_INDEPENDENT_CODE ${BUILD_SHARED_LIBS} )
include(CMakePackageConfigHelpers) # generate the config file that is includes the exports configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfig.cmake" INSTALL_DESTINATION "lib/cmake/example" NO_SET_AND_CHECK_MACRO NO_CHECK_REQUIRED_COMPONENTS_MACRO )