CMake - ссылка на библиотеку, загруженную из ExternalProject_add()
Я пытаюсь использовать ExternalProject_add() для загрузки / установки зависимостей. Устанавливается нормально, но я не могу понять, как на самом деле связать библиотеки после их загрузки.
Я хочу вызвать target_link_libraries() для библиотеки, которая была только что загружена, но путь к библиотеке будет зависеть от системы.
Если бы это была системная зависимость, я мог бы просто вызвать find_package() - но пакеты не были установлены в пути поиска по умолчанию. Я не думаю, что вы можете указать путь поиска для find_package в режиме модуля.
Вот фрагмент моего CMakeLists.txt, который не работает:
ExternalProject_Add(
protobuf
URL http://protobuf.googlecode.com/files/protobuf-2.4.1.tar.gz
CONFIGURE_COMMAND <SOURCE_DIR>/configure --prefix=<INSTALL_DIR>
PREFIX ${MYPROJ_SOURCE_DIR}/dependencies
)
find_package(protobuf REQUIRED)
set(LIBS ${LIBS} ${PROTOBUF_LIBRARIES})
target_link_libraries (mybinary ${LIBS})
6 ответов
Когда вы используете ExternalProject_Add, вы не можете использовать find_package, так как при запуске CMake для настройки внешнего проекта нечего искать.
Таким образом, если расположение библиотек зависит от платформы, вам потребуется условная логика, основанная на вашей платформе. (Я не знаю библиотек или структуры protobuf здесь, так что это всего лишь пример, но он должен направить вас в правильном направлении...) Примерно так:
if(WIN32)
set(PROTOBUF_LIB_DIR "${MYPROJ_SOURCE_DIR}/dependencies/win"
set(prefix "")
set(suffix ".lib")
elseif(APPLE)
set(PROTOBUF_LIB_DIR "${MYPROJ_SOURCE_DIR}/dependencies/mac"
set(prefix "lib")
set(suffix ".a")
else()
set(PROTOBUF_LIB_DIR "${MYPROJ_SOURCE_DIR}/dependencies/linux"
set(prefix "lib")
set(suffix ".a")
endif()
set(PROTOBUF_LIBRARIES
"${PROTOBUF_LIB_DIR}/${prefix}protobufLib1${suffix}"
"${PROTOBUF_LIB_DIR}/${prefix}protobufLib2${suffix}")
Конечно, это менее удобно, чем использование find_package. Если вы можете использовать предварительно собранный / предварительно установленный пакет, вы должны, чтобы вы могли использовать find_package. Если вам необходимо собрать другой пакет из исходного кода как часть вашего проекта, то ExternalProject_Add будет полезен, даже если он не сможет абстрагировать все детали для вас.
Поскольку вы загружаете внешний проект, вы уже знаете, где все находится, потому что вы только что загрузили его, поэтому он не нуждается в "поиске".
Я получил это работает с add_library. Это мой настоящий код, который работает:
ExternalProject_Add(ForexConnectDownload
PREFIX 3rd_party
#--Download step--------------
URL http://fxcodebase.com/bin/forexconnect/1.3.1/ForexConnectAPI-1.3.1-Linux-x86_64.tar.gz
URL_HASH SHA1=7fdb90a2d45085feb8b76167cae419ad4c211d6b
#--Configure step-------------
CONFIGURE_COMMAND ""
#--Build step-----------------
BUILD_COMMAND ""
#--Install step---------------
UPDATE_COMMAND "" # Skip annoying updates for every build
INSTALL_COMMAND ""
)
SET(FXCM_INCLUDE_DIR ${CMAKE_CURRENT_BINARY_DIR}/3rd_party/src/ForexConnectDownload/include)
SET(FXCM_LIB_DIR ${CMAKE_CURRENT_BINARY_DIR}/3rd_party/src/ForexConnectDownload/lib)
add_library(ForexConnect SHARED IMPORTED)
set_target_properties(ForexConnect PROPERTIES IMPORTED_LOCATION ${FXCM_LIB_DIR}/libForexConnect.so)
Оттуда каждая программа, которая зависит от нее, нуждается в add_dependencies
и конечно target_link_libraries
, Например:
include_directories(${FXCM_INCLUDE_DIR})
add_executable(syncDatabase syncDatabase.cpp trader/database.cpp trader/fxcm.cpp)
target_link_libraries(syncDatabase ForexConnect)
add_dependencies(syncDatabase ForexConnectDownload)
- include_directories - говорит ему искать там каталоги
- target_link_libraries - просто добавьте свою библиотеку, как вы ее назвали (не переменная)
Add_dependencies заставляет его ждать, прежде чем включать необходимые каталоги.
Это делает трюк для меня. Работает с make -j4. Получите все зависимости правильно.
Чтобы расширить ответ DLRdave выше, вам не нужно устанавливать префиксы и суффиксы для статических библиотек вручную, потому что CMAKE предоставляет переменные с правильными для каждой платформы.
См. Полезные переменные CMake для получения дополнительной информации.
Например:
- CMAKE_SHARED_LIBRARY_PREFIX
- CMAKE_SHARED_LIBRARY_SUFFIX
- CMAKE_STATIC_LIBRARY_PREFIX
- CMAKE_STATIC_LIBRARY_SUFFIX
Вы можете использовать команду link_directories для связывания библиотек в определенном каталоге. В вашем случае каталог, где ваш внешний проект является сборкой.
ExternalProject_Add(MyExternalLibrary ...)
Добавьте выходной каталог в путь поиска:
link_directories(${CMAKE_BINARY_DIR}/lib/MyExternalLibrary-prefix/lib)
Обязательно добавьте исполняемый файл после указания каталога ссылок:
add_executable(MyProgram main.c)
Укажите библиотеки, с которыми должен быть связан ваш проект:
target_link_libraries(MyProgram ExternalLibraryName)
Не забудьте зависеть от внешнего проекта:
add_dependencies(MyProgram MyExternalLibrary)
Еще одна идиома, которую вы можете использовать для решения этой проблемы:
- Сделайте ваши команды find_package необязательными (удалите 'REQUIRED')
- Добавьте некоторый код условия, чтобы построить свои цели только в том случае, если find_package завершится успешно.
- find_package потерпит неудачу, и ваши цели не будут созданы в первый раз, но будут построены внешние проекты.
- Запустите cmake / make снова, на этот раз find_package будет успешным, и ваши цели будут построены.
Вы можете увидеть эту идиому в действии на https://github.com/biometrics/likely.
Вы можете использовать find_package
с ExternalProject_add
как в следующем фрагменте кода:
# --------------------------------------------------
function (build_external_project target file_name)
set(CMAKELIST_CONTENT "
cmake_minimum_required(VERSION ${CMAKE_MINIMUM_REQUIRED_VERSION})
project(build_external_project)
file(MD5 \"${file_name}\" FILE_HASH)
include(ExternalProject)
ExternalProject_add(${target}
URL \"${file_name}\"
URL_MD5 \${FILE_HASH}
CMAKE_GENERATOR \"${CMAKE_GENERATOR}\"
CMAKE_GENERATOR_PLATFORM \"${CMAKE_GENERATOR_PLATFORM}\"
CMAKE_GENERATOR_TOOLSET \"${CMAKE_GENERATOR_TOOLSET}\"
CMAKE_GENERATOR_INSTANCE \"${CMAKE_GENERATOR_INSTANCE}\"
CMAKE_ARGS ${ARGN})
add_custom_target(build_external_project)
add_dependencies(build_external_project ${target})
")
set(TARGET_DIR "${CMAKE_CURRENT_BINARY_DIR}/ExternalProjects/${target}")
file(WRITE "${TARGET_DIR}/CMakeLists.txt" "${CMAKELIST_CONTENT}")
file(MAKE_DIRECTORY "${TARGET_DIR}" "${TARGET_DIR}/build")
execute_process(COMMAND ${CMAKE_COMMAND}
-G "${CMAKE_GENERATOR}"
-A "${CMAKE_GENERATOR_PLATFORM}"
-T "${CMAKE_GENERATOR_TOOLSET}"
..
WORKING_DIRECTORY "${TARGET_DIR}/build")
execute_process(COMMAND ${CMAKE_COMMAND}
--build .
--config ${CMAKE_BUILD_TYPE}
WORKING_DIRECTORY "${TARGET_DIR}/build")
endfunction()
#----------------------------------------------------------------------------------------------------
set(THIDR_PARTY_DIR "${CMAKE_CURRENT_LIST_DIR}")
set(THIDR_PARTY_INSTALL_DIR "${CMAKE_CURRENT_BINARY_DIR}/ThirdParty")
#----------------------------------------------------------------------------------------------------
# OpenCV.
set(OPENCV_OPTIONS "")
list(APPEND OPENCV_OPTIONS -D WITH_1394=ON)
list(APPEND OPENCV_OPTIONS -D WITH_ADE=ON)
list(APPEND OPENCV_OPTIONS -D WITH_CUDA=OFF)
list(APPEND OPENCV_OPTIONS -D WITH_EIGEN=ON)
list(APPEND OPENCV_OPTIONS -D WITH_FFMPEG=ON)
list(APPEND OPENCV_OPTIONS -D WITH_IPP=ON)
list(APPEND OPENCV_OPTIONS -D WITH_ITT=ON)
list(APPEND OPENCV_OPTIONS -D WITH_JASPER=ON)
list(APPEND OPENCV_OPTIONS -D WITH_JPEG=ON)
list(APPEND OPENCV_OPTIONS -D WITH_OPENCL=ON)
list(APPEND OPENCV_OPTIONS -D WITH_OPENEXR=ON)
list(APPEND OPENCV_OPTIONS -D WITH_OPENJPEG=ON)
list(APPEND OPENCV_OPTIONS -D WITH_PNG=ON)
list(APPEND OPENCV_OPTIONS -D WITH_PROTOBUF=ON)
list(APPEND OPENCV_OPTIONS -D WITH_QT=OFF)
list(APPEND OPENCV_OPTIONS -D WITH_TBB=ON)
list(APPEND OPENCV_OPTIONS -D WITH_TIFF=ON)
list(APPEND OPENCV_OPTIONS -D WITH_WEBP=ON)
list(APPEND OPENCV_OPTIONS -D BUILD_CUDA_STUBS=OFF)
list(APPEND OPENCV_OPTIONS -D BUILD_DOCS=OFF)
list(APPEND OPENCV_OPTIONS -D BUILD_EXAMPLES=OFF)
list(APPEND OPENCV_OPTIONS -D BUILD_IPP_IW=ON)
list(APPEND OPENCV_OPTIONS -D BUILD_ITT=ON)
list(APPEND OPENCV_OPTIONS -D BUILD_JASPER=ON)
list(APPEND OPENCV_OPTIONS -D BUILD_JAVA=OFF)
list(APPEND OPENCV_OPTIONS -D BUILD_JPEG=ON)
list(APPEND OPENCV_OPTIONS -D BUILD_OPENEXR=ON)
list(APPEND OPENCV_OPTIONS -D BUILD_PACKAGE=OFF)
list(APPEND OPENCV_OPTIONS -D BUILD_PERF_TESTS=OFF)
list(APPEND OPENCV_OPTIONS -D BUILD_PNG=ON)
list(APPEND OPENCV_OPTIONS -D BUILD_PROTOBUF=ON)
list(APPEND OPENCV_OPTIONS -D BUILD_TBB=ON)
list(APPEND OPENCV_OPTIONS -D BUILD_TESTS=OFF)
list(APPEND OPENCV_OPTIONS -D BUILD_TIFF=ON)
list(APPEND OPENCV_OPTIONS -D BUILD_WEBP=ON)
list(APPEND OPENCV_OPTIONS -D BUILD_ZLIB=ON)
list(APPEND OPENCV_OPTIONS -D BUILD_opencv_apps=OFF)
list(APPEND OPENCV_OPTIONS -D BUILD_opencv_java_bindings_generator=OFF)
list(APPEND OPENCV_OPTIONS -D BUILD_opencv_js=OFF)
list(APPEND OPENCV_OPTIONS -D BUILD_opencv_python_bindings_generator=OFF)
list(APPEND OPENCV_OPTIONS -D BUILD_opencv_python_tests=OFF)
list(APPEND OPENCV_OPTIONS -D BUILD_opencv_world=OFF)
list(APPEND OPENCV_OPTIONS -D OPENCV_ENABLE_NONFREE=OFF)
list(APPEND OPENCV_OPTIONS -D OPENCV_FORCE_3RDPARTY_BUILD=ON)
list(APPEND OPENCV_OPTIONS -D BUILD_WITH_STATIC_CRT=OFF)
list(APPEND OPENCV_OPTIONS -D CMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE})
list(APPEND OPENCV_OPTIONS -D CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE})
list(APPEND OPENCV_OPTIONS -D CMAKE_POSITION_INDEPENDENT_CODE=ON)
list(APPEND OPENCV_OPTIONS -D BUILD_SHARED_LIBS=OFF)
list(APPEND OPENCV_OPTIONS -D CMAKE_INSTALL_PREFIX=${THIDR_PARTY_INSTALL_DIR}/OpenCV)
build_external_project(OpenCV "${THIDR_PARTY_DIR}/OpenCV/opencv-4.3.0+cache.zip" ${OPENCV_OPTIONS})
set(OpenCV_STATIC ON)
#----------------------------------------------------------------------------------------------------
# Dlib.
set(DLIB_OPTIONS "")
list(APPEND DLIB_OPTIONS -D USE_SSE2_INSTRUCTIONS=ON)
list(APPEND DLIB_OPTIONS -D USE_SSE4_INSTRUCTIONS=ON)
list(APPEND DLIB_OPTIONS -D USE_AVX_INSTRUCTIONS=ON)
list(APPEND DLIB_OPTIONS -D DLIB_GIF_SUPPORT=ON)
list(APPEND DLIB_OPTIONS -D DLIB_JPEG_SUPPORT=ON)
list(APPEND DLIB_OPTIONS -D DLIB_PNG_SUPPORT=ON)
list(APPEND DLIB_OPTIONS -D DLIB_USE_BLAS=ON)
list(APPEND DLIB_OPTIONS -D DLIB_USE_CUDA=OFF)
list(APPEND DLIB_OPTIONS -D DLIB_USE_LAPACK=ON)
list(APPEND DLIB_OPTIONS -D DLIB_USE_MKL_FFT=OFF)
list(APPEND DLIB_OPTIONS -D DLIB_LINK_WITH_SQLITE3=OFF)
list(APPEND DLIB_OPTIONS -D DLIB_NO_GUI_SUPPORT=OFF)
list(APPEND DLIB_OPTIONS -D DLIB_ENABLE_ASSERTS=OFF)
list(APPEND DLIB_OPTIONS -D DLIB_ENABLE_STACK_TRACE=OFF)
list(APPEND DLIB_OPTIONS -D CMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE})
list(APPEND DLIB_OPTIONS -D CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE})
list(APPEND DLIB_OPTIONS -D CMAKE_POSITION_INDEPENDENT_CODE=ON)
list(APPEND DLIB_OPTIONS -D BUILD_SHARED_LIBS=OFF)
list(APPEND DLIB_OPTIONS -D CMAKE_INSTALL_PREFIX=${THIDR_PARTY_INSTALL_DIR}/dlib)
build_external_project(dlib ${THIDR_PARTY_DIR}/Dlib/dlib-19.20.tar.bz2 ${DLIB_OPTIONS})
#----------------------------------------------------------------------------------------------------
####################################################################################################
# Now, you can use find_package:
find_package(OpenCV REQUIRED PATHS "${THIDR_PARTY_INSTALL_DIR}/OpenCV" NO_DEFAULT_PATH)
find_package(dlib REQUIRED PATHS "${THIDR_PARTY_INSTALL_DIR}/dlib" NO_DEFAULT_PATH)
####################################################################################################
https://gist.github.com/amir-saniyan/4339e6f3ef109c75eda8018f7d5192a7
Вы можете запросить свойства внешнего проекта, такие как source_dir
или же binary_dir
по ExternalProject_Get_Property.binary_dir
может быть подсказкой для find_package, в то время как путь к заголовкам может быть получен из source_dir
, В случае protobuf заголовки находятся в ${source_dir}/src
,
Вот мое решение:
ExternalProject_Add(
protobuf-external
PREFIX protobuf
URL https://github.com/google/protobuf/archive/v3.6.0.tar.gz
BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/protobuf
CMAKE_CACHE_ARGS
"-Dprotobuf_BUILD_TESTS:BOOL=OFF"
"-Dprotobuf_BUILD_EXAMPLES:BOOL=OFF"
"-Dprotobuf_WITH_ZLIB:BOOL=OFF"
SOURCE_SUBDIR cmake
BUILD_ALWAYS 1
STEP_TARGETS build
INSTALL_COMMAND ""
)
ExternalProject_Get_Property(protobuf-external source_dir)
ExternalProject_Get_Property(protobuf-external binary_dir)
find_package(protobuf HINTS ${binary_dir})
include_directories(${source_dir}/src)