With cmake, how would you disable in-source builds

2020-02-20 07:33发布

I want to disallow people from cluttering our source tree with generated CMake files... and, more importantly, disallow them from stepping on existing Makefiles that are not part of the same build process we're using CMake for. (best not to ask)

The way I have come up with to do this is to have a few lines at the top of my CMakeLists.txt, as follows:

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}")

However, doing it this way seems too verbose. Additionally, if I try an in-source build it still creates the the CMakeFiles/ directory, and the CMakeCache.txt file in the source tree before the error is thrown.

Am I missing a better way to do this?

标签: build cmake
7条回答
啃猪蹄的小仙女
2楼-- · 2020-02-20 08:09

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.

查看更多
Evening l夕情丶
3楼-- · 2020-02-20 08:10

You can configure your .bashrc file like this one

Look at the functions cmakekde and kdebuild. Set BUILD and SRC env. variables and edit these functions according to your needs. This will build only in buildDir rather than srcDir

查看更多
看我几分像从前
4楼-- · 2020-02-20 08:21

Include a function like this one. It is similar to what you do with these differences:

  1. 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)
    
  2. 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()
查看更多
家丑人穷心不美
5楼-- · 2020-02-20 08:23

Just make the directory read-only by the people/processes doing the builds. Have a separate process that checks out to the directory from source control (you are using source control, right?), then makes it read-only.

查看更多
你好瞎i
6楼-- · 2020-02-20 08:28

I think I like your way. The cmake mailing list does a good job at answering these types of questions.

As a side note: you could create a "cmake" executable file in the directory which fails. Depending on whether or not "." is in their path (on linux). You could even symlink /bin/false.

In windows, I am not sure if a file in your current directory is found first or not.

查看更多
你好瞎i
7楼-- · 2020-02-20 08:30

For those on Linux:

add to top-level CMakeLists.txt:

set(CMAKE_DISABLE_IN_SOURCE_BUILD ON)

create a file 'dotme' in your top-level or add to your .bashrc (globally):

#!/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

now run:

. ./dotme

when you try to run cmake in the top-level source tree:

$ cmake .
CMAKE_DISABLE_IN_SOURCE_BUILD ON

No CMakeFiles/ or CMakeCache.txt gets generated.

When doing out-of-source build and you need to run cmake first time just call the actual executable:

$ cd build
$ /usr/bin/cmake ..
查看更多
登录 后发表回答