Répertoire de sortie / construction de CMake

116

Je suis assez nouveau dans CMake, et j'ai lu quelques tutoriels sur la façon de l'utiliser, et j'ai écrit quelques 50 lignes compliquées de script CMake afin de créer un programme pour 3 compilateurs différents. Ceci conclut probablement toutes mes connaissances sur CMake.

Maintenant, mon problème est que j'ai du code source, dont je ne veux pas toucher / manipuler le dossier lorsque je crée le programme. Je veux que tous makeles fichiers et dossiers CMake et de sortie entrent dans ../Compile/, donc j'ai changé quelques variables dans mon script CMake pour cela, et cela a fonctionné pendant un certain temps lorsque j'ai fait quelque chose comme ça sur mon ordinateur portable:

Compile$ cmake ../src
Compile$ make

Où avec cela j'ai eu une sortie propre dans le dossier dans lequel je suis en ce moment, ce qui est exactement ce que je recherche.

Maintenant, je suis passé à un autre ordinateur, et j'ai recompilé CMake 2.8.11.2, et je suis presque revenu à la case départ! Il compile toujours la chose dans le srcdossier où CMakeLists.txtse trouve my .

La partie où je choisis le répertoire dans mon script CMake est la suivante:

set(dir ${CMAKE_CURRENT_SOURCE_DIR}/../Compile/)
set(EXECUTABLE_OUTPUT_PATH ${dir} CACHE PATH "Build directory" FORCE)
set(LIBRARY_OUTPUT_PATH ${dir} CACHE PATH "Build directory" FORCE)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${dir})
set(CMAKE_BUILD_FILES_DIRECTORY ${dir})
set(CMAKE_BUILD_DIRECTORY ${dir})
set(CMAKE_BINARY_DIR  ${dir})
SET(EXECUTABLE_OUTPUT_PATH ${dir})
SET(LIBRARY_OUTPUT_PATH ${dir}lib)
SET(CMAKE_CACHEFILE_DIR ${dir})

Et maintenant, cela se termine toujours par:

-- Build files have been written to: /.../src

Est-ce que je manque quelque chose?

Le physicien quantique
la source
4
Il n'est pas nécessaire de définir toutes les variables que vous définissez. CMake les définit sur des valeurs par défaut raisonnables. Vous ne devriez certainement pas modifier CMAKE_BINARY_DIRou CMAKE_CACHEFILE_DIR. Que se passe-t-il si vous supprimez tous ces set()appels et faites simplement cd Compile; rm -rf *; cmake ../src?
Angew n'est plus fier de SO
5
En gros, tant que vous êtes en dehors du répertoire source lors de l'exécution de CMake, il ne modifiera pas le répertoire source à moins que votre CMakeList ne le lui dise explicitement.
Angew n'est plus fier de SO
@Angew Merci pour la pointe, qui est surprenante! J'ai supprimé toutes ces lignes et juste utilisé cmake ../src et cela a fonctionné comme un charme! C'est tellement surprenant parce que je l'ai essayé avant quand j'ai appris CMake et cela n'a pas fonctionné. Veuillez mettre votre réponse dans une réponse officielle pour vous donner la grosse coche :)
The Quantum Physicist
1
Ce qui m'a sauvé, c'est la remarque de @Adam Bowen selon laquelle "vous ne pouvez pas créer une compilation hors source pour un répertoire source avec une construction in-source"
Aur Saraf

Réponses:

60

Il n'est pas nécessaire de définir toutes les variables que vous définissez. CMake les définit sur des valeurs par défaut raisonnables. Vous ne devez absolument pas modifier CMAKE_BINARY_DIRouCMAKE_CACHEFILE_DIR . Traitez-les en lecture seule.

Supprimez d'abord le fichier de cache problématique existant du répertoire src:

cd src
rm CMakeCache.txt
cd ..

Ensuite, supprimez toutes les set()commandes et faites:

cd Compile
rm -rf *
cmake ../src

Tant que vous êtes en dehors du répertoire source lors de l'exécution de CMake, il ne modifiera pas le répertoire source à moins que votre CMakeList ne le lui dise explicitement.

Une fois que cela fonctionne, vous pouvez regarder où CMake place les choses par défaut, et seulement si vous n'êtes pas satisfait des emplacements par défaut (tels que la valeur par défaut de EXECUTABLE_OUTPUT_PATH), ne modifiez que ceux dont vous avez besoin. Et essayer de les exprimer par rapport à CMAKE_BINARY_DIR, CMAKE_CURRENT_BINARY_DIR,PROJECT_BINARY_DIR etc.

Si vous regardez la documentation de CMake, vous verrez des variables partitionnées en sections sémantiques. Sauf dans des circonstances très spéciales, vous devez traiter toutes celles répertoriées sous «Variables qui fournissent des informations» en lecture seule à l'intérieur de CMakeLists.

Angew n'est plus fier de SO
la source
2
J'ai commencé à utiliser cmake avec des builds dans le répertoire src ... cette technique a échoué au départ. Une fois que j'ai supprimé tous les fichiers / caches de construction cmake dans le répertoire src, cette technique a fonctionné. Merci!
Avi Tevet
18
Il vaut peut-être mieux ne pas conseiller d'utiliser rm -rf *. Ce n'est pas joli si cd Compileéchoue ...
Roman
2
@Roman Je considère ces exemples de ligne de commande comme du pseudo-code. C'est moins verbeux et plus précis que de taper "entrez dans le répertoire Compile, supprimez tout ce qui s'y trouve, puis exécutez CMake avec un chemin vers le répertoire source". J'assume le bon sens et le jugement de base d'une partie du lecteur.
Angew n'est plus fier du SO
@AviTevet: Je pense que c'est la bonne réponse. S'il y a des fichiers de cache cmake à partir d'un appel précédent de cmake dans le répertoire source, vous n'obtiendrez pas cmake pour choisir un autre répertoire pour les fichiers générés, sauf si vous supprimez tous les anciens du répertoire source. Comportement assez cassé par CMake à mon avis. Pourquoi n'écris-tu pas une autre réponse?
Jo So
113

Il semble que vous vouliez une construction hors source . Il existe plusieurs façons de créer une version hors source.

  1. Fais ce que tu faisais, cours

    cd /path/to/my/build/folder
    cmake /path/to/my/source/folder

    ce qui entraînera cmake pour générer un arbre de construction dans /path/to/my/build/folderle arbre source dans /path/to/my/source/folder.

    Une fois que vous l'avez créé, cmake se souvient où se trouve le dossier source - vous pouvez donc réexécuter cmake sur l'arborescence de construction avec

    cmake /path/to/my/build/folder

    ou même

    cmake .

    si votre répertoire actuel est déjà le dossier de construction.

  2. Pour CMake 3.13 ou version ultérieure, utilisez ces options pour définir les dossiers source et build

    cmake -B/path/to/my/build/folder -S/path/to/my/source/folder
  3. Pour les anciens CMake, utilisez des options non documentées pour définir les dossiers source et build :

    cmake -B/path/to/my/build/folder -H/path/to/my/source/folder

    qui fera exactement la même chose que (1), mais sans s'appuyer sur le répertoire de travail actuel.

CMake met toutes ses sorties dans l' arborescence de construction par défaut, donc à moins que vous n'utilisiez généreusement ${CMAKE_SOURCE_DIR}ou ${CMAKE_CURRENT_SOURCE_DIR}dans vos fichiers cmake, il ne devrait pas toucher votre arborescence source .

La plus grande chose qui peut mal tourner est si vous avez précédemment généré une arborescence de construction dans votre arborescence source (c'est-à-dire que vous avez une construction source ). Une fois que vous avez fait cela, la deuxième partie de (1) ci-dessus entre en jeu et cmake n'apporte aucune modification à la source ou aux emplacements de construction. Par conséquent, vous ne pouvez pas créer de build hors source pour un répertoire source avec une build in-source . Vous pouvez résoudre ce problème assez facilement en supprimant (au minimum) CMakeCache.txtdu répertoire source. Il existe quelques autres fichiers (principalement dans leCMakeFiles répertoire) que CMake génère que vous devriez également supprimer, mais ceux-ci n'amèneront pas cmake à traiter l'arborescence source comme une arborescence de construction.

Étant donné que les builds hors source sont souvent plus souhaitables que les builds in-source, vous voudrez peut-être modifier votre cmake pour exiger des builds hors source:

# Ensures that we do an out of source build

MACRO(MACRO_ENSURE_OUT_OF_SOURCE_BUILD MSG)
     STRING(COMPARE EQUAL "${CMAKE_SOURCE_DIR}"
     "${CMAKE_BINARY_DIR}" insource)
     GET_FILENAME_COMPONENT(PARENTDIR ${CMAKE_SOURCE_DIR} PATH)
     STRING(COMPARE EQUAL "${CMAKE_SOURCE_DIR}"
     "${PARENTDIR}" insourcesubdir)
    IF(insource OR insourcesubdir)
        MESSAGE(FATAL_ERROR "${MSG}")
    ENDIF(insource OR insourcesubdir)
ENDMACRO(MACRO_ENSURE_OUT_OF_SOURCE_BUILD)

MACRO_ENSURE_OUT_OF_SOURCE_BUILD(
    "${CMAKE_PROJECT_NAME} requires an out of source build."
)

La macro ci-dessus provient d'un module couramment utilisé appelé MacroOutOfSourceBuild. Il existe de nombreuses sources MacroOutOfSourceBuild.cmakesur Google, mais je n'arrive pas à trouver l'original et il est assez court pour l'inclure ici dans son intégralité.

Malheureusement, cmake a généralement écrit quelques fichiers au moment où la macro est appelée, donc même si cela vous empêchera d'exécuter réellement la construction, vous devrez toujours supprimer CMakeCache.txtet CMakeFiles.

Vous pouvez trouver utile de définir les chemins dans lesquels les binaires, les bibliothèques partagées et statiques sont écrits - dans ce cas, voyez comment puis-je transformer la sortie cmake dans un répertoire 'bin'? (avertissement, j'ai la réponse la plus votée sur cette question ... mais c'est comme ça que je le sais).

Adam Bowen
la source
En fait, l'option pour définir le dossier source est -S, pas-H
smac89
@ smac89 Merci! Il semble qu'ils les aient documentés dans la version 3.13 - j'ai mis à jour la réponse pour refléter CMake moderne.
Adam Bowen
8

Transformer mon commentaire en réponse:

Au cas où quelqu'un ferait ce que j'ai fait, commencer par mettre tous les fichiers de construction dans le répertoire source:

cd src
cmake .

CMake mettre un tas de fichiers de compilation et les fichiers cache ( CMakeCache.txt, CMakeFiles, cmake_install.cmake, etc.) dans la srcdir.

Pour passer à une version hors source, j'ai dû supprimer tous ces fichiers. Ensuite, je pourrais faire ce que @Angew recommandait dans sa réponse:

mkdir -p src/build
cd src/build
cmake ..
Avi Tevet
la source
7

À partir de CMake Wiki :

CMAKE_BINARY_DIR si vous construisez dans la source, c'est la même chose que CMAKE_SOURCE_DIR, sinon c'est le répertoire de niveau supérieur de votre arborescence de construction

Comparez ces deux variables pour déterminer si la construction hors source a été lancée

damkrat
la source
6

Vous ne devez pas vous fier à un nom de répertoire de construction codé en dur dans votre script, donc la ligne avec ../Compiledoit être modifiée.

C'est parce que ce devrait être à l'utilisateur où compiler.

Au lieu de cela, utilisez l'une des variables prédéfinies: http://www.cmake.org/Wiki/CMake_Useful_Variables (recherchez CMAKE_BINARY_DIRet CMAKE_CURRENT_BINARY_DIR)

Michał Walenciak
la source
2
c'est exactement ce que je recherchais - CMAKE_CURRENT_BINARY_DIR, je dirais généralement le chemin de construction binaire actuel. Peut-être peut être utilisé pour définir les compilations libs / bin dépendantes.
parasrish