48

我想禁止人们将我们的源代码树与生成的 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源树中的文件。

我错过了更好的方法吗?

4

8 回答 8

56

CMake 有两个未记录的选项: CMAKE_DISABLE_SOURCE_CHANGESCMAKE_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;
}
于 2012-04-24T21:46:21.677 回答
7

包括一个这样的功能。它类似于您对这些差异所做的事情:

  1. 它被封装在一个函数中,当您包含该PreventInSourceBuilds.cmake模块时会调用该函数。您的主要 CMakeLists.txt 必须包含它:

    set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/CMake)
    include(PreventInSourceBuilds)
    
  2. 它使用带有 REALPATH 参数的get_filename_component()在比较路径之前解析符号链接。

如果 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()
于 2014-03-25T14:00:47.170 回答
5

我的/中有一个类似于这个的cmake()shell 函数:.bashrc.zshrc

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(或不直接调用)完全使用包装函数)。这很简单

于 2013-10-13T18:31:06.197 回答
4

我想我喜欢你的方式。cmake 邮件列表在回答这些类型的问题方面做得很好。

附带说明:您可以在失败的目录中创建一个“cmake”可执行文件。取决于是否“。” 在他们的路径中(在 linux 上)。你甚至可以对 /bin/false 进行符号链接。

在 Windows 中,我不确定是否首先找到了当前目录中的文件。

于 2009-07-30T19:13:34.283 回答
1

您可以像这样配置 .bashrc 文件

查看函数cmakekdekdebuild。设置 BUILD 和 SRC 环境。变量并根据您的需要编辑这些函数。这将仅在buildDir而不是srcDir中构建

于 2011-12-19T03:47:07.840 回答
0

只需由进行构建的人员/进程将目录设为只读即可。有一个单独的进程从源代码管理签出到目录(您正在使用源代码管理,对吗?),然后将其设为只读。

于 2009-07-30T19:13:37.950 回答
0

对于那些在 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 ..
于 2014-11-17T17:27:41.947 回答
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在源目录中创建。

于 2020-05-27T10:45:20.160 回答