With some compilers, using pow
and certain other functions in a C program requires linking to the m
library. However, some compilers don't require this and would error out on linking to the m
library. An almost identical situation exists for C++ with std::thread
and pthread
, but the CMake module FindThreads
alleviates this entirely - is there some similar module for libm?
What is the best way to detect what to do with CMake? This is my current solution, which is less than ideal because there are many more C compilers than just GCC and MSVC:
if(NOT MSVC)
target_link_libraries(my-c-target PUBLIC m)
endif()
This works for my purposes but I'm pretty sure there are cases where it would fail and require manual user intervention, which isn't fun for someone who doesn't know about this obscurity. Ideally I don't want the user to have to specify whether their compiler is weird or not via the commandline; I want to detect it automatically within CMake, since this is the entire point of CMake.
You should use the CHECK_FUNCTION_EXISTS
command to check if pow
can be used without additional flags. If this check fails, you can add m
library to CMAKE_REQUIRED_LIBRARIES
variable, assuming that linking against libm
is what's missing. But you'll need to CHECK_FUNCTION_EXISTS
again to make sure the linking is sufficient.
Sample code:
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()
If I understand correctly, linking libm
is always preferred if it is exists.
So, CheckLibraryExists works.
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})
tested with Linux x86_64, glibc 2.23 cmake 3.13.2
Common way for check, whether some code is correct for the compiler, is 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})
Cache entry POW_LIBS
contains libraries needed for use pow
function.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With