Может ли CMake определить, нужно ли мне ссылаться на libm при использовании pow в C?

С некоторыми компиляторами, используя pow и некоторые другие функции в программе на C требуют ссылки на m библиотека Тем не менее, некоторые компиляторы не требуют этого и выдают ошибку при соединении с m библиотека. Практически идентичная ситуация существует для C++ с std::thread а также pthread, но модуль CMake FindThreads полностью облегчает это - есть ли подобный модуль для libm?

Как лучше всего определить, что делать с CMake? Это мое текущее решение, которое далеко не идеально, потому что компиляторов Си гораздо больше, чем просто GCC и MSVC:

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

Это работает для моих целей, но я почти уверен, что бывают случаи, когда он не срабатывает и требует ручного вмешательства пользователя, что неинтересно для тех, кто не знает об этой неизвестности. В идеале я не хочу, чтобы пользователь определял, является ли его компилятор странным или нет, через командную строку; Я хочу обнаружить это автоматически в CMake, так как это весь смысл CMake.

2 ответа

Решение

Вы должны использовать модуль CHECK_FUNCTION_EXISTS, чтобы проверить, pow можно использовать без дополнительных флагов. Если эта проверка не пройдена, вы можете добавить m библиотека для CMAKE_REQUIRED_LIBRARIES переменная и запустить CHECK_FUNCTION_EXISTS снова.

Образец кода:

include(CheckFunctionExists)

CHECK_FUNCTION_EXISTS(pow RESULT)
if(NOT RESULT)
  unset(RESULT)
  list(APPEND CMAKE_REQUIRED_LIBRARIES m)
  CHECK_FUNCTION_EXISTS(pow RESULT)
  if(RESULT)
    target_link_libraries(yourtarget m)
  else()
    message(FATAL_ERROR "No pow() found")
  endif()
endif()

Если я правильно понимаю, ссылка 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

Обычный способ проверки правильности кода для компилятора - 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 функция.

Другие вопросы по тегам