31

project/buildのように、CMakeLists.txt が にあるディレクトリ「build」に CMake をビルドしようとしていproject/ます。

私はできることを知っています:

mkdir build
cd build
cmake ../

しかし、それは面倒です。スクリプトに入れて呼び出すこともできますが、CMake にさまざまな引数 (-G "MSYS Makefiles" など) を指定するのは不快です。そうしないと、各プラットフォームでこのファイルを編集する必要があります。

SET(CMAKE_OUTPUT_DIR build)できれば、メインの CMakeLists.txt のようなことをしたいと思います。これが可能であることを教えてください。または、さまざまな引数を簡単に指定できるようにする、ソース以外のビルド方法はありますか?

4

3 に答える 3

53

CMake 3.13 以降では、コマンド ライン オプション -Sがサポートされており、-Bソース ディレクトリとバイナリ ディレクトリをそれぞれ指定できます。

cmake -S . -B build -G "MSYS Makefiles"

CMakeLists.txtこれにより、現在のフォルダーでが検索され、その中にフォルダーが作成されbuildます (まだ存在しない場合)。

古いバージョンの CMake では、文書化されていない CMake オプション-Hを使用し-Bて、呼び出し時にソースとバイナリ ディレクトリを指定できますcmake

cmake -H. -Bbuild -G "MSYS Makefiles"

オプションとディレクトリ パスの間にスペース文字があってはならないことに注意してください。

于 2012-06-21T18:05:20.553 に答える
6

私が最近見つけた解決策は、アウト オブ ソース ビルドの概念を Makefile ラッパーと組み合わせることです。

最上位の CMakeLists.txt ファイルに、インソース ビルドを防ぐために次を含めます。

if ( ${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR} )
    message( FATAL_ERROR "In-source builds not allowed. Please make a new directory (called a build directory) and run CMake from there. You may need to remove CMakeCache.txt." )
endif()

次に、最上位の Makefile を作成し、以下を含めます。

# -----------------------------------------------------------------------------
# CMake project wrapper Makefile ----------------------------------------------
# -----------------------------------------------------------------------------

SHELL := /bin/bash
RM    := rm -rf
MKDIR := mkdir -p

all: ./build/Makefile
    @ $(MAKE) -C build

./build/Makefile:
    @  ($(MKDIR) build > /dev/null)
    @  (cd build > /dev/null 2>&1 && cmake ..)

distclean:
    @  ($(MKDIR) build > /dev/null)
    @  (cd build > /dev/null 2>&1 && cmake .. > /dev/null 2>&1)
    @- $(MAKE) --silent -C build clean || true
    @- $(RM) ./build/Makefile
    @- $(RM) ./build/src
    @- $(RM) ./build/test
    @- $(RM) ./build/CMake*
    @- $(RM) ./build/cmake.*
    @- $(RM) ./build/*.cmake
    @- $(RM) ./build/*.txt

ifeq ($(findstring distclean,$(MAKECMDGOALS)),)
    $(MAKECMDGOALS): ./build/Makefile
    @ $(MAKE) -C build $(MAKECMDGOALS)
endif

allと入力すると、デフォルトのターゲットが呼び出されmake、ターゲットが呼び出されます./build/Makefile

ターゲットが最初に行うことは、 の変数である を使用してディレクトリを./build/Makefile作成することです。ディレクトリは、アウトオブソース ビルドを実行する場所です。すでに存在する可能性のあるディレクトリを作成しようとして、 が私たちを怒鳴らないようにするための引数を提供します。build$(MKDIR)mkdir -pbuild-pmkdir

ターゲットが行う 2 番目のことは、ディレクトリ./build/Makefileをディレクトリに変更し、.buildcmake

ターゲットに戻りall、 を呼び出します$(MAKE) -C build。ここで、$(MAKE)は に対して自動的に生成される Makefile 変数ですmakemake -C何かをする前にディレクトリを変更します。したがって、 を使用することは、 を使用$(MAKE) -C buildすることと同じcd build; makeです。

要約すると、この Makefile ラッパーをmake allorで呼び出すことは、次のことmakeと同等です。

mkdir build
cd build
cmake ..
make 

ターゲットは をdistclean呼び出しcmake ..、次にを呼び出し、最後にディレクトリmake -C build cleanからすべてのコンテンツを削除します。buildこれはまさにあなたが質問で要求したものだと思います。

Makefile の最後の部分は、ユーザーが指定したターゲットが であるかどうかを評価しますdistcleanbuildそうでない場合は、呼び出す前にディレクトリをに変更します。これは非常に強力です。たとえば、ユーザーが を入力するmake cleanと、Makefile がそれを に相当するものに変換するからcd build; make cleanです。

結論として、この Makefile ラッパーは、必須のアウトオブソース ビルド CMake 構成と組み合わせて、ユーザーがコマンドを操作する必要がないようにしますcmakebuildこのソリューションは、ディレクトリからすべての CMake 出力ファイルを削除する洗練された方法も提供します。

PS Makefile では、プレフィックスを使用し@てシェル コマンドからの出力を抑制し、プレフィックスを使用してシェル コマンド@-からのエラーを無視します。rmターゲットの一部として使用distcleanする場合、ファイルが存在しない場合、コマンドはエラーを返します (ファイルは、コマンド ラインを使用して既に削除されているrm -rf buildか、最初から生成されていない可能性があります)。この戻りエラーにより、Makefile は強制的に終了します。@-それを防ぐためにプレフィックスを使用します。ファイルが既に削除されている場合は許容されます。Makefile を続行し、残りを削除する必要があります。

注意すべきもう 1 つの点: プロジェクトをビルドするために可変数の CMake 変数を使用する場合、この Makefile は機能しない可能性がありますcmake .. -DSOMEBUILDSUSETHIS:STRING="foo" -DSOMEOTHERBUILDSUSETHISTOO:STRING="bar"cmake ..この Makefile は、入力するかcmake、一貫した数の引数 (Makefile に含めることができます) を指定することによって、一貫した方法で CMake を呼び出すことを前提としています。

最後に、クレジットが必要なクレジット。この Makefile ラッパーは、C++ Application Project Templateによって提供される Makefile から適用されました。

この回答はもともとここに投稿されました。あなたの状況にも当てはまると思いました。

于 2015-04-16T15:10:59.873 に答える
3

以前の回答に基づいて、ソース外ビルドを強制するために含めることができる次のモジュールを作成しました。

set(DEFAULT_OUT_OF_SOURCE_FOLDER "cmake_output")

if (${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR})
    message(WARNING "In-source builds not allowed. CMake will now be run with arguments:
        cmake -H. -B${DEFAULT_OUT_OF_SOURCE_FOLDER}
")

    # Run CMake with out of source flag
    execute_process(
            COMMAND ${CMAKE_COMMAND} -H. -B${DEFAULT_OUT_OF_SOURCE_FOLDER}
            WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})

    # Cause fatal error to stop the script from further execution
    message(FATAL_ERROR "CMake has been ran to create an out of source build.
This error prevents CMake from running an in-source build.")
endif ()

これは機能しますが、私はすでに 2 つの欠点に気付きました。

  • ユーザーが怠惰で単純cmake .に を実行すると、常にFATAL_ERROR. CMake が他の操作を実行して早期に終了するのを防ぐ別の方法を見つけることができませんでした。
  • 元の呼び出しに渡されたコマンド ライン引数はcmake、「ソース外ビルド呼び出し」には渡されません。

このモジュールを改善するための提案を歓迎します。

于 2016-05-31T08:35:30.033 に答える