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

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

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

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

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


person LB--    schedule 28.09.2015    source источник
comment
некоторые компиляторы не требуют этого и выдадут ошибку при связывании с библиотекой m Какой из них, пожалуйста?   -  person alk    schedule 28.09.2015
comment
@alk Я работал с малоизвестным компилятором C для микроконтроллера робота, который, как я точно знаю, не поддерживает -lm, потому что это была первая ошибка, которую я когда-либо получал от этого компилятора. Не исключено, что мой конкретный код будет использоваться в таком сценарии.   -  person LB--    schedule 28.09.2015
comment
@alk Я получаю сообщение об ошибке ссылки, когда libm устанавливается с помощью CMake target_link_libraries(MY_TARGET m) при использовании компилятора Visual Studio v16.   -  person Wouter Beek    schedule 06.07.2019


Ответы (3)


Вы должны использовать команду 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()
person arrowd    schedule 28.09.2015
comment
Хотя это выглядит так, как будто это должно работать, CHECK_FUNCTION_EXISTS, кажется, кэширует результат, так что второй раз, когда вы вызываете его, это не работает. - person LB--; 29.09.2015
comment
О верно. Либо unset(RESULT), либо используйте другое имя переменной во втором вызове. - person arrowd; 29.09.2015
comment
Спасибо, это сработало! Я приму ваш ответ сейчас, только не забудьте отредактировать его с исправлением. - person LB--; 29.09.2015
comment
RESULT os am ужасное имя переменной. И вы не должны повторно использовать имя переменной. Следовательно, вам не нужны уродливые unset с разумным выбором имени переменной в первую очередь. - person usr1234567; 04.02.2016
comment
@ usr1234567 Вы правы, и я уже прокомментировал это. Это не производственный код, а пример. - person arrowd; 04.02.2016
comment
Отредактировано, чтобы отразить мой опыт работы с этим фрагментом кода - мне нужно было очистить значение из кеша; также, используя более подходящее имя переменной. - person einpoklum; 27.02.2019
comment
@ usr1234567: отредактировано, чтобы изменить это. - person einpoklum; 27.02.2019


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

person Byoungchan Lee    schedule 15.02.2019