问题描述
我想构建一个第三方项目,该项目已经将 CMake 作为我项目的 CMake 条带的一部分.ExternalProject_Add 就是为了这个目的,但我发现它只能与特定的生成器一起工作,我希望它可以轻松地在许多平台上工作.
例如,这是我的外部项目,为 zlib 添加了脚本,它有自己的 CMakeLists.txt:
set(USE_PROJECT_CMAKE_MODULE_PATH "-DCMAKE_MODULE_PATH=${MAKE_MODULE_PATH}")外部项目_添加(ZLIBSOURCE_DIR ${CMAKE_SOURCE_DIR}/external/zlib下载命令"更新命令"CMAKE_ARGS-DCMAKE_INSTALL_PREFIX=-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}-DCMAKE_C_FLAGS=${CMAKE_C_FLAGS}-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}${USE_PROJECT_CMAKE_MODULE_PATH}INSTALL_COMMAND "")ExternalProject_Add_Step(ZLIB 安装内部命令 cd &&进行安装依赖安装总是 1)ExternalProject_Get_Property(ZLIB install_dir)如果(UNIX)设置(ZLIB_NAME libz)其他(UNIX)设置(ZLIB_NAME zlib)结束(UNIX)add_library(zlib 未知导入)set_property(TARGET zlib PROPERTY IMPORTED_LOCATION ${install_dir}/lib/${ZLIB_NAME}.a)设置(ZLIB_LIBRARIES zlib)设置(ZLIB_LIBRARIES_OPTIONAL ${ZLIB_LIBRARIES})设置(ZLIB_DIR ${install_dir} 缓存内部zlib 根目录")设置(ZLIB_INCLUDE_DIRS ${install_dir}/include CACHE INTERNALzlib 包含目录")设置(ZLIB_DEFINES-msse2 -mfpmath=sse"缓存内部zlib定义")
问题在于它适用于 make,但不适用于 Xcode 或 Visual Studio.也许有某种方法可以将传递给我的项目的 CMake 构建命令转发给 ExternalProject_Add.
如何以跨平台的方式以最小的代码复杂性编写 ExternalProject_Add 调用,或者是否有更好的替代方法?
问题
-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
这对于单配置项目来说已经足够了.但是对于 Xcode 和 Visual Studio,您需要设置 CMAKE_CONFIGURATION_TYPES
并调用 build .--config
在构建阶段.请参阅我的答案.>
COMMAND cd &&进行安装
这当然只适用于 Makefile 生成器.要跨平台,您可以使用:
--build .--target install --config
在 ExternalProject_Add
的 INSTALL_COMMAND
内.
ExternalProject_Add(${current_project}"网址@HUNTER_PACKAGE_URL@URL_HASHSHA1=@HUNTER_PACKAGE_SHA1@下载目录"@HUNTER_PACKAGE_DOWNLOAD_DIR@"SOURCE_DIR"@HUNTER_PACKAGE_SOURCE_DIR@"安装目录"@HUNTER_PACKAGE_INSTALL_PREFIX@"# 没用,只是避免创建 Install/空目录BUILD_COMMAND ""# 此命令为空,因为所有必需的目标都将# 建立在安装阶段CMAKE_ARGS-G@CMAKE_GENERATOR@""-C@HUNTER_CACHE_FILE@""-C@HUNTER_ARGS_FILE@""-D${postfix_name}=${${postfix_name}}"-DCMAKE_BUILD_TYPE=${configuration}"-DCMAKE_CONFIGURATION_TYPES=${configuration}""-DCMAKE_INSTALL_PREFIX=@HUNTER_PACKAGE_INSTALL_PREFIX@"-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}"INSTALL_COMMAND@CMAKE_COMMAND@"- 建造 .--目标安装--config ${配置}——${jobs_option})
替代方案
你可以像这个一样添加zlib:
hunter_add_package(ZLIB)find_package(需要 ZLIB 配置)target_link_libraries(... ZLIB::zlib)
此代码适用于任何地方.第三方依赖将在配置步骤中自动下载.使用不同生成器/工具链构建的示例(build.py 只是一个设置 CMAKE_TOOLCHAIN_FILE 的 CMake 包装器
和 -G
/-B
):
build.py --toolchain mingw --config Release # MinGW Makefilesbuild.py --toolchain vs-12-2013 --config 调试 # Visual Studio 12 2013build.py --toolchain xcode --config Release # Xcodebuild.py --toolchain libcxx --config Release # Makefile with -stdlib=libc++ toolchainbuild.py --toolchain ios-8-2 --config Release # Xcode with iOS SDK 8.2 toolchain
您可以完全控制选项、构建类型 或 工作数量 在构建第三方软件包时您希望拥有.例如,您可以这样为 zlib 构建四种类型,Debug、Release、MinSizeRel 和 RelWithDebInfo,并将 MinSizeRel 链接到当前项目:
>build.py --toolchain xcode --verbose --config MinSizeRel --fwd "HUNTER_CONFIGURATION_TYPES=Release;Debug;MinSizeRel;RelWithDebInfo"/.../clang/.../lib/libz-MinSizeRel.a ... -o/.../_builds/xcode/MinSizeRel/foo>ls -la/.../.hunter/_Base/d1232c0/326318e/37e4682/Install/lib/libz*99056/.../.hunter/_Base/d1232c0/326318e/37e4682/Install/lib/libz-MinSizeRel.a307872/.../.hunter/_Base/d1232c0/326318e/37e4682/Install/lib/libz-RelWithDebInfo.a109536/.../.hunter/_Base/d1232c0/326318e/37e4682/Install/lib/libz.a258904/.../.hunter/_Base/d1232c0/326318e/37e4682/Install/lib/libzd.a
I would like to build a third-party project that already has CMake as part of my project's CMake strips. ExternalProject_Add is for this purpose, but I have found it can only be made to work with a specific generator, and I wanted it to work on many platforms easily.
For example, here is my external project with an added script for zlib, which has its own CMakeLists.txt:
set(USE_PROJECT_CMAKE_MODULE_PATH "-DCMAKE_MODULE_PATH=${MAKE_MODULE_PATH}")
ExternalProject_Add(ZLIB
SOURCE_DIR ${CMAKE_SOURCE_DIR}/external/zlib
DOWNLOAD_COMMAND ""
UPDATE_COMMAND ""
CMAKE_ARGS
-DCMAKE_INSTALL_PREFIX=<INSTALL_DIR>
-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}
-DCMAKE_C_FLAGS=${CMAKE_C_FLAGS}
-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
${USE_PROJECT_CMAKE_MODULE_PATH}
INSTALL_COMMAND "")
ExternalProject_Add_Step(ZLIB installInternally
COMMAND cd <BINARY_DIR> && make install
DEPENDEES install
ALWAYS 1)
ExternalProject_Get_Property(ZLIB install_dir)
if(UNIX)
set(ZLIB_NAME libz)
else(UNIX)
set(ZLIB_NAME zlib)
endif(UNIX)
add_library(zlib UNKNOWN IMPORTED)
set_property(TARGET zlib PROPERTY IMPORTED_LOCATION ${install_dir}/lib/${ZLIB_NAME}.a)
set(ZLIB_LIBRARIES zlib)
set(ZLIB_LIBRARIES_OPTIONAL ${ZLIB_LIBRARIES})
set(ZLIB_DIR ${install_dir} CACHE INTERNAL "zlib ROOT dir")
set(ZLIB_INCLUDE_DIRS ${install_dir}/include CACHE INTERNAL "zlib include dirs")
set(ZLIB_DEFINES "-msse2 -mfpmath=sse" CACHE INTERNAL "zlib defines")
The problem with this is that it works with make, but not with Xcode or Visual Studio. Perhaps there is some way to take the CMake build commands passed to my project and forward them to ExternalProject_Add.
How can I write ExternalProject_Add calls in a cross-platform way with minimal code complexity, or is there a better alternative?
Problems
-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
This is enough for single-configuration projects. But for Xcode and Visual Studio, you need to set CMAKE_CONFIGURATION_TYPES
plus call build . --config
at the build stage. See my answer.
COMMAND cd <BINARY_DIR> && make install
This will work only for Makefile generators of course. To be cross-platform you can use:
--build . --target install --config
inside INSTALL_COMMAND
of ExternalProject_Add
.
Take a look at this template file, and in particular the following lines:
ExternalProject_Add(
"${current_project}"
URL
@HUNTER_PACKAGE_URL@
URL_HASH
SHA1=@HUNTER_PACKAGE_SHA1@
DOWNLOAD_DIR
"@HUNTER_PACKAGE_DOWNLOAD_DIR@"
SOURCE_DIR
"@HUNTER_PACKAGE_SOURCE_DIR@"
INSTALL_DIR
"@HUNTER_PACKAGE_INSTALL_PREFIX@"
# Not used, just avoid creating Install/<name> empty directory
BUILD_COMMAND ""
# This command is empty because all necessary targets will
# be built on install stage
CMAKE_ARGS
"-G@CMAKE_GENERATOR@"
"-C@HUNTER_CACHE_FILE@"
"-C@HUNTER_ARGS_FILE@"
"-D${postfix_name}=${${postfix_name}}"
"-DCMAKE_BUILD_TYPE=${configuration}"
"-DCMAKE_CONFIGURATION_TYPES=${configuration}"
"-DCMAKE_INSTALL_PREFIX=@HUNTER_PACKAGE_INSTALL_PREFIX@"
"-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}"
INSTALL_COMMAND
"@CMAKE_COMMAND@"
--build .
--target install
--config ${configuration}
--
${jobs_option}
)
Alternative
Have you seen Hunter?
You can add zlib just like this:
hunter_add_package(ZLIB)
find_package(ZLIB CONFIG REQUIRED)
target_link_libraries(... ZLIB::zlib)
This code works everywhere. Third party dependencies will be downloaded automatically in the configuration step. Example of building with different generator/toolchains (build.py is just a CMake wrapper that sets CMAKE_TOOLCHAIN_FILE
and -G
/-B
):
build.py --toolchain mingw --config Release # MinGW Makefiles
build.py --toolchain vs-12-2013 --config Debug # Visual Studio 12 2013
build.py --toolchain xcode --config Release # Xcode
build.py --toolchain libcxx --config Release # Makefile with -stdlib=libc++ toolchain
build.py --toolchain ios-8-2 --config Release # Xcode with iOS SDK 8.2 toolchain
You got full control what options, build types or number of jobs you want to have while building third-party packages. For instance, this is how you can build four types, Debug, Release, MinSizeRel, and RelWithDebInfo for zlib and link MinSizeRel to the current project:
> build.py --toolchain xcode --verbose --config MinSizeRel --fwd "HUNTER_CONFIGURATION_TYPES=Release;Debug;MinSizeRel;RelWithDebInfo"
/.../clang /.../lib/libz-MinSizeRel.a ... -o /.../_builds/xcode/MinSizeRel/foo
> ls -la /.../.hunter/_Base/d1232c0/326318e/37e4682/Install/lib/libz*
99056 /.../.hunter/_Base/d1232c0/326318e/37e4682/Install/lib/libz-MinSizeRel.a
307872 /.../.hunter/_Base/d1232c0/326318e/37e4682/Install/lib/libz-RelWithDebInfo.a
109536 /.../.hunter/_Base/d1232c0/326318e/37e4682/Install/lib/libz.a
258904 /.../.hunter/_Base/d1232c0/326318e/37e4682/Install/lib/libzd.a
这篇关于如何以跨平台的方式使用 CMake ExternalProject_Add 或替代品?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!