CMake-链接到从ExternalProject_add()下载的库
我正在尝试使用ExternalProject_add()下载/安装依赖项。它安装得很好,但我不知道如何在下载库之后链接它们 我想在刚下载的库上调用target_link_libraries(),但是库的路径会因系统而异 如果这是一个系统依赖项,我可以调用find_package()-但是包没有安装在默认的搜索路径上。我认为您不能在模块模式下为find_包指定搜索路径 下面是我的CMakeLists.txt的一个片段,它不起作用:CMake-链接到从ExternalProject_add()下载的库,cmake,external-project,Cmake,External Project,我正在尝试使用ExternalProject_add()下载/安装依赖项。它安装得很好,但我不知道如何在下载库之后链接它们 我想在刚下载的库上调用target_link_libraries(),但是库的路径会因系统而异 如果这是一个系统依赖项,我可以调用find_package()-但是包没有安装在默认的搜索路径上。我认为您不能在模块模式下为find_包指定搜索路径 下面是我的CMakeLists.txt的一个片段,它不起作用: ExternalProject_Add( protobuf URL
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})
ExternalProject\u添加(
protobuf
统一资源定位地址http://protobuf.googlecode.com/files/protobuf-2.4.1.tar.gz
CONFIGURE_命令/CONFIGURE--prefix=
前缀${MYPROJ_SOURCE_DIR}/dependencies
)
查找_包(需要protobuf)
集合(LIBS${LIBS}${PROTOBUF_库})
目标链接库(mybinary${LIBS})
当您使用ExternalProject\u Add时,您不能使用find\u软件包,因为当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_包方便。如果您可以使用预构建/预安装的软件包,那么您应该这样做,以便可以使用find_软件包。但是,如果您必须从源代码构建另一个包作为项目的一部分,那么ExternalProject\u Add非常有用,即使它无法为您提取所有详细信息。您可以使用link\u 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)
您可以使用另一个成语来解决此问题:
您可以在中看到这一习惯用法。要扩展上面的DLRdave答案,您不需要为静态库手动设置前缀和后缀,因为CMAKE为每个平台提供了正确的变量 有关更多信息,请参阅 例如:
- CMAKE_共享_库_前缀
- CMAKE_共享_库_后缀
- CMAKE_静态_库_前缀
- CMAKE_静态_库_后缀
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)
从这里开始,依赖它的每个程序都需要一个添加依赖项
,当然还有目标链接库
。例如:
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_目录-告诉它在那里搜索目录
- target_link_库-只需添加您命名的库(不是变量)
这对我来说很有用。与make-j4一起工作。让所有依赖项都正确无误。您可以使用
find\u package
和ExternalProject\u 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)
####################################################################################################
谢谢,这真的很有帮助。另外,为了不引起混淆,protobuf没有变量库位置,但是R有。cmake为您的平台提供前缀和后缀变量:
“${install_dir}/lib/${cmake_SHARED_MODULE_prefix}protobufLib1${cmake_SHARED_library_suffix}”
虽然这样做很有效,但我觉得很糟糕。如果我必须编写平台条件代码,那么使用cmake有什么意义?此外,我希望ExternalProject提供一种简单的方法来导入构建的目标,如果以后无法轻松导入它们,为什么我要构建一个外部项目呢?重点是什么?我遗漏了什么吗?你没有遗漏任何@Jens,但是这个场景不是在CMake中正常使用ExternalProject。事实上,我建议不要这样做。典型的场景是全部ExternalProject,或者没有ExternalProject,而不是一些外部的,一些不是的混合情况。当ExternalProject在所谓的“超级构建”场景中构建/安装所有组件时,以后构建的组件可以使用find_包来查找早期构建/安装的组件。这是使用ExternalProject的推荐方法。我觉得实际的link\u目录
string应该更长,因为在我的例子中,我在lib下看到了类似MyExternalLibrary build/lib的内容。我尝试过这种技术,但在新的构建中它不起作用。您收到错误(找不到您的库)。由于cmake 3.2,您可以使用UPDATE_DISCONNECTED来避免自动更新。如果需要,您仍然可以添加自定义目标进行更新。它如何知道ForexConnect
?这里的示例add\u library(ForexConnect SHARED IMPORTED)
真是一个很棒的解决方案,它甚至超越了简单的区分,管理依赖项和链接。看起来像一个优雅的解决方案。它适用于make
,但不适用于ninja
。对于后者,您必须使用生成文件的路径设置外部项目的BUILD\u BYPRODUCTS
属性。若并没有,忍者会尖叫着说它找不到你们的藏书室。@Lamda只是为了不让它不被回答:它并没有