Как создать общую библиотеку с cmake?
Я написал библиотеку, которую я использовал для компиляции с помощью самописного файла Makefile, но теперь я хочу переключиться на cmake. Дерево выглядит так (я удалил все ненужные файлы):
.
├── include
│ ├── animation.h
│ ├── buffers.h
│ ├── ...
│ ├── vertex.h
│ └── world.h
└── src
├── animation.cpp
├── buffers.cpp
├── ...
├── vertex.cpp
└── world.cpp
Так что я пытаюсь сделать, это просто скомпилировать исходный код в общую библиотеку, а затем установить его с заголовочных файлов.
большинство примеров, которые я нашел, компилируют исполняемые файлы с некоторыми общими библиотеками, но никогда не просто общей библиотекой.
Это также было бы полезно если кто-то может просто сказать мне очень простую библиотеку, которая использует cmake, поэтому я могу использовать это в качестве примера.
4 ответов:
всегда указывайте минимально необходимую версию
cmakecmake_minimum_required(VERSION 3.9)вы должны объявить проект.
cmakeговорит, что это обязательно, и он будет определять удобные переменныеPROJECT_NAME,PROJECT_VERSIONиPROJECT_DESCRIPTION(эта последняя переменная требует cmake 3.9):project(mylib VERSION 1.0.1 DESCRIPTION "mylib description")объявить новую цель библиотеки. Пожалуйста, избегайте использования
file(GLOB ...). Эта функция не обеспечивает участие мастерство процесса компиляции. Если вы ленивы, скопируйте-вставьте выводls -1 sources/*.cpp:add_library(mylib SHARED sources/animation.cpp sources/buffers.cpp [...] )Set
VERSIONсвойство (необязательно, но это хорошая практика):set_target_properties(mylib PROPERTIES VERSION ${PROJECT_VERSION})вы также можете установить
SOVERSIONк большому числуVERSION. Так чтоlibmylib.so.1будет символическая ссылка наlibmylib.so.1.0.0.set_target_properties(mylib PROPERTIES SOVERSION 1)объявить публичный API вашей библиотеки. Этот API будет установлен для сторонних приложений. Это хорошая практика, чтобы изолировать его в дереве проекта (например, поместив его ). Обратите внимание, что частные заголовки не должны быть установлены и я настоятельно рекомендую разместить их с исходными файлами.
set_target_properties(mylib PROPERTIES PUBLIC_HEADER include/mylib.h)если вы работаете с подкаталогами, не очень удобно включать относительный путь, например
"../include/mylib.h". Итак, передайте верхнюю директорию в включенные каталоги:target_include_directories(mylib PRIVATE .)или
target_include_directories(mylib PRIVATE include) target_include_directories(mylib PRIVATE src)Создать правило установки для вашей библиотеки. Я предлагаю использовать переменные
CMAKE_INSTALL_*DIRопределена вGNUInstallDirs:include(GNUInstallDirs)и объявить файлы для установки:
install(TARGETS mylib LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})вы можете также экспорт . Эти файлы позволяют стороннему приложению легко импортировать вашу библиотеку:
- С помощью Makefile, см.
pkg-config- С Autotools, см.
PKG_CHECK_MODULES- С cmake, см.
pkg_check_modulesсоздать файл шаблона с именем
mylib.pc.in(см. pc (5) manpage для получения дополнительной информации):prefix=@CMAKE_INSTALL_PREFIX@ exec_prefix=@CMAKE_INSTALL_PREFIX@ libdir=${exec_prefix}/@CMAKE_INSTALL_LIBDIR@ includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@ Name: @PROJECT_NAME@ Description: @PROJECT_DESCRIPTION@ Version: @PROJECT_VERSION@ Requires: Libs: -L${libdir} -lmylib Cflags: -I${includedir}в вашей
CMakeLists.txt, добавьте правило для расширения@макросы (@ONLYзадать для CMake, чтобы не расширить переменных вида${VAR}):configure_file(mylib.pc.in mylib.pc @ONLY)и, наконец, установите сгенерированный файл:
install(FILES ${CMAKE_BINARY_DIR}/mylib.pc DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig)вы также можете использовать cmake
EXPORTхарактеристика. Однако, эта функция совместима только сcmakeи я считаю, что это трудно использовать.наконец, все
CMakeLists.txtдолжно выглядеть так:cmake_minimum_required(VERSION 3.9) project(mylib VERSION 1.0.1 DESCRIPTION "mylib description") include(GNUInstallDirs) add_library(mylib SHARED src/mylib.c) set_target_properties(mylib PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION 1 PUBLIC_HEADER api/mylib.h) configure_file(mylib.pc.in mylib.pc @ONLY) target_include_directories(mylib PRIVATE .) install(TARGETS mylib LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) install(FILES ${CMAKE_BINARY_DIR}/mylib.pc DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig)
Это минимальные CMakeLists.txt файл компилирует простую общую библиотеку:
cmake_minimum_required(VERSION 2.8) project (test) set(CMAKE_BUILD_TYPE Release) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) add_library(test SHARED src/test.cpp)однако у меня нет опыта копирования файлов в другое место назначения с помощью CMake. Команда file с подписью COPY/INSTALL выглядит так, как будто это может быть полезно.
Я пытаюсь узнать, как это сделать сам, и, кажется, вы можете установить библиотеку следующим образом:
cmake_minimum_required(VERSION 2.4.0) project(mycustomlib) # Find source files file(GLOB SOURCES src/*.cpp) # Include header files include_directories(include) # Create shared library add_library(${PROJECT_NAME} SHARED ${SOURCES}) # Install library install(TARGETS ${PROJECT_NAME} DESTINATION lib/${PROJECT_NAME}) # Install library headers file(GLOB HEADERS include/*.h) install(FILES ${HEADERS} DESTINATION include/${PROJECT_NAME})
во-первых, это макет каталога, который я использую:
. ├── include │ ├── class1.hpp │ ├── ... │ └── class2.hpp └── src ├── class1.cpp ├── ... └── class2.cppчерез пару дней, взглянув на это, это мой любимый способ сделать это благодаря современному CMake:
cmake_minimum_required(VERSION 3.5) project(mylib VERSION 1.0.0 LANGUAGES CXX) set(DEFAULT_BUILD_TYPE "Release") if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) message(STATUS "Setting build type to '${DEFAULT_BUILD_TYPE}' as none was specified.") set(CMAKE_BUILD_TYPE "${DEFAULT_BUILD_TYPE}" CACHE STRING "Choose the type of build." FORCE) # Set the possible values of build type for cmake-gui set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") endif() include(GNUInstallDirs) set(SOURCE_FILES src/class1.cpp src/class2.cpp) target_include_directories(${PROJECT_NAME} PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> $<INSTALL_INTERFACE:include> PRIVATE src) set_target_properties(${PROJECT_NAME} PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION 1) install(TARGETS ${PROJECT_NAME} EXPORT MyLibConfig ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}) install(EXPORT MyLibConfig DESTINATION share/MyLib/cmake) export(TARGETS ${PROJECT_NAME} FILE MyLibConfig.cmake)после запуска CMake и установки библиотеки нет необходимости использовать Find***.cmake файлы, он может быть использован следующим образом:
find_package(MyLib REQUIRED) #No need to perform include_directories(...) target_link_libraries(${TARGET} mylib)вот и все, если он был установлен в стандартном каталоге он будет найден и нет необходимости делать что-либо еще. Если это был установлен в нестандартном пути, это также легко, просто скажите CMake, где найти MyLibConfig.cmake с помощью:
cmake -DMyLib_DIR=/non/standard/install/path ..Я надеюсь, что это помогает всем так же, как это помогло мне. Старые способы сделать это были довольно громоздкими.
Comments