【问题标题】:Can CMake detect if I need to link to libm when using pow in C?在 C 中使用 pow 时,CMake 是否可以检测到我是否需要链接到 libm?
【发布时间】:2015-12-25 07:41:42
【问题描述】:

对于某些编译器,using pow and certain other functions in a C program requires linking to the m library。但是,一些编译器不需要这样做,并且在链接到 m 库时会出错。使用std::threadpthread 的C++ 存在几乎相同的情况,但CMake 模块FindThreads 完全缓解了这种情况——libm 是否有一些类似的模块?

检测如何使用 CMake 的最佳方法是什么?这是我目前的解决方案,它不太理想,因为 C 编译器不仅仅是 GCC 和 MSVC:

if(NOT MSVC)
    target_link_libraries(my-c-target PUBLIC m)
endif()

这适用于我的目的,但我很确定在某些情况下它会失败并需要手动用户干预,这对于不了解这种默默无闻的人来说并不好玩。理想情况下,我不希望用户必须通过命令行指定他们的编译器是否为weird;我想在 CMake 中自动检测它,因为这是 CMake 的全部意义所在。

【问题讨论】:

  • "一些编译器不需要这个,并且在链接到 m 库时会出错" 请问是哪一个?
  • @alk 我为机器人微控制器使用了一个不起眼的 C 编译器,我知道它不支持 -lm,因为这是我从该编译器得到的第一个错误。在这种情况下使用我的特定代码并非不可能。
  • @alk 在使用 Visual Studio 编译器 v16 时,使用 CMake 的 target_link_libraries(MY_TARGET m) 设置 libm 时出现链接错误。

标签: c gcc cmake libm


【解决方案1】:

您应该使用CHECK_FUNCTION_EXISTS 命令来检查pow 是否可以在没有附加标志的情况下使用。如果此检查失败,您可以将 m 库添加到 CMAKE_REQUIRED_LIBRARIES 变量,假设缺少与 libm 的链接。但是您需要再次CHECK_FUNCTION_EXISTS 以确保链接足够。

示例代码:

include(CheckFunctionExists)

if(NOT POW_FUNCTION_EXISTS AND NOT NEED_LINKING_AGAINST_LIBM)
  CHECK_FUNCTION_EXISTS(pow POW_FUNCTION_EXISTS)
  if(NOT POW_FUNCTION_EXISTS)
      unset(POW_FUNCTION_EXISTS CACHE)
      list(APPEND CMAKE_REQUIRED_LIBRARIES m)
      CHECK_FUNCTION_EXISTS(pow POW_FUNCTION_EXISTS)
      if(POW_FUNCTION_EXISTS)
          set(NEED_LINKING_AGAINST_LIBM True CACHE BOOL "" FORCE)
      else()
          message(FATAL_ERROR "Failed making the pow() function available")
      endif()
  endif()
endif()

if (NEED_LINKING_AGAINST_LIBM)
     target_link_libraries(your_target_here m)
endif()

【讨论】:

  • 虽然这看起来应该可以工作,但CHECK_FUNCTION_EXISTS 似乎会缓存结果,以便您第二次调用它时不会执行任何操作。
  • 哦,对了。 unset(RESULT) 或在第二次调用中使用不同的变量名。
  • 谢谢,成功了!我现在会接受你的回答,只是不要忘记用修复来编辑它。
  • RESULT os 是糟糕的变量名。而且您不应该重用变量名。因此,您首先不需要丑陋的unset 并具有合理的变量名称选择。
  • 已编辑以反映我对这段代码 sn-p 的体验 - 我需要从缓存中清除值;另外,使用更相关的变量名。
【解决方案2】:

检查某些代码是否对编译器正确的常用方法是try_compile

use_pow.c

#include <math.h>
int main(void) {return pow(2, 2.5);}

CMakeLists.txt

...
if(NOT DEFINED POW_LIBS)
    try_compile(pow_use_m # RESULT_VAR
                check_pow # bindir
                use_pow.c # srcfile
                LINK_LIBRARIES m)
    if(pow_use_m)
        set(POW_LIBS m CACHE INTERNAL "Libraries for use pow")
    else()
        set(POW_LIBS "" CACHE INTERNAL "Libraries for use pow")
    endif()
endif()

...
target_link_libraries(my-c-target PUBLIC ${POW_LIBS})

缓存条目POW_LIBS 包含使用pow 函数所需的库。

【讨论】:

    【解决方案3】:

    如果我理解正确,如果存在链接libm,则始终是首选。

    所以,CheckLibraryExists 有效。

    CMakeLists.txt

    set(POW_LIBS "")
    include(CheckLibraryExists)
    check_library_exists(m pow "" LIBM)
    if(LIBM)
        list(APPEND POW_LIBS "m")
    endif()
    
    ...
    target_link_libraries(my-c-target PUBLIC ${POW_LIBS})
    

    使用 Linux x86_64、glibc 2.23 cmake 3.13.2 测试

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-05-27
      • 2018-09-24
      • 1970-01-01
      • 1970-01-01
      • 2012-09-09
      • 1970-01-01
      • 1970-01-01
      • 2014-06-10
      相关资源
      最近更新 更多