【问题标题】:How do I use CMake ExternalProject_Add or alternatives in a cross-platform way?如何以跨平台方式使用 CMake ExternalProject_Add 或替代方案?
【发布时间】:2013-05-26 09:15:20
【问题描述】:

我想构建一个第三方项目,该项目已经将 CMake 作为我项目的 CMake 条带的一部分。 ExternalProject_Add 就是为此目的,但我发现它只能与特定的生成器一起使用,并且我希望它能够轻松地在许多平台上工作。

例如,这是我的外部项目,其中添加了 zlib 脚本,它有自己的 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")

问题在于它适用于 make,但不适用于 Xcode 或 Visual Studio。也许有一些方法可以将 CMake 构建命令传递给我的项目并将它们转发到 ExternalProject_Add。

如何以跨平台的方式编写 ExternalProject_Add 调用,代码复杂度最低,还是有更好的替代方案?

【问题讨论】:

  • 找到了另一个可以达到这个目的的工具:conan.io

标签: cmake cross-platform external-project


【解决方案1】:

问题

-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}

这对于单一配置项目来说已经足够了。但对于 Xcode 和 Visual Studio,您需要在构建阶段设置 CMAKE_CONFIGURATION_TYPES 并调用 build . --config。见my answer

COMMAND cd <BINARY_DIR> && make install

这当然只适用于 Makefile 生成器。要跨平台,您可以使用:

--build . --target install --configINSTALL_COMMAND 中,属于ExternalProject_Add

看看this template file,尤其是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}
)

另类

还是有更好的选择?

你见过Hunter吗?

你可以像this一样添加zlib:

hunter_add_package(ZLIB)
find_package(ZLIB CONFIG REQUIRED)
target_link_libraries(... ZLIB::zlib)

此代码适用于任何地方。第三方依赖将在配置步骤中自动下载。使用不同的生成器/工具链构建的示例(build.py 只是一个设置 CMAKE_TOOLCHAIN_FILE-G/-B 的 CMake 包装器):

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

在构建第三方软件包时,您可以完全控制想要拥有的 optionsbuild typesnumber of jobs。例如,您可以通过以下方式为 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.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

【讨论】:

  • 酷,“--build ...”很有用,你能解释一下它在做什么吗?为什么构建命令是空的?我也对猎人很感兴趣所以I created a github issue那边有几个问题。
  • @AndrewHundt could you explain exactly what it is doing 设置生成器-G、构建目录(-B_builds/xcode 用于xcode 工具链或-B_builds/vs-12-2013 用于vs-12-2013 工具链)或一些环境变量。例如mingw --config Release 等于:set PATH=%MINGW_PATH%;%PATH% + cmake -H. -B_builds/mingw-Release "-GMinGW Makefiles" -DCMAKE_BUILD_TYPE=Release
  • Why is the build command empty? 你的意思是为什么没有build.py --configure 步骤?脚本检查没有 CMakeCache.txt 文件并运行 CMake 配置。由于 CMake 会进一步自动检测代码更改,因此您只需运行 cmake --build。无论如何build.py 对 Hunter 来说不是强制性的,它只是一个很好的别名工具,我觉得非常有用。
  • 对不起,我的问题很不清楚,我想问为什么this build command 是空的。感谢您解释 build.py,如果它正在简化一些命令行参数并且仅此而已,那实际上是一件好事!
  • @AndrewHundt I meant to ask why this build command was empty 好的,我明白了。我添加了一些comments
【解决方案2】:

默认情况下,CMake ExternalProject_Add 调用可以跨平台工作,并且只有在使用仅在部分操作系统上可用的特定命令时才会这样做。

通常,CMAKE_ARGS 用于将信息传递给外部项目构建中的每个超级构建单元。控制整个构建的每个微型部分的 CMakeLists.txt 文件使用 CMake 的声明性语法(例如,“add_library(library_name SHARED filename1.hpp filename1.cpp)”。CMake 会将此类语法转换为特定于特定构建系统的命令您希望使用(例如,make 和 Ninja)。

上面的示例回复:zlib 无法跨平台,部分原因是 ExternalProject_Add_Step 包含“COMMAND cd && make install”,这必然只适用于调用“cd”实际上是更改目录的正确方法的情况,并且其中调用“make”实际上是构建软件的正确方法。

CMake 的 -E 选项提供了一种调用基本操作(例如更改/复制/制作/删除目录)的方法,而无需做出此类假设。

(顺便说一句,如果您使用的是 Visual Studio 或 Xcode 等 IDE,则在使用 CMake 时可能需要调用一个或多个 IDE 生成器。例如,设置

-G "Eclipse CDT4 - Unix Makefiles" -DCMAKE_ECLIPSE_GENERATE_SOURCE_PROJECT=TRUE

将导致在每个构建区域以及为所有构建共享的源代码区域中生成 Eclipse 项目。当然,如果您使用的是 Xcode 或 Visual Studio,则必须为这些 IDE 替换适当的标志。或者,您可以考虑在所有平台上使用带有 Ninja 的 Eclipse,尽管在撰写本文时,我并不完全确定 Ninja 是否已准备好在非 Linux、非 Windows 操作系统上的黄金时间。)

【讨论】:

  • 感谢您尝试回复,但我认为您的回复实际上与问题无关。我不是在问 zlib,它只是一个例子。我一般特别询问有关使用 cmake 函数 ExternalProject_Add 以便它可以跨平台工作,因此我不需要为每个平台和配置实例化该调用的多个版本。
  • 感谢您指出我误解了您的问题。我已经修改了我的帖子,试图回答你真正想要的。
  • 我明白了,所以我想看看我是否可以用cmake -E build &lt;BINARY_DIR&gt; 替换cd &lt;BINARY_DIR&gt; &amp;&amp; make install,但我认为这不会完成我真正想要的安装步骤。另外,我还有一个问题,例如 Xcode 将文件放入 buildDir/bin/Debug/binarybuildDir/bin/Release/binary,而 make 将文件放入 buildDir/bin/binary。旁白:不得不考虑所有这些平台特定的差异有点令人沮丧,我希望 CMake 有一种更简洁的方式来处理我目前所缺少的。
猜你喜欢
  • 2022-06-10
  • 1970-01-01
  • 1970-01-01
  • 2021-05-13
  • 1970-01-01
  • 2011-12-30
  • 1970-01-01
  • 1970-01-01
  • 2016-08-26
相关资源
最近更新 更多