50

How do I add the math library to my CMake file? This post references adding a target link library, yet I am not too familiar with C. An Additional post - Could someone please demonstrate an example. Documentation I am using C and I receive an undefined reference to 'pow' with the pow method of the math header.

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)
Sled
  • 18,541
  • 27
  • 119
  • 168
phillipsK
  • 1,466
  • 5
  • 29
  • 43
  • 1
    Why do you set CXX flags? These are for C++, not C. And you have not defined the language for your project, should be `enable_language(C)`. – usr1234567 Jan 06 '16 at 08:12

3 Answers3

72

Many mathematical functions (pow, sqrt, fabs, log etc.) are declared in math.h and require the library libm to be linked. Unlike libc, which is automatically linked, libm is a separate library and often requires explicit linkage. The linker presumes all libraries to begin with lib, so to link to libm you link to m.

You have to use it like target_link_libraries(ch4 m) to link libmto your target. The first argument must be a target. Thus it must be used after add_executable(ch4 ch4.c) like:

add_executable(ch4 ch4.c)
target_link_libraries(ch4 m)
Sled
  • 18,541
  • 27
  • 119
  • 168
usr1234567
  • 21,601
  • 16
  • 108
  • 128
  • 6
    It's surprising this isn't needed for Cygwin on Windows. But sadly is required on *nix. – John Strood Jul 26 '16 at 18:23
  • 4
    Can you write out the full correct answer? Is `m` a placeholder? or is it just common knowledge that `math.c` is in a library called `m`? Or is it declared in a way that I don't fathom in the script above? – Sled Jan 17 '19 at 19:30
  • 1
    Awesome, I get it now. I linked to a question that I had asked earlier about how "libm" becomes just "m" just for completeness. – Sled Jan 18 '19 at 15:18
  • 6
    With MSVC this results in the following build error: `[CMake] LINK : fatal error LNK1104: cannot open file 'm.lib'` – Wouter Beek Jul 06 '19 at 11:14
  • 1
    I am trying to build `GLFW` from source and there is no line `add_executable` in `CMakeLists.txt`. What should I do? – user2513149 Jul 14 '19 at 14:31
11

For various targets it's a good idea to test if adding a library is needed or not and if so where it's located of how it's named. Here's one way to do it:

:
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})

For targets where libm is part of libc, the above test should fail, i.e. ${EXTRA_LIBS} will miss it and target_link will not try to add.

Michael Ambrus
  • 983
  • 7
  • 9
9

I am frankly a bit surprised that this kind of question still doesn't have a proper answer for Modern CMake. These days, the recommended (and portable) approach is this:

find_library(MATH_LIBRARY m)
if(MATH_LIBRARY)
    target_link_libraries(MyTarget PUBLIC ${MATH_LIBRARY})
endif()
Xaldew
  • 560
  • 5
  • 18
  • This is super-convenient and easy, although it does produce an unnecessary link on macOS, due to libm being bundled into libc on macOS, but libm is still available separately too. Still, this is probably of little consequence, and it'll catch any case where it might need to be linked in manually. More portable than just checking if OS = Linux? – saxbophone Apr 19 '23 at 11:56