2009-07-30 9 views
35

Voglio impedire alle persone di ingombrare il nostro albero dei sorgenti con file CMake generati ... e, cosa ancora più importante, non consentire loro di passare allo Makefiles esistente che non fa parte dello stesso processo di generazione per cui utilizziamo CMake. (Meglio non chiedere)Con cmake, come si disabiliteranno le build in-source?

Il modo in cui sono venuto su con per farlo è quello di avere poche righe nella parte superiore della mia CMakeLists.txt, come segue:

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

Tuttavia, facendo in questo modo sembra troppo prolisso. Inoltre, se provo una build in-source, crea ancora la directory CMakeFiles/ e il file CMakeCache.txt nell'albero di origine prima che venga generato l'errore.

Mi manca un modo migliore per farlo?

+0

Lo facciamo esattamente come questo. – JesperE

+2

Questa è la soluzione migliore che ho trovato finora. Potresti rendere il messaggio più informativo, tuttavia: messaggio (FATAL_ERROR "Le build in-source non sono consentite. Crea una cartella separata per la costruzione: \ nmkdir build; cd build; cmake .. \ nPrima di quello, rimuovi i file già creati: \ nrm -rf CMakeCache.txt CMakeFiles ") – Tronic

risposta

3

Penso che mi piaccia la strada. La mailing list cmake fa un buon lavoro nel rispondere a questi tipi di domande.

Come nota a margine: è possibile creare un file eseguibile "cmake" nella directory che non riesce. A seconda che "o". è nel loro percorso (su linux). Potresti anche collegare simbolicamente/bin/false.

In Windows, non sono sicuro che prima venga trovato un file nella directory corrente o meno.

+0

Buona idea; Lo interpreterò come mettendo qualcosa sul $ PATH che intercetterà la chiamata a cmake - o semplicemente uno script separato che lo avvolgerà. O forse un alias standard. A meno che non ci sia un modo "nativo" per farlo in cmake, penso che sia la strada da percorrere. E sì, credo su Windows '.' è implicitamente sul $ PATH; su UNIX non lo è, ma potremmo sempre mettere un wrapper cmake da qualche altra parte nel $ PATH. – mpontillo

+20

Che tipo di nutter ha. sul loro cammino? – Draemon

+1

La falsa idea "cmake" non funzionerà di default, come al solito "." non sarà sulla loro strada –

0

Basta fare in modo che la directory sia di sola lettura per le persone/i processi che eseguono le build. Avere un processo separato che controlla la directory dal controllo del codice sorgente (si sta utilizzando il controllo del codice sorgente, giusto?), Quindi lo rende di sola lettura.

+0

Grazie per la risposta. Sfortunatamente, a causa del modo in cui funziona il nostro sistema di controllo e sistema sorgente, sarebbe impraticabile farlo in questo modo. Stavo cercando una soluzione più generale. – mpontillo

1

È possibile configurare il file .bashrc come this one

Guardate le funzioni cmakekde e kdebuild. Imposta ENV BUILD e SRC. variabili e modificare queste funzioni in base alle proprie esigenze. Questo costruisce solo in builddir piuttosto che srcdir

46

CMake ha due opzioni non documentate: CMAKE_DISABLE_SOURCE_CHANGES e 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/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

Fantastico! Questa dovrebbe essere la risposta accettata. – Nav

+4

Sfortunatamente questo non impedisce a CMake di creare CMakeCache.txt e CMakeFiles/e quindi non è meglio che segnalare un errore (ed è peggio in quanto dà un messaggio criptico). – Tronic

+1

Basta creare una directory con il nome "CMakeCache.txt" per evitare di creare file di cache. –

5

Ho una funzione cmake() shell nel mio .bashrc/.zshrc simile a questo:

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 
} 

preferisco questa soluzione a basso cerimonia. Si è sbarazzato della più grande lamentela dei miei colleghi quando siamo passati a CMake, ma non impedisce alle persone che in realtà vogliono fare una compilazione in-source/top-of-tree: possono semplicemente invocare /usr/bin/cmake direttamente (o non usare affatto la funzione wrapper). Ed è stupido semplice.

+0

Il problema è che non è portatile e non è esplicito nelle fonti. –

+0

Mi piace la tua soluzione. È semplice e risolve il problema. – aaragon

7

Includere una funzione come this one.E 'simile a quello che si fa con queste differenze:

  1. Si è incapsulato in una funzione, che si chiama quando si include il modulo PreventInSourceBuilds.cmake. Il tuo CMakeLists.txt principale deve includerlo:

    set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/CMake) 
    include(PreventInSourceBuilds) 
    
  2. Usa get_filename_component() con il parametro realpath che risolve i collegamenti simbolici prima di confrontare i percorsi.

Nel caso in cui i cambiamenti di collegamento GitHub, ecco il codice sorgente del modulo (che dovrebbe essere collocato in un PreventInSouceBuilds.cmake, in una directory chiamata CMake, nell'esempio di cui sopra):

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

Grazie. Ho modificato questa risposta per includere il codice sorgente. Mi piace questo approccio. – mpontillo

1

Per coloro che su Linux:

aggiungere al livello superiore CMakeLists.txt:

set(CMAKE_DISABLE_IN_SOURCE_BUILD ON) 

c Reate un file 'dotme' nel vostro livello superiore o aggiungere al vostro .bashrc (a livello mondiale):

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

ora gestita:

. ./dotme 

quando si tenta di eseguire cmake nella sorgente di livello superiore albero:

$ cmake . 
CMAKE_DISABLE_IN_SOURCE_BUILD ON 

Nessun CMakeFiles/o CMakeCache.txt generato.

Quando si esegue out-of-source accumulo ed è necessario eseguire cmake prima volta basta chiamare l'eseguibile vero e proprio:

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