CMake官方文档如下,
https://cmake.org/cmake/help/latest/guide/tutorial/Adding%20a%20Custom%20Command%20and%20Generated%20File.html
本文主要演示使用CMake CheckSymbolExists函数探查系统是否存在相应的函数,如果不存在,就使用CMake自带的数学库。并定义编译选项,让程序根据编译选项,执行对应分支。
程序结构如下,

tutorial.cpp
#include "tutorial_config.h"
#ifdef USE_MYMATH
#include "math_functions.h"
#endif
#include <cmath>
#include <iostream>
#include <string>
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 EXIT_FAILURE;
}
double const input_val = std::stod(argv[1]);
#ifdef USE_MYMATH
double const ouput_val = mysqrt(input_val);
#else
double const ouput_val = sqrt(input_val);
#endif
std::cout << "The sqrt root of " << input_val << " is: " << ouput_val << std::endl;
return EXIT_SUCCESS;
}
tutorial_config.h.in
// Tutorial的配置选项和设置
#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@
#cmakedefine USE_MYMATH
外层CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
# 设置工程名称和版本
project(Tutorial VERSION 1.0)
# 指定C++标准
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED true)
# 是否使用自定义的 math实现
option(USE_MYMATH "Use tutorial provided math implementation" ON)
# 配置生成header文件
configure_file(tutorial_config.h.in tutorial_config.h)
# 添加 math_functions 库
if(USE_MYMATH)
add_subdirectory(math_functions)
list(APPEND EXTRA_LIBS math_functions)
endif()
add_executable(Tutorial tutorial.cpp)
target_link_libraries(Tutorial PUBLIC ${EXTRA_LIBS})
target_include_directories(Tutorial PUBLIC "${PROJECT_BINARY_DIR}")
enable_testing()
# 应用程序能运行吗?
add_test(NAME Runs COMMAND Tutorial 25)
# 使用消息 能工作吗?
add_test(NAME Usage COMMAND Tutorial)
set_tests_properties(Usage PROPERTIES PASS_REGULAR_EXPRESSION "Usage:.*number")
# 定义一个函数来简化添加测试
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(Tutorial 4 "The sqrt root of 4 is: 2")
do_test(Tutorial 9 "The sqrt root of 9 is: 3")
do_test(Tutorial 5 "The sqrt root of 5 is: 2.23607")
do_test(Tutorial 7 "The sqrt root of 7 is: 2.64575")
do_test(Tutorial 25 "The sqrt root of 25 is: 5")
do_test(Tutorial -25 "The sqrt root of -25 is: 0")
do_test(Tutorial 0.0001 "The sqrt root of 0.0001 is: 0.01")
install(TARGETS Tutorial DESTINATION bin)
install(FILES "${PROJECT_BINARY_DIR}/tutorial_config.h" DESTINATION include)
math_functions/CMakeLists.txt
add_library(math_functions mysqrt.cpp)
target_include_directories(math_functions INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
# 系统是否包含log和exp 函数?
include(CheckSymbolExists)
check_symbol_exists(log "math.h" HAVE_LOG)
check_symbol_exists(exp "math.h" HAVE_EXP)
if(NOT (HAVE_LOG AND HAVE_EXP))
unset(HAVE_LOG CACHE)
unset(HAVE_EXP CACHE)
set(CMAKE_REQUIRED_LIBRARIES "m")
check_symbol_exists(log "math.h" HAVE_LOG)
check_symbol_exists(exp "math.h" HAVE_EXP)
if(HAVE_LOG AND HAVE_EXP)
target_link_libraries(math_functions PRIVATE m)
endif()
endif()
# 添加编译选项
if(HAVE_LOG AND HAVE_EXP)
target_compile_definitions(math_functions PRIVATE "HAVE_LOG" "HAVE_EXP")
endif()
install(TARGETS math_functions DESTINATION lib)
install(FILES math_functions.h DESTINATION include)
math_functions/math_functions.h
#ifndef _FREDRIC_MATH_FUNCTIONS_H_
#define _FREDRIC_MATH_FUNCTIONS_H_
double mysqrt(double x);
#endif
math_functions/my_sqrt.cpp
#include <iostream>
#include <cmath>
#include "math_functions.h"
// a hack square root calculation using simple operations
double mysqrt(double x) {
if (x <= 0) {
return 0;
}
#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 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
return result;
}
程序输出如下,

网友评论