2009-07-30 9 views
35

Quiero prohibir que las personas atemperen nuestro árbol fuente con los archivos CMake generados ... y, lo que es más importante, no permitirles pisar el existente Makefiles que no forme parte del mismo proceso de compilación para el que estamos utilizando CMake. (Mejor no preguntar)Con cmake, ¿cómo inhabilitarías las compilaciones in-source?

La forma en que he llegado con hacer esto es tener un par de líneas en la parte superior de mi CMakeLists.txt, de la siguiente manera:

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

Sin embargo, hacerlo de esta manera parece demasiado detallado. Además, si intento una compilación in-source, aún crea el directorio CMakeFiles/ y el archivo CMakeCache.txt en el árbol de fuentes antes de que se produzca el error.

¿Me está faltando una mejor manera de hacerlo?

+0

Lo hacemos exactamente como esta. – JesperE

+2

Esta es la mejor solución que he encontrado hasta ahora. Sin embargo, podría hacer que el mensaje sea más informativo: message (FATAL_ERROR "No se permiten compilaciones in-source. Cree una carpeta separada para compilación: \ nmkdir build; cd build; cmake ... \ nAntes de eso, elimine los archivos ya creados: \ nrm -rf CMakeCache.txt CMakeFiles ") – Tronic

Respuesta

3

Creo que me gusta su camino. La lista de correo de cmake hace un buen trabajo respondiendo este tipo de preguntas.

Como nota al margen: puede crear un archivo ejecutable "cmake" en el directorio que falla. Dependiendo de si "o no". está en su camino (en Linux). Incluso puedes hacer un enlace simbólico/bin/falso.

En Windows, no estoy seguro de si se encuentra primero un archivo en su directorio actual o no.

+0

Buena idea; Lo interpretaré como poner algo en $ PATH que interceptará la llamada a cmake, o simplemente un script separado que lo envolverá. O tal vez un alias estándar. A menos que haya una forma "nativa" de hacer esto en cmake, creo que ese es el camino a seguir. Y sí, creo en Windows '.' está implícitamente en $ PATH; en UNIX no lo es, pero siempre podríamos poner un envoltorio de cmake en otro lugar en $ PATH. – mpontillo

+20

¿Qué tipo de nutter tiene. en su camino? – Draemon

+1

La idea falsa de "cmake" no funcionará por defecto, como suele ser "." no estará en su camino. –

0

Simplemente haga que el directorio sea de solo lectura por las personas/procesos que realizan las compilaciones. Tenga un proceso por separado que verifique el directorio desde el control de origen (está usando el control de código fuente, ¿verdad?), Luego haga que sea de solo lectura.

+0

Gracias por la respuesta. Desafortunadamente, debido a la forma en que funciona nuestro sistema de control de fuente, no sería práctico hacerlo de esta manera. Estaba buscando una solución más general. – mpontillo

1

puede configurar su archivo .bashrc como this one

mirada a las funciones cmakekde y kdebuild. Establecer BUILD y SRC env. variables y edite estas funciones de acuerdo a sus necesidades. Esto se basará únicamente en builddir en lugar de SRCDIR

46

CMake tiene dos opciones: indocumentados CMAKE_DISABLE_SOURCE_CHANGES y 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) 

-

[email protected]:~/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/Fuente/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

¡Impresionante! Esta debería ser la respuesta aceptada. – Nav

+4

Desafortunadamente, esto no impide que CMake cree CMakeCache.txt y CMakeFiles/y por lo tanto, no es mejor que señalar un error (y es peor porque proporciona un mensaje críptico). – Tronic

+1

Simplemente cree un directorio con el nombre "CMakeCache.txt" para evitar la creación de un archivo de caché. –

5

que tienen una función cmake() cáscara similares en mi .bashrc/.zshrc a éste:

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 
} 

prefiero esta solución bajo ceremonia. Me deshice de la mayor queja de mis colegas cuando cambiamos a CMake, pero no impide que las personas que realmente quieran hacer una compilación in-source/top-of-tree de hacerlo, pueden invocar directamente /usr/bin/cmake (o no use la función de envoltura en absoluto). Y es estúpido simple.

+0

El problema con eso es que no es portátil y no está explícito en las fuentes. –

+0

Me gusta su solución. Es simple y soluciona el problema. – aaragon

7

Incluya una función como this one.Es similar a lo que se hace con estas diferencias:

  1. que se encapsula en una función que se llama cuando se incluye el módulo de PreventInSourceBuilds.cmake. Su CMakeLists.txt principal debe incluir:

    set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/CMake) 
    include(PreventInSourceBuilds) 
    
  2. Utiliza get_filename_component() con el parámetro de la ruta real que resuelve los enlaces simbólicos antes de comparar los caminos.

En caso de que los cambios de enlace github, aquí está el código fuente del módulo (que debe ser colocado en un PreventInSouceBuilds.cmake, en un directorio llamado CMake, en el ejemplo anterior):

# 
# 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() 
+0

Gracias. He editado esta respuesta para incluir el código fuente. Me gusta este enfoque. – mpontillo

1

Para los que tienen Linux:

añadir a alto nivel CMakeLists.txt:

set(CMAKE_DISABLE_IN_SOURCE_BUILD ON) 

c rear un 'dotme' archivo en su máximo nivel o agregar a su .bashrc (a nivel mundial):

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

Ahora ejecute:

. ./dotme 

cuando intenta ejecutar cmake en la fuente de alto nivel árbol:

$ cmake . 
CMAKE_DISABLE_IN_SOURCE_BUILD ON 

No se generan CMakeFiles/o CMakeCache.txt.

Al hacer construir fuera de la fuente y lo que necesita para funcionar CMAKE primera vez simplemente llamar al ejecutable real:

$ cd build 
$ /usr/bin/cmake .. 
Cuestiones relacionadas