【问题标题】:CMake - linking to library downloaded from ExternalProject_add()CMake - 链接到从 ExternalProject_add() 下载的库
【发布时间】:2011-09-15 03:33:34
【问题描述】:

我正在尝试使用 ExternalProject_add() 下载/安装依赖项。它安装得很好,但我不知道下载后如何实际链接库。

我想在刚刚下载的库上调用 target_link_libraries(),但是库的路径会因系统而异。

如果这是系统依赖项,我可以调用 find_package() - 但这些包并未安装在默认搜索路径上。我认为您不能在模块模式下为 find_package 指定搜索路径。

这是我的 CMakeLists.txt 的一个 sn-p,它不起作用:

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})

【问题讨论】:

标签: cmake external-project


【解决方案1】:

因为你是在下载外部项目,所以你已经知道所有东西在哪里,因为你刚刚下载了它,所以不需要“查找”。

我让它与 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 一起使用。正确获取所有依赖项。

【讨论】:

  • 从 cmake 3.2 开始,您可以使用 UPDATE_DISCONNECTED 来避免自动更新。如有必要,您仍然可以更新添加自定义目标。
  • 它怎么知道ForexConnect?例如这里add_library(ForexConnect SHARED IMPORTED)
  • 看起来是一个优雅的解决方案。它适用于make,但不适用于ninja。对于后者,您必须将外部项目的BUILD_BYPRODUCTS 属性设置为生成文件的路径。如果没有,Ninja 会尖叫它找不到你的图书馆。
  • @Lamda 只是为了不让这个问题得不到答复:它不知道ForexConnectadd_library() 创建它作为一个新目标。 (add_library 总是创建新的目标,IMPORTED 只是指定要创建的目标的 type。)IMPORTED_LOCATION 属性在之后设置,这就是它知道 where i> 可以找到ForexConnect 库文件。
  • 这看起来只适用于 Linux(您对 lib***.so 的使用)。你如何让它交叉编译?
【解决方案2】:

当你使用 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 很有用,即使它无法为您抽象出所有细节。

【讨论】:

  • 谢谢,这真的很有帮助。也只是为了不引起混淆,protobuf 没有可变库位置,但 R 有。
  • cmake 为您的平台提供前缀和后缀变量:"${install_dir}/lib/${CMAKE_SHARED_MODULE_PREFIX}protobufLib1${CMAKE_SHARED_LIBRARY_SUFFIX}"
  • 虽然这可行,但我认为这很可怕。如果我必须编写平台条件代码,使用 cmake 有什么意义?此外,我希望 ExternalProject 能够提供一种简单的方法来导入构建的目标,如果之后我不能轻松地导入它们,为什么还要构建一个外部项目呢?重点是什么?我错过了什么吗?
  • @Jens 并没有遗漏任何东西,但该场景不是 ExternalProject 与 CMake 的正常使用。事实上,我建议不要这样做。典型的场景是all ExternalProject,或者没有ExternalProject,不是一些外部的混合情况,一些不是。当所有组件都由 ExternalProject 在所谓的“超级构建”场景中构建/安装时,稍后构建的组件可以使用 find_package 查找较早构建/安装的组件。这是使用 ExternalProject 的推荐方式。
【解决方案3】:

要扩展上面的 DLRdave 答案,您不需要为静态库手动设置前缀和后缀,因为 CMAKE 为每个平台提供了正确的变量。

请参阅CMake Useful Variables 了解更多信息。

例如:

  • CMAKE_SHARED_LIBRARY_PREFIX
  • CMAKE_SHARED_LIBRARY_SUFFIX
  • CMAKE_STATIC_LIBRARY_PREFIX
  • CMAKE_STATIC_LIBRARY_SUFFIX

【讨论】:

    【解决方案4】:

    您可以使用 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)
    

    【讨论】:

    • 我觉得实际的 link_directories 字符串应该更长,因为我在 lib 下看到类似 MyExternalLibrary-build/lib 的内容。
    • 我尝试了这种技术,但它不适用于新版本。您收到错误消息(找不到您的库)。
    【解决方案5】:

    你可以用另一个成语来解决这个问题:

    1. 将 find_package 命令设为可选(删除“必需”)
    2. 添加一些条件代码以仅在 find_package 成功时构建目标。
    3. find_package 将失败,您的目标不会在第一次构建,但会构建外部项目。
    4. 再次运行 cmake/make,这一次 find_package 将成功,您的目标将被构建。

    您可以在https://github.com/biometrics/likely 中看到这个习语。

    【讨论】:

      【解决方案6】:

      您可以将find_packageExternalProject_add 一起使用,如以下代码sn-p:

      # --------------------------------------------------
      
      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

      【讨论】:

      • 有趣的解决方法。如果项目不够灵活,无法使用 add_subdirectory 而不是 find_package,这确实是一种不好的做法,具体取决于上下文。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-12-26
      • 2016-11-26
      • 1970-01-01
      • 2013-01-06
      • 2013-07-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多