如何使用CMake链接C数学库?

51
我如何将math库添加到我的CMake文件中?这个post提到了添加一个目标链接库,但我对C语言不太熟悉。另外一个post有示例,请问能否演示一个例子?文档。我正在使用C语言,当我使用math头文件的pow方法时,收到一个undefined reference to 'pow'的错误提示。
cmake_minimum_required(VERSION 3.3)
project(CSCI-E-28-Unix-Linux-Systems-Programming)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")

set(SOURCE_FILES
    CMakeLists.txt
    getchar.c
    main.cpp
        hw0
    more01.c)

#target_link_libraries(<math.h> m)

add_executable(main main.cpp)
add_executable(getchar getchar.c)
add_executable(more01 more01.c)
add_executable(argu print_all_arguments.c)
add_executable(chars chars.c)
add_executable(ch4 ch4.c)

1
为什么要设置CXX标志?这些是用于C++而不是C的。而且,您还没有定义项目的语言,应该是 enable_language(C) - usr1234567
3个回答

73

许多数学函数(例如powsqrtfabslog等)在math.h中声明,并且需要链接到库libm,详情请参见C数学函数库。与自动链接的libc不同,libm是一个单独的库,通常需要显式链接链接器假定所有库都以lib开头,因此要连接到libm,请连接到m

您必须像target_link_libraries(ch4 m)这样使用它来链接libm到您的目标文件。第一个参数必须是一个目标文件。因此,必须在add_executable(ch4 ch4.c)之后使用它,例如:

add_executable(ch4 ch4.c)
target_link_libraries(ch4 m)

6
令人惊讶的是,在Windows上使用Cygwin时不需要这个,但在*nix上必须要用。 - John Strood
4
你能写出完整正确的答案吗?m 是一个占位符吗?还是math.c 在一个叫做 m 的库中是常识?或者它在上面的脚本中声明的方式是我无法理解的? - Sled
1
太棒了,我现在明白了。为了完备起见,我链接了一个我之前提出的问题,有关于“libm”如何变成“m”的。 - Sled
7
使用MSVC编译会出现以下构建错误:[CMake] LINK : 致命错误 LNK1104: 无法打开文件 'm.lib'。需注意保留原文中的技术术语和排版格式,仅进行翻译工作。 - Wouter Beek
1
我正在尝试从源代码构建GLFW,但在CMakeLists.txt中没有add_executable行。我该怎么办? - user2513149

11

对于各种目标,测试是否需要添加库以及如果需要,在哪里定位它或如何命名它是一个好主意。以下是一种实现方式:

:
include(CheckLibraryExists)

CHECK_LIBRARY_EXISTS(m sin "" HAVE_LIB_M)                                                                                                
                                                                                                                                         
if (HAVE_LIB_M)                                                                                                                          
    set(EXTRA_LIBS ${EXTRA_LIBS} m)                                                                                                      
endif (HAVE_LIB_M)

:
//More tests & build-up of ${EXTRA_LIBS}
:

add_executable(ch4 ch4.c)
target_link_libraries(ch4 PUBLIC ${EXTRA_LIBS})

对于libmlibc的一部分的目标,上述测试应该失败,即${EXTRA_LIBS}将不包含它,target_link也不会尝试添加它。


10

说实话,我有些惊讶这种问题在现代的CMake中仍然没有得到一个合适的答案。现在,推荐的(并且可移植的)方法是:

find_library(MATH_LIBRARY m)
if(MATH_LIBRARY)
    target_link_libraries(MyTarget PUBLIC ${MATH_LIBRARY})
endif()

这非常方便和容易,尽管在 macOS 上会产生一个不必要的链接,因为 libm 已经捆绑到 libc 中了,但是 libm 也仍然可以单独使用。不过,这可能影响不大,它会捕捉到任何需要手动链接的情况。比只检查操作系统是否为 Linux 更具可移植性? - saxbophone

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接