使用cmake,您将如何禁用源内构建?

时间:2009-07-30 19:08:17

标签: build cmake

我想禁止人们使用生成的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文件。

我错过了更好的方法吗?

8 个答案:

答案 0 :(得分:49)

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;
}

答案 1 :(得分:7)

包含this one之类的功能。它与您对这些差异的处理方式类似:

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

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

  3. 如果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