With cmake, how would you disable in-source builds?
I have a cmake()
shell function in my .bashrc
/.zshrc
similar to this one:
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
}
I prefer this low ceremony solution. It got rid of my colleagues' biggest complaint when we switched to CMake, but it doesn't prevent people who really want to do an in-source/top-of-tree build from doing so—they can just invoke /usr/bin/cmake
directly (or not use the wrapper function at all). And it's stupid simple.
Include a function like this one. It is similar to what you do with these differences:
It is encapsulated in a function, which is called when you include the
PreventInSourceBuilds.cmake
module. Your main CMakeLists.txt must include it:set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/CMake) include(PreventInSourceBuilds)
It uses get_filename_component() with REALPATH parameter that resolves symlinks before comparing the paths.
In case the github link changes, here's the module source code (which should be placed in a PreventInSouceBuilds.cmake
, in a directory called CMake
, in the above example):
#
# 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()
CMake has two undocumented options:
CMAKE_DISABLE_SOURCE_CHANGES
and 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;
}