Cmake·

[#8][Adding System Introspection][A菌严肃的CMake手记]

美式A菌

美式A菌

24 1

Intro

复习

  • /usr/local 目录的作用?
  • install ?
  • enable_testing ?
  • add_test ?
  • set_tests_properties ?

今天看一下如何根据不同的实现动态的切换我们代码使用的库(根据可用的系统依赖项更改实现)。

开始

  • MathFunctions\CMakeLists.txt
# 设定库的名字和源文件
add_library(MathFunctions MathFunctions.cxx) 
# 将当前目录添加到库的包含目录
target_include_directories(MathFunctions INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) 
option(USE_MYMATH "Use tutorial provided math implementation" ON) 
if (USE_MYMATH) 
# 向程式添加预处理器宏 名为USE_MYMATH
  target_compile_definitions(MathFunctions PRIVATE "USE_MYMATH") 
# 添加库SqrtLibrary
  add_library(SqrtLibrary STATIC mysqrt.cxx)
# 链接库tutorial_compiler_flags到SqrtLibrary
  target_link_libraries(SqrtLibrary PUBLIC tutorial_compiler_flags)
# 链接库SqrtLibrary到MathFunctions
  target_link_libraries(MathFunctions PRIVATE SqrtLibrary)

  # 检查编译器是否支持log和exp函数
  include(CheckCXXSourceCompiles)
  # 如何检查呢?编译一个小程序,看是否能通过编译,然后把是否通过编译的结果存到HAVE_LOG和HAVE_EXP里
   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) 
  message(STATUS "HAVE_LOG=${HAVE_LOG}")
  message(STATUS "HAVE_EXP=${HAVE_EXP}")
  # 如果HAVE_LOG和HAVE_EXP都为真则向SqrtLibrary添加预处理器宏
  if(HAVE_LOG AND HAVE_EXP)
    # 向SqrtLibrary添加预处理器宏 名为HAVE_LOG和HAVE_EXP
    # 程序就可以通过#ifdef HAVE_LOG和#ifdef HAVE_EXP来判断是否支持log和exp函数
    target_compile_definitions(SqrtLibrary PRIVATE "HAVE_LOG" "HAVE_EXP") 
  endif()
endif() 


# 如果USE_MYMATH为OFF以上链接不会被执行
# 这里重新链接库tutorial_compiler_flags到MathFunctions 传递编译器标志和其他信息
target_link_libraries(MathFunctions PUBLIC tutorial_compiler_flags) 

# 设置一个变量名为installable_libs 包含MathFunctions并且传递tutorial_compiler_flags
set(installable_libs MathFunctions tutorial_compiler_flags) 
# TARGET 是用来检查某个目标(比如库或可执行文件)是否已经定义的。
# 如果USE_MYMATH为ON则SqrtLibrary一定被定义了
if(TARGET SqrtLibrary) 
  # 将SqrtLibrary添加到installable_libs
  list(APPEND installable_libs SqrtLibrary)
endif() 

# 安装installable_libs里的文件
# DESTINATION指定安装的目录
# lib为 /usr/local/lib


install(TARGETS ${installable_libs} DESTINATION lib) 
# 安装MathFunctions.h到include目录
# include为 /usr/local/include
install(FILES MathFunctions.h DESTINATION include) 

# TARGET 用于安装构建目标,如库和可执行文件。 语法:install(TARGETS target1 target2 ... DESTINATION <dir>)
# 用于安装单个文件或一组文件。 语法:install(FILES file1 file2 ... DESTINATION <dir>)
# `MathFunctions` `tutorial_compiler_flags`都为程式定义的 所以用TARGETS
# `MathFunctions.h`为真实文件 所以用FILES

注意这部分

# 检查编译器是否支持log和exp函数
  include(CheckCXXSourceCompiles)
  # 如何检查呢?编译一个小程序,看是否能通过编译,然后把是否通过编译的结果存到HAVE_LOG和HAVE_EXP里
   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) 
  message(STATUS "HAVE_LOG=${HAVE_LOG}")
  message(STATUS "HAVE_EXP=${HAVE_EXP}")
  # 如果HAVE_LOG和HAVE_EXP都为真则向SqrtLibrary添加预处理器宏
  if(HAVE_LOG AND HAVE_EXP)
    # 向SqrtLibrary添加预处理器宏 名为HAVE_LOG和HAVE_EXP
    # 程序就可以通过#ifdef HAVE_LOG和#ifdef HAVE_EXP来判断是否支持log和exp函数
    target_compile_definitions(SqrtLibrary PRIVATE "HAVE_LOG" "HAVE_EXP") 
  endif()

  • 通过包含CheckCXXSourceCompiles引入check_cxx_source_compiles函数。
  • check_cxx_source_compiles(<code> <resultVar> [FAIL_REGEX <regex1> [<regex2>...]])
  • 检查一次是否可以构建 code 中提供的源码。结果存储在 resultVar 指定的内部缓存变量中,布尔值 true 表示成功,布尔值 false 表示失败。

  • MathFunctions\mysqrt.cxx
#include "mysqrt.h"

#include <cmath>
#include <iostream>

namespace mathfunctions
{
  namespace detail
  {
    double mysqrt(double x)
    {
      if (x <= 0)
      {
        return 0;
      }
// 通过使用if defined来判断是否调用
#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;
      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;
    }
  }
}

总结

  • include(CheckCXXSourceCompiles)
  • check_cxx_source_compiles

所属系列

从当前文章继续阅读它所在合集中的前后内容。

相关文章

优先推荐同专题、同标签和同作者内容,补足热门文章。

评论 1

登录 后参与评论

评论 1

美式A菌
美式A菌1月14日 16:29

真的有夠簡單,就是試著編譯一次我給定的代碼來判斷是否支持,然後使用宏在代碼裏判斷調用就好了。