我想禁止人们使用生成的CMake文件来混乱我们的源代码树...更重要的是,不允许他们踩到不属于同一构建过程的现有Makefiles
我们正在使用CMake对于。 (最好不要问)
我提出这样做的方法是在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
文件。
我错过了更好的方法吗?
答案 0 :(得分:49)
CMake有两个未记录的选项:
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;
}
答案 1 :(得分:7)
包含this one之类的功能。它与您对这些差异的处理方式类似:
它封装在一个函数中,当您包含PreventInSourceBuilds.cmake
模块时会调用该函数。您的主要CMakeLists.txt必须包含它:
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/CMake)
include(PreventInSourceBuilds)
它使用get_filename_component()和REALPATH参数在比较路径之前解析符号链接。
如果github链接发生变化,这里的模块源代码(应放在PreventInSouceBuilds.cmake
中,在上面示例中名为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()
答案 2 :(得分:5)
我的cmake()
/ .bashrc
中有一个.zshrc
shell函数,与此类似:
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
(或根本不使用包装函数)。这是愚蠢的简单。
答案 3 :(得分:4)
我想我喜欢你的方式。 cmake邮件列表在回答这些类型的问题方面做得很好。
作为旁注:您可以在失败的目录中创建“cmake”可执行文件。取决于是否“。”在他们的路径(在Linux上)。你甚至可以用symlink / bin / false。
在Windows中,我不确定是否首先找到当前目录中的文件。
答案 4 :(得分:1)
您可以配置.bashrc文件,例如this one
查看函数 cmakekde 和 kdebuild 。设置BUILD和SRC环境。变量并根据您的需要编辑这些功能。这将只在 buildDir 而不是 srcDir
中构建答案 5 :(得分:1)
对于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 ..
答案 6 :(得分:0)
只需让执行构建的人员/进程只读目录。有一个单独的进程从源代码控制检出目录(你正在使用源代码控制,对吗?),然后将其设置为只读。
答案 7 :(得分:0)
这仍然是我的最佳答案:
project(myproject)
if(PROJECT_SOURCE_DIR STREQUAL PROJECT_BINARY_DIR)
message(FATAL_ERROR "In-source builds are not allowed")
endif()
或允许构建,但显示警告消息:
if(PROJECT_SOURCE_DIR STREQUAL PROJECT_BINARY_DIR)
message(WARNING "In-source builds are not recommended")
endif()
但是,似乎没有一种简单的方法可以避免在源目录中创建CMakeFiles/
和CMakeCache.txt
。