2009-07-30 7 views
35

Je veux interdire aux gens d'encombrer notre arborescence source avec les fichiers CMake générés ... et, surtout, les empêcher de marcher sur les Makefiles existants qui ne font pas partie du même processus de construction que nous utilisons pour CMake. (Préférable de ne pas demander)Avec cmake, comment désactiver les builds in-source?

La façon dont je suis venu avec pour ce faire est d'avoir quelques lignes en haut de mon CMakeLists.txt, comme suit:

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

Cependant, cette façon de faire semble trop verbeux. En outre, si j'essaie une version in-source, elle crée toujours le répertoire CMakeFiles/ et le fichier CMakeCache.txt dans l'arborescence source avant le lancement de l'erreur.

Ai-je une meilleure façon de faire?

+0

Nous le faisons exactement comme cela. – JesperE

+2

C'est la meilleure solution que j'ai trouvée jusqu'ici. Vous pouvez rendre le message plus instructif, cependant: message (FATAL_ERROR "Les constructions In-source ne sont pas autorisées Créer un dossier séparé pour construire: \ nmkdir build; cd build; cmake .. \ nAvant cela, supprimez les fichiers déjà créés: \ nrm -rf CMakeCache.txt CMakeFiles ") – Tronic

Répondre

3

Je pense que j'aime votre chemin. La liste de diffusion cmake fait un bon travail pour répondre à ces types de questions. En remarque: vous pouvez créer un fichier exécutable "cmake" dans le répertoire qui échoue. Selon que "." est dans leur chemin (sur Linux). Vous pourriez même symlink/bin/false.

Dans Windows, je ne suis pas sûr si un fichier dans votre répertoire actuel est trouvé en premier ou non.

+0

Bonne idée; Je vais interpréter cela comme mettre quelque chose sur le $ PATH qui va intercepter l'appel à cmake - ou simplement un script séparé qui va l'envelopper. Ou peut-être un alias standard. À moins qu'il y ait un moyen «indigène» de le faire dans cmake, je pense que c'est la voie à suivre. Et oui, je crois sur Windows '.' est implicitement sur le $ PATH; sous UNIX, ce n'est pas le cas, mais nous pourrions toujours placer un wrapper cmake ailleurs dans le $ PATH. – mpontillo

+20

Quel genre de noisette a. sur leur chemin? – Draemon

+1

La fausse idée "cmake" ne fonctionnera pas par défaut, comme d'habitude "." ne sera pas sur leur chemin. –

0

Créez simplement le répertoire en lecture seule par les personnes/processus qui exécutent les générations. Avoir un processus séparé qui vérifie dans le répertoire du contrôle de la source (vous utilisez le contrôle de la source, n'est-ce pas?), Puis le rend en lecture seule.

+0

Merci pour la réponse. Malheureusement, en raison du fonctionnement de notre système de contrôle de source et de notre système, il serait impossible de le faire de cette façon. Je cherchais une solution plus générale. – mpontillo

1

Vous pouvez configurer votre fichier .bashrc comme this one

Regardez les fonctions cmakekde et kdebuild. Définir BUILD et SRC env. variables et éditer ces fonctions selon vos besoins. Cela va construire que dans BuildDir plutôt que SRCDIR

46

CMake a deux options sans papier: CMAKE_DISABLE_SOURCE_CHANGES et 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

Génial! Cela devrait être la réponse acceptée. – Nav

+4

Malheureusement, ceci n'empêche pas CMake de créer CMakeCache.txt et CMakeFiles/et donc cela ne vaut pas mieux que de signaler une erreur (et c'est pire car cela donne un message crypté). – Tronic

+1

Créez simplement un répertoire avec le nom "CMakeCache.txt" pour éviter de créer un fichier cache. –

5

J'ai une fonction shell cmake() dans mon .bashrc/.zshrc semblable à celui-ci:

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 
} 

Je préfère cette solution à faible cérémonie. Il s'est débarrassé de la plus grande plainte de mes collègues lorsque nous sommes passés à CMake, mais cela n'empêche pas les gens qui veulent vraiment faire une construction in-source/top-of-tree - ils peuvent simplement appeler directement /usr/bin/cmake (ou n'utilisez pas la fonction wrapper du tout). Et c'est stupide simple.

+0

Le problème avec cela est que ce n'est pas portable et n'est pas explicite dans les sources. –

+0

J'aime votre solution. C'est simple et ça résout le problème. – aaragon

7

Inclut une fonction comme this one.Il est semblable à ce que vous faites avec ces différences:

  1. Il est encapsulé dans une fonction, qui est appelée lorsque vous incluez le module PreventInSourceBuilds.cmake. Votre principale CMakeLists.txt doit inclure:

    set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/CMake) 
    include(PreventInSourceBuilds) 
    
  2. Il utilise get_filename_component() avec le paramètre Realpath qui résout les liens symboliques avant de comparer les chemins.

En cas de changement de lien github, voici le code source du module (qui devrait être placé dans un PreventInSouceBuilds.cmake, dans un répertoire appelé CMake, dans l'exemple ci-dessus):

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

Merci. J'ai modifié cette réponse pour inclure le code source. J'aime cette approche. – mpontillo

1

Pour ceux qui Linux:

ajouter à haut niveau CMakeLists.txt:

set(CMAKE_DISABLE_IN_SOURCE_BUILD ON) 

c réer un fichier « dotme » dans votre haut niveau ou ajouter à votre .bashrc (globalement):

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

Exécuter maintenant:

. ./dotme 

lorsque vous essayez d'exécuter CMake dans la source de haut niveau arbre:

$ cmake . 
CMAKE_DISABLE_IN_SOURCE_BUILD ON 

Pas CMakeFiles/ou CMakeCache.txt est généré.

Quand vous faites hors de la source et la construction, vous devez exécuter cmake première fois il suffit d'appeler l'exécutable réel:

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