生成されたCMakeファイルでソースツリーを乱雑にすることを禁止したい...そしてさらに重要なことに、CMakeを使用しているのと同じビルドプロセスの一部ではない既存のMakefiles
を踏むことを禁止したい。 (聞かないでください)
これを行うために私が思いついた方法は、次のように、CMakeLists.txt
の上部に数行を配置することです。
if("${PROJECT_SOURCE_DIR}" STREQUAL "${PROJECT_BINARY_DIR}")
message(SEND_ERROR "In-source builds are not allowed.")
endif("${PROJECT_SOURCE_DIR}" STREQUAL "${PROJECT_BINARY_DIR}")
ただし、この方法で行うのは冗長すぎるようです。さらに、ソース内ビルドを試行しても、エラーがスローされる前に、ソースツリーにCMakeFiles/
ディレクトリとCMakeCache.txt
ファイルが作成されます。
これを行うためのより良い方法がありませんか?
私はあなたのやり方が好きだと思います。 cmakeメーリングリストは、これらのタイプの質問に答えるのに適しています。
補足として:失敗したディレクトリに「cmake」実行可能ファイルを作成することができます。 「。」かどうかによって異なります。それらのパスにあります(Linuxの場合)。/bin/falseをシンボリックリンクすることもできます。
Windowsでは、現在のディレクトリ内のファイルが最初に見つかるかどうかはわかりません。
CMakeには2つの文書化されていないオプションがあります:CMAKE_DISABLE_SOURCE_CHANGES
およびCMAKE_DISABLE_IN_SOURCE_BUILD
cmake_minimum_required (VERSION 2.8)
# add this options before PROJECT keyword
set(CMAKE_DISABLE_SOURCE_CHANGES ON)
set(CMAKE_DISABLE_IN_SOURCE_BUILD ON)
project (HELLO)
add_executable (hello hello.cxx)
-
andrew@manchester:~/src% cmake .
CMake Error at /usr/local/share/cmake-2.8/Modules/CMakeDetermineSystem.cmake:160 (FILE):
file attempted to write a file: /home/andrew/src/CMakeFiles/CMakeOutput.log
into a source directory.
/home/selivanov/cmake-2.8.8/Source/cmMakefile.cxx
bool cmMakefile::CanIWriteThisFile(const char* fileName)
{
if ( !this->IsOn("CMAKE_DISABLE_SOURCE_CHANGES") )
{
return true;
}
// If we are doing an in-source build, than the test will always fail
if ( cmSystemTools::SameFile(this->GetHomeDirectory(),
this->GetHomeOutputDirectory()) )
{
if ( this->IsOn("CMAKE_DISABLE_IN_SOURCE_BUILD") )
{
return false;
}
return true;
}
// Check if this is subdirectory of the source tree but not a
// subdirectory of a build tree
if ( cmSystemTools::IsSubDirectory(fileName,
this->GetHomeDirectory()) &&
!cmSystemTools::IsSubDirectory(fileName,
this->GetHomeOutputDirectory()) )
{
return false;
}
return true;
}
これ のような関数を含めます。これは、これらの違いで行うことと似ています。
これは、PreventInSourceBuilds.cmake
モジュールを含めると呼び出される関数にカプセル化されます。メインのCMakeLists.txtには次のものを含める必要があります。
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/CMake)
include(PreventInSourceBuilds)
パスを比較する前にシンボリックリンクを解決するREALPATHパラメーターで get_filename_component() を使用します。
Githubリンクが変更された場合、モジュールのソースコードは次のとおりです(上記の例では、CMake
というディレクトリのPreventInSouceBuilds.cmake
に配置する必要があります)。
#
# This function will prevent in-source builds
function(AssureOutOfSourceBuilds)
# make sure the user doesn't play dirty with symlinks
get_filename_component(srcdir "${CMAKE_SOURCE_DIR}" REALPATH)
get_filename_component(bindir "${CMAKE_BINARY_DIR}" REALPATH)
# disallow in-source builds
if("${srcdir}" STREQUAL "${bindir}")
message("######################################################")
message("# ITK should not be configured & built in the ITK source directory")
message("# You must run cmake in a build directory.")
message("# For example:")
message("# mkdir ITK-Sandbox ; cd ITK-sandbox")
message("# git clone http://itk.org/ITK.git # or download & unpack the source tarball")
message("# mkdir ITK-build")
message("# this will create the following directory structure")
message("#")
message("# ITK-Sandbox")
message("# +--ITK")
message("# +--ITK-build")
message("#")
message("# Then you can proceed to configure and build")
message("# by using the following commands")
message("#")
message("# cd ITK-build")
message("# cmake ../ITK # or ccmake, or cmake-gui ")
message("# make")
message("#")
message("# NOTE: Given that you already tried to make an in-source build")
message("# CMake have already created several files & directories")
message("# in your source tree. run 'git status' to find them and")
message("# remove them by doing:")
message("#")
message("# cd ITK-Sandbox/ITK")
message("# git clean -n -d")
message("# git clean -f -d")
message("# git checkout --")
message("#")
message("######################################################")
message(FATAL_ERROR "Quitting configuration")
endif()
endfunction()
AssureOutOfSourceBuilds()
_.bashrc
_/_.zshrc
_に次のようなcmake()
シェル関数があります。
_function cmake() {
# Don't invoke cmake from the top-of-tree
if [ -e "CMakeLists.txt" ]
then
echo "CMakeLists.txt file present, cowardly refusing to invoke cmake..."
else
/usr/bin/cmake $*
fi
}
_
私はこの低い式典の解決策を好みます。 CMakeに切り替えたとき、同僚の最大の不満は解消されましたが、本当にインソース/トップオブツリービルドを実行したい人がそうすることを妨げることはありません。 _/usr/bin/cmake
_を直接呼び出すことができます(またはラッパー関数をまったく使用しません)。そしてそれは愚かな単純です。
.bashrcファイルは これ のように構成できます。
関数cmakekdeとkdebuildを見てください。 BUILDおよびSRCenvを設定します。変数を作成し、必要に応じてこれらの関数を編集します。これは、srcDirではなくbuildDirでのみビルドされます
Linuxを使用している場合:
トップレベルのCMakeLists.txtに追加します。
set(CMAKE_DISABLE_IN_SOURCE_BUILD ON)
トップレベルにファイル「dotme」を作成するか、.bashrcに(グローバルに)追加します。
#!/bin/bash
cmk() { if [ ! -e $1/CMakeLists.txt ] || ! grep -q "set(CMAKE_DISABLE_IN_SOURCE_BUILD ON)" $1/CMakeLists.txt;then /usr/bin/cmake $*;else echo "CMAKE_DISABLE_IN_SOURCE_BUILD ON";fi }
alias cmake=cmk
今実行します:
. ./dotme
トップレベルのソースツリーでcmakeを実行しようとすると:
$ cmake .
CMAKE_DISABLE_IN_SOURCE_BUILD ON
CMakeFiles /またはCMakeCache.txtは生成されません。
ソース外のビルドを実行していて、初めてcmakeを実行する必要がある場合は、実際の実行可能ファイルを呼び出すだけです。
$ cd build
$ /usr/bin/cmake ..
ビルドを行う人/プロセスがディレクトリを読み取り専用にするだけです。ソース管理からディレクトリにチェックアウトし(ソース管理を使用していますよね?)、読み取り専用にする別のプロセスがあります。