How to use CMake ExternalProject_Add or alternatives in a cross platform way?

狂风中的少年 提交于 2019-11-28 18:38:31

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 on build stage. See my answer.

COMMAND cd <BINARY_DIR> && make install

This will work only for Makefile generators of course. To be cross-platformic 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

or is there a better 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 will be downloaded automatically on configuration step. Example of building with different generator/toolchains (build.py is just CMake wrapper that set 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 3rd party package. For instance this is how you can build 4 types Debug, Release, MinSizeRel, RelWithDebInfo for zlib and link MinSizeRel to 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 calls work cross-platform by default, and will only fail to do so if one uses particular commands that are only available on a subset of operating systems. Typically, CMAKE_ARGS is used to pass information to each superbuild unit within an external project build. The CMakeLists.txt files that control each miniature part of the overall build use CMake's declarative syntax (e.g., "add_library(library_name SHARED filename1.hpp filename1.cpp). CMake will convert such syntax to the commands that are specific to the particular build system you wish to use (e.g., make, ninja).

The sample above re: zlib fails to be cross-platform in part because the ExternalProject_Add_Step contains "COMMAND cd && make install", which necessarily only works in situations where invoking "cd" is actually the correct way to change directories, and where invoking "make" is actually the correct way to build software. CMake's -E option provides a way to invoke basic operations like changing/copying/making/removing directories without making such assumptions.

(By the way, if you're using IDEs such as Visual Studio or XCode, you'll likely want to invoke one or more IDE generators when using CMake. For instance, setting

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

will cause Eclipse projects to be generated in each build area, and also in the source code area that is shared for all builds. Of course, if you are using XCode or Visual Studio, you'll have to substitute the appropriate flag for those IDEs. Alternatively, you could consider using Eclipse with Ninja on all platforms, though at the time of writing, I am not completely certain that Ninja is ready for prime-time on non-Linux, non-Windows operating systems.)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!