我想分享我在上一个项目中是如何解决类似问题的——希望它对你有用。我的要求是相似的——只公开第三方项目的开发人员打算公开的头文件和库。我的项目本身使用 cmake,但这不是必需的。
我在 repo 的根目录中创建了一个 deps 文件夹,并将 CMakeLists.txt 放在那里。这不是构建主项目,而是拉下我关心的依赖项,构建它们(他们的开发人员打算构建的方式),并安装它们以供我的项目使用。看起来像这样:
myrepo/
deps/
CMakeLists.txt
与@jordanvrtanoski 类似,我使用ExternalProject 功能,但我编写了一个宏,这让我更加简洁。我最初在add_subdirectory 上苦苦挣扎,最终我找到了他的建议来避免add_subdirectory 声音:)。与@jordanvrtanoski 不同,我更喜欢为依赖项使用单独的 CMakeLists.txt,即使我的顶级项目是基于 cmake 的。否则,我发现 cmake 会进行一些检查,确认依赖项已正确安装,并且从我的内部开发循环中抢夺时间......我还发现,将依赖项安装在内循环之外可以让您可靠地执行 @ 987654324@ 在 cmake 中,不用担心在顶层项目中分别指定 include 和 lib 目录。
这是 CMakeLists.txt 的 sn-p
cmake_minimum_required(VERSION 3.17)
project(deps)
include(ExternalProject)
function(install NAME GIT_REPO GIT_TAG)
ExternalProject_Add(
${NAME}
GIT_REPOSITORY ${GIT_REPO}
GIT_TAG ${GIT_TAG}
PREFIX ${CMAKE_SOURCE_DIR}/${CMAKE_BUILD_TYPE}
${ARGN}
CMAKE_ARGS
--config ${CMAKE_BUILD_TYPE}
-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded$<$<CONFIG:Debug>:Debug>
-DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_SOURCE_DIR}/${CMAKE_BUILD_TYPE}/install
)
endfunction()
install(gflags
https://github.com/gflags/gflags.git
v2.2.0
CMAKE_ARGS
-DREGISTER_INSTALL_PREFIX=FALSE
-DGFLAGS_BUILD_TESTING=FALSE)
install(glog
https://github.com/google/glog.git
v0.4.0
DEPENDS gflags
CMAKE_ARGS
-DBUILD_TESTING=FALSE)
您可以通过以下方式触发安装:
cmake -DCMAKE_BUILD_TYPE=Debug --log-level=VERBOSE -G "NMake Makefiles" ..
cmake --build . --config Debug
请注意,您可以分别进行 Debug 和 Release 构建,并且工件最终位于 deps 下的单独文件夹中。
这里有一些需要解开的东西,但我希望这都是有充分理由的。您可以看到,一旦宏退出,安装gflags 的sn-p 就非常少了。它为 cmake 指定 repo、标签和一些特定于 gflags 的选项。安装glog 的以下步骤同样简单,但我将其作为传递依赖的示例包含在内...您可以看到它声明了对gflags 的依赖,这很重要...因为可以安装glog有或没有gflags 支持,我想要后者。
另一个需要注意的更普遍的事情是,宏覆盖了依赖项的CMAKE_INSTALL_PREFIX,因此它被安装在myrepo/deps/Debug/install/... 之类的地方。安装本身将根据原始开发人员的意图在其下创建 include 和 lib 和有时 bin 文件夹。
在编译myrepo 时,需要将编译器指向安装目录,明确告诉它在myrepo/deps/Debug/install/include 中查找头文件,在myrepo/deps/Debug/install/libs 中查找库文件。如何执行此操作取决于您用于主项目的构建系统。如果是 cmake(像我的一样),这对我有用:
...
set(CMAKE_PREFIX_PATH ${CMAKE_SOURCE_DIR}/deps/${CMAKE_BUILD_TYPE}/install)
find_package(gflags REQUIRED NO_MODULE)
find_package(glog REQUIRED NO_MODULE)
add_binary(mybinary
...)
target_link_libraries(mybinary
glog::glog)
我希望这对你有用,我真的在寻找其他解决这个问题的人的反馈。我发现 C/C++ 中的整个依赖基础架构比为 Java(例如 Maven)或 JavaScript(例如 NPM)或 Python(例如 PyPI)开发的较新的基础架构更脆弱,考虑到它已经存在了多长时间,这确实有点令人惊讶。
我想 Eigen 在其安装脚本中会在 .../deps/Debug/include/Eigen 下创建 Eigen 目录,你的梦想就会成真 :)
请注意,这种方法不使用 git 子模块,但依赖项的来源最终会被ExternalProject 模块获取并包含在.../deps/Debug/src 下......所以你仍然可以去那里检查它们。如果您选择在 .../deps/CMakeLists.txt 中使用不同的标签或 rev 并如上所述重新运行安装部分,则可以轻松更新依赖项的修订版。
一些离别的想法和花絮,有些重要,但不应该在主要阐述中占有一席之地......
- 如果你需要安装一些特殊的东西,你可以放弃我的宏,它不是基于 cmake,不存储在 git 中,甚至使用预构建的二进制文件......这个宏旨在解决最常见的快乐路径我,但您可以在所有其他情况下直接使用
ExternalProject_Add。
曾经我必须为 Windows 上的 OpenSSL 执行此操作,然后我在 deps/CMakeLists.txt 中使用了这个 sn-p:
ExternalProject_Add(
openssl
URL https://github.com/CristiFati/Prebuilt-Binaries/raw/master/OpenSSL/v1.1.1/OpenSSL-1.1.1i-Win-pc064.zip
PREFIX ${CMAKE_SOURCE_DIR}/${CMAKE_BUILD_TYPE}
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ${CMAKE_COMMAND} -E echo installing from `<SOURCE_DIR>/OpenSSL/1.1.1i` to `${CMAKE_SOURCE_DIR}/${CMAKE_BUILD_TYPE}/install`
COMMAND ${CMAKE_COMMAND} -E copy_directory <SOURCE_DIR>/OpenSSL/1.1.1i/include ${CMAKE_SOURCE_DIR}/${CMAKE_BUILD_TYPE}/install/include
COMMAND ${CMAKE_COMMAND} -E copy_directory <SOURCE_DIR>/OpenSSL/1.1.1i/lib ${CMAKE_SOURCE_DIR}/${CMAKE_BUILD_TYPE}/install/lib
COMMAND ${CMAKE_COMMAND} -E copy_directory <SOURCE_DIR>/OpenSSL/1.1.1i/bin ${CMAKE_SOURCE_DIR}/${CMAKE_BUILD_TYPE}/install/bin
)
- 我对@987654349@ 很幸运,但它更喜欢静态库,并且它们的 cmake 脚本会做一些相当低级的手术,以注入正确的编译器选项来完成当你有大量依赖项时会混淆的事情,所以我必须向它传递一个标志以容忍共享库:
install(googletest
https://github.com/google/googletest.git
release-1.10.0
CMAKE_ARGS
#FIXME: figure out how to make all of them static!!!
-Dgtest_force_shared_crt=ON)
- 我的待办事项清单上的一件事是尝试将此技术应用于容器并使用标准安装目录,而不是像本示例中那样被覆盖的目录。我会在这些日子里解决它。
如果您有任何问题,请告诉我!