Всем привет!
Решил развивать свой блог делясь своим опытом.
Я, как и многие другие, столкнулся с проблемой: к проекту надо подключить библиотеку, которой может и не быть на компьютере, на котором будет установлена программа. А может она будет, но не той версии. Может гораздо более старой версии, возможностей которой вам не хватит. Что мы можем сделать? Как мне кажется, довольно эффективным решением является статическая линковка со своей программой. А чтобы не раздувать своей проект исходниками сторонних библиотек, мы можем таскать их архив. Если думать в контексте CMake, то мы можем указывать URL на архив или даже ссылку на ветку в git репозитарии, что гораздо удобнее. Но тут нам CMake преподносит неприятный сюрприз. Во время сборки проекта, мы не сможем заставить CMake указать собрать сторонний проект раньше, чем он соберёт наш. Например, пытаясь слинковаться со сторонним проектом с помощью CMake, он скорее всего выдаст ошибку, потому что он соберёт ваш проект быстрее и не найдёт библиотеки для линковки или не найдёт нужные заголовочные файлы для вашего проекта. Предположим, что мы выбрали следующую иерархию каталогов:
Решил развивать свой блог делясь своим опытом.
Я, как и многие другие, столкнулся с проблемой: к проекту надо подключить библиотеку, которой может и не быть на компьютере, на котором будет установлена программа. А может она будет, но не той версии. Может гораздо более старой версии, возможностей которой вам не хватит. Что мы можем сделать? Как мне кажется, довольно эффективным решением является статическая линковка со своей программой. А чтобы не раздувать своей проект исходниками сторонних библиотек, мы можем таскать их архив. Если думать в контексте CMake, то мы можем указывать URL на архив или даже ссылку на ветку в git репозитарии, что гораздо удобнее. Но тут нам CMake преподносит неприятный сюрприз. Во время сборки проекта, мы не сможем заставить CMake указать собрать сторонний проект раньше, чем он соберёт наш. Например, пытаясь слинковаться со сторонним проектом с помощью CMake, он скорее всего выдаст ошибку, потому что он соберёт ваш проект быстрее и не найдёт библиотеки для линковки или не найдёт нужные заголовочные файлы для вашего проекта. Предположим, что мы выбрали следующую иерархию каталогов:
+-- 3-rd_party
\-- lib.zip
+-- Build
+-- CMakeLists.txt
+-- include
\-- main.hpp
+-- source
\-- main.cpp
Для того, чтобы задать порядок сборки, указать зависимость нашего проекта, от того, который мы подключаем через ExternalProjectAdd, нам надо добавить ещё одну цель:
\-- lib.zip
+-- Build
+-- CMakeLists.txt
+-- include
\-- main.hpp
+-- source
\-- main.cpp
add_library(lib-static STATIC IMPORTED)
#не всегда требуется, но иногда, когда вы используете С++, может понадобиться
set_target_properties(event-static PROPERTIES LINKER_LANGUAGE C)
#указываем расположение библиотеки
set_target_properties(lib-static PROPERTIES IMPORTED_LOCATION
"${CMAKE_BINARY_DIR}/3-rd_party/Libevent-2.1.5-beta/lib/${CMAKE_STATIC_LIBRARY_PREFIX}event${CMAKE_STATIC_LIBRARY_SUFFIX}"
)
#решение проблемы, которое заставит собрать сторонний проект раньше вашего:
add_dependencies(lib-static ep_lib)
ep_lib это идентификатор объявленный в вызове ExternalProjectAdd. После этого мы можем добавлять цель по сборке нашего бинарника, и команду линковки:
add_executable(${PROJECT_NAME} ${SRC_LIST})
target_link_libraries (${PROJECT_NAME} lib-static)
Вот пример полного сценария, как можно подключить библиотеку к своему проекту.
Тут указаны флаги о подключении статической библиотеки C++ и указание компилятору использовать свежий стандарт С++11.
${CMAKE_STATIC_LIBRARY_PREFIX} и ${CMAKE_STATIC_LIBRARY_SUFFIX} использованы для переносимости. Под разными платформами библиотеки объявляются по-разному, например, в windows статическая библиотека может быть такой: library.lib, а под GNU/linux liblibrary.a
Для динамических библиотек константы такие ${CMAKE_SHARED_LIBRARY_PREFIX} и ${CMAKE_SHARED_LIBRARY_SUFFIX}.
project(exam)
cmake_minimum_required(VERSION 3.0)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(CMAKE_EXE_LINKER_FLAGS "-static-libstdc++")
include(ExternalProject)
aux_source_directory(./source SRC_LIST)
ExternalProject_Add(
ep_lib
URL ${CMAKE_CURRENT_SOURCE_DIR}/3-rd_party/lib.zip
SOURCE_DIR ${CMAKE_BINARY_DIR}/3-rd_party/lib-SOURCES/
BUILD_IN_SOURCE 1
INSTALL_DIR ${CMAKE_BINARY_DIR}/3-rd_party/lib/
CMAKE_ARGS -DCMAKE_BUILD_TYPE=Debug
CMAKE_CACHE_ARGS -DBUILD_TESTING:BOOL=ON
-DEVENT__DISABLE_SAMPLES:BOOL=OFF
-DCMAKE_INSTALL_PREFIX:STRING=${CMAKE_BINARY_DIR}/3-rd_party/lib/
)
add_library(lib-static STATIC IMPORTED)
set_target_properties(lib-static PROPERTIES LINKER_LANGUAGE C)
set_target_properties(lib-static PROPERTIES IMPORTED_LOCATION
"${CMAKE_BINARY_DIR}/3-rd_party/lib/lib/${CMAKE_STATIC_LIBRARY_PREFIX}lib${CMAKE_STATIC_LIBRARY_SUFFIX}"
)
add_dependencies(lib-static ep_libevent)
include_directories("${CMAKE_BINARY_DIR}/3-rd_party/Libevent-2.1.5-beta/include/")
add_executable(${PROJECT_NAME} ${SRC_LIST})
target_link_libraries (${PROJECT_NAME} lib-static)