web-dev-qa-db-ja.com

クロスプラットフォームでCMake ExternalProject_Addまたは代替を使用するにはどうすればよいですか?

私のプロジェクトのCMakeストリップの一部として既にCMakeを持っているサードパーティのプロジェクトを構築したいと思います。 ExternalProject_Addはこの目的のためのものですが、特定のジェネレーターでのみ動作するようにできることがわかり、多くのプラットフォームで簡単に動作することを望んでいました。

たとえば、独自のCMakeLists.txtを持つzlibのスクリプトが追加された外部プロジェクトです。

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

これの問題は、XcodeやVisual Studioではなくmakeで機能することです。おそらく、私のプロジェクトに渡されたCMakeビルドコマンドを取得し、ExternalProject_Addに転送する方法があります。

コードの複雑さを最小限に抑えて、クロスプラットフォームの方法でExternalProject_Add呼び出しを作成するにはどうすればよいですか?

30
Andrew Hundt

問題点

-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 of ExternalProject_Add

このテンプレートファイル 、特に 次の行 を見てください。

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

代替案

またはより良い代替手段はありますか?

ハンター を見ましたか?

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

オプションビルドタイプ または ジョブの数 サードパーティパッケージのビルド中に必要なものを完全に制御できます。たとえば、zlibのDebug、Release、MinSizeRel、およびRelWithDebInfoの4つのタイプをビルドし、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
26
user2288008

CMake ExternalProject_Add呼び出しはデフォルトでクロスプラットフォームで動作し、オペレーティングシステムのサブセットでのみ使用可能な特定のコマンドを使用する場合にのみ失敗します。

通常、CMAKE_ARGSは、外部プロジェクトビルド内の各スーパービルドユニットに情報を渡すために使用されます。ビルド全体の各ミニチュア部分を制御するCMakeLists.txtファイルは、CMakeの宣言構文を使用します(たとえば、「add_library(library_name SHARED filename1.hpp filename1.cpp)。CMakeは、特定のビルドシステムに固有のコマンドにそのような構文を変換します。使用したい(例:makeおよび Ninja )。

上記のサンプルre:zlibは部分的にクロスプラットフォームに失敗します。ExternalProject_Add_Stepに「COMMAND cd && make install」が含まれているためです。これは、「cd」の呼び出しが実際にディレクトリを変更する正しい方法であり、「 make」は実際にソフトウェアをビルドする正しい方法です。

CMakeの-Eオプションは、そのような仮定をすることなく、ディレクトリの変更/コピー/作成/削除などの基本的な操作を呼び出す方法を提供します。

(ところで、Visual StudioやXcodeなどのIDEを使用している場合は、CMakeを使用するときに1つ以上のIDEジェネレーターを呼び出すことをお勧めします。たとえば、設定

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

eclipseプロジェクトが各ビルド領域で生成され、すべてのビルドで共有されるソースコード領域でも生成されます。もちろん、XcodeまたはVisual Studioを使用している場合、それらのIDEに適切なフラグを代用する必要があります。あるいは、すべてのプラットフォームでEclipseをNinjaとともに使用することを検討できますが、執筆時点では、Ninjaが非Linux、非Windowsオペレーティングシステムでプライムタイムに対応できるかどうかは完全にはわかりません)

0
newbrific