CMake: как связать библиотеку БЕЗ функции автоматического поиска FIND_PACKAGE?

Интересно, как найти/связать библиотеку без FIND_PACKAGE.

Предположим, что у нас есть "личная" библиотека, называемая testlib:

/perso/testlib/include/testlib1.h
/perso/testlib/include/testlib2.h
/perso/testlib/lib/testlib1.a
/perso/testlib/lib/testlib2.a

Как связать его с CMake?

1) Какие функции можно связать непосредственно в коде CMakeLists.txt?

2) Как разрешить пользователю выбирать, где находятся файлы?

3) Мне трудно понять, что интерпретируется и что это не CMake. Например, если вы определяете переменную ${MYVARIABLE_INCLUDE_DIR} или ${MYVARIABLE_LIBRARIES}, это "INCLUDE_DIR" или "LIBRARIES" расширение, интерпретируемое CMake или нет разницы, если я вызываю эту переменную ${MYVARIABLE_INCDIR}?

4) Как выполнять те же процедуры (включая "личную" библиотеку), если у вас есть библиотека, содержащая десять файлов библиотеки или больше в каталоге lib?

5) И, наконец, когда вы введете TARGET_LINK_LIBRARIES(myexecutable gmp), откуда вы знаете, что имя библиотеки "gmp". Почему бы не "Gmp" или "GMP"? Является ли имя библиотеки помещенным в эту функцию равным файлу .a минус "lib" и ".a"? Например libgmp.a → gmp? Если я хочу связать библиотеку libtestlolexample.a, мне нужно набрать TARGET_LINK_LIBRARIES(myexecutable testlolexample)?

Большое спасибо.

Ответ 1

Вы можете использовать target_link_libraries(myexecutable mylib) для ссылки на библиотеку "mylib". Компилятор будет использовать свой путь по умолчанию, чтобы найти указанную библиотеку (например, он будет искать libmylib.a в Linux). Компилятор будет смотреть только в link_directories(directory1 directory2 ...), поэтому вы можете попробовать эту команду, чтобы добавить необходимые каталоги в путь поиска.

Когда "mylib" также скомпилирован с помощью CMake, это будет распознано, и все должно работать автоматически.

Если вы хотите, чтобы пользователь указывал каталог, вы можете использовать переменную CMake с кешированием. set(MYPATH "NOT-DEFINED" CACHE PATH "docstring").

Для более сложных материалов очень полезно написать модуль поиска CMake, который можно использовать с find_package. Я предлагаю вам взглянуть на FindALSA.cmake, который можно использовать в качестве хорошей отправной точки.

Интересная часть в конце:

if(ALSA_FOUND)
  set( ALSA_LIBRARIES ${ALSA_LIBRARY} )
  set( ALSA_INCLUDE_DIRS ${ALSA_INCLUDE_DIR} )
endif()

mark_as_advanced(ALSA_INCLUDE_DIR ALSA_LIBRARY)

Переменные ALSA_LIBRARY и ALSA_INCLUDE_DIR настраиваются пользователем и сохраняются в кеше, тогда как ALSA_LIBRARIES и ALSA_INCLUDE_DIRS, а также ALSA_FOUND вычисляются и являются теми, которые предполагается пользователю модуля find для использования.

Обычно можно использовать модуль find следующим образом:

find_package(ALSA REQUIRED)
include_directories(${ALSA_INCLUDE_DIRS})
target_link_libraries(myexe ${ALSA_LIBRARIES})

Я уверен, что вы можете адаптировать это для своей личной библиотеки.

Ответ 2

Обычно, если вы хотите связать с библиотекой, у которой нет модуля find_package (например, это необычная библиотека или ваша собственная библиотека), вы можете использовать основные команды (команды find_X) для установки переменных с пути, которые вам нужны. Затем вы используете эти переменные как с find_package (include_directories, target_link_libraries).

Если вы собираетесь использовать эту библиотеку из нескольких пакетов, вам может понадобиться создать модуль find_package; в основном, используя те же команды с определенными соглашениями.

Любой из них позволяет вам указывать пути (в модуле CMake) для просмотра, и они позволяют пользователю переопределять пути (переменные отображаются как параметры в ccmake/cmake-gui).

Я был бы рад добавить пример одного или обоих этих методов, просто дайте мне знать, что вы ищете.

Если вам просто нужно быстрое и грязное решение, вы можете это сделать, но я бы не рекомендовал его:

include_directories(/perso/testlib/include)
add_executable(myexecutable myexecutable.cpp)
target_link_libraries(myexecutable
    /perso/testlib/lib/testlib1.a
    /perso/testlib/lib/testlib2.a)

Что касается вашего вопроса о target_link_libraries (# 5), вы можете сделать это несколькими способами. Если вы хотите, вы можете предоставить полное имя (например, target_link_libraries(myexe libfoo.a)), но я думаю, что лучше (более портативный, я полагаю) использовать короткое имя (например, target_link_libraries(myexe foo). Вы также можете использовать флаги компоновщика; Я не уверен, где я его читаю, но я думаю, что он может переводить флаги -L и -l для разных компоновщиков.

Например, если у меня есть группа библиотек в том же каталоге, и я знаю имена, я могу найти каталог, сохранить его в переменной и затем сделать это:

# First, find and set TESTLIB_LIBRARY_DIR, e.g. with find_path
# ...

# This assumes the libraries are e.g. 'libtestlib1.a' and 'libtestlib2.a'
set(TESTLIB_LIBRARIES
    -L${TESTLIB_LIBRARY_DIR)
    -l testlib1
    -l testlib2)

add_executable(myexecutable myexecutable.cpp)
target_link_libraries(myexecutable ${TESTLIB_LIBRARIES})

Если вы хотите создать свой собственный модуль find_package (например, упомянутые trenki, FindALSA.cmake кажется хорошей отправной точкой), вы можете использовать его, добавив каталог в CMAKE_MODULE_PATH; например, если вы поместите свой модуль в подкаталог cmake/modules/:

# Look for extra CMake modules in a subdirectory of this project
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules/" ${CMAKE_MODULE_PATH})

Одна из возможных проблем с FindALSA.cmake: я не уверен, что CMAKE_CURRENT_LIST_DIR будет работать. Поэтому я думаю, что вы должны сделать это изменение (вторая работа для меня в модуле, который я написал):

# Change this line
include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)

# To this (with no path/extension it will search the CMake modules path):
include(FindPackageHandleStandardArgs)

И чтобы получить использование FIND_PACKAGE_HANDLE_STANDARD_ARGS, посмотрите FindPackageHandleStandardArgs.cmake в каталоге CMake Modules.

Ответ 3

CMake имеет хорошую документацию.

  • Статическая связь (если я понимаю вас правильно) архивируется передачей ключевого слова STATIC add_library
  • Я бы посоветовал не делать этого (я не эксперт CMake), но похоже, что расходы будут большими.
  • Нет никакой разницы, ${MYVARIABLE_INCLUDE_DIR} ist просто имя переменной, которое вы хотите. Но я предлагаю вам следовать соглашению об именах.
  • Одна библиотека всегда является одним файлом .lib/.a, поэтому не должно быть никаких проблем, просто используйте add_library & target_link_libraries & add_dependencies.
  • Имя библиотеки - это имя, которое вы переходите в add_library. Однако Gmp или gMP будут такими же, как CMake - это интенсивность случая.