Ninja: mélanger les chemins absolus depfile avec les chemins relatifs manifestes casse les reconstructions

Créé le 24 févr. 2017  ·  70Commentaires  ·  Source: ninja-build/ninja

Le manuel ninja met en garde contre un tel mélange, mais c'est devenu une limitation sérieuse.

Le problème est que les gens veulent que leurs systèmes de construction invoquent le compilateur avec un chemin absolu vers le fichier source. Cela produit une meilleure sortie pour les IDE pour faire correspondre les messages d'erreur et se référer aux fichiers d'origine. Cela peut également affecter les chemins enregistrés dans les informations de débogage. Cependant, cela entre en conflit avec la préférence de ninja pour les chemins relatifs dans le manifeste de construction.

Voici un script illustrant le problème : ninja-bug.bash.txt

Commentaire le plus utile

Je ne pense vraiment pas que la solution devrait être "contourner cela dans tous les autres outils".

1924 démontre un correctif de travail complet avec des tests, basé sur l'approche ninja_workdir . Un générateur utilisant cela peut résoudre tous les problèmes ci-dessus.

Tous les 70 commentaires

Cc : @nico @chaoren

Dans CMake, il y a une discussion pertinente dans le numéro 16675 , le numéro 13894 et le MR 520 .

Comme solution de contournement, vous pouvez définir explicitement le répertoire de sortie de l'objet, même "." ou "..", mais le chemin absolu fonctionne également.
ninjatst.bash.txt

@zlolik IIUC, vous suggérez de placer des chemins absolus dans les nœuds de graphique du manifeste de construction ( build.ninja ). Cela fonctionne certainement (et c'est ce que fait CMake dans les versions hors source), mais ce que je veux dire ici, c'est que Ninja décourage l'utilisation de chemins absolus et pourtant les IDE les exigent en sortie.

Il est également hypothétiquement possible qu'un compilateur donné -c foo.c puisse de toute façon générer un chemin absolu dans le fichier dep. Si cela se produit, Ninja ne reconnaîtra pas la dépendance en raison du même problème signalé ici.

Pour résoudre ce problème, Ninja doit être capable de reconnaître quand un chemin relatif et un chemin absolu sont le même fichier et n'ont qu'un seul nœud de graphique en interne au lieu de deux. Faire cela uniquement pour le traitement depfile peut être suffisant, car il est raisonnable de demander aux générateurs build.ninja de nommer les chemins de manière cohérente dans le manifeste de construction.

@bradking Tout d'abord, je suis d'accord avec vous que nous avons un problème avec ninja et je ne suggère qu'une solution de contournement.
Je pense qu'il y a 3 problèmes liés :

  1. Logique avec entrée chemin absolu/relatif, plus de détails dans #1152 .
  2. Logique pour forcer le chemin absolu/relatif de sortie. Le problème avec les compilateurs - la seule façon de dire au compilateur que vous voulez avoir un chemin absolu en sortie est d'utiliser un chemin absolu dans la ligne de commande. Pas un problème de ninja mais le nôtre.
  3. Logique pour analyser le chemin absolu/relatif depfile. Ce problème.

J'utilise 2 solutions de contournement :

  1. Utilisez les préfixes $p et $o dans le chemin du générateur build.ninja pour résoudre les 2 premiers problèmes. Dans mon cas, $p et $o ne sont pas absolus mais relatifs à partir du répertoire actuel où le générateur build.ninja a été exécuté.
  2. Utilisez un script pour convertir depfile en chemin compatible ninja. Certains compilateurs ont même besoin d'appels séparés pour générer depfile. Mais il n'y a pas de problème de chemin absolu while.

Pour référence, j'ai lancé un fil de discussion sur la liste de diffusion ninja-build avec une solution proposée.

Un autre problème lié aux informations de débogage et de couverture : l'utilisation de commandes avec des chemins relatifs crée également des fichiers d'informations de débogage avec des chemins relatifs. Le problème est que les fichiers de débogage sont généralement placés à côté des fichiers objet, et non des fichiers source, de sorte que les chemins relatifs y font référence à des fichiers inexistants.

Une mise à jour pour ceci? Il n'y a pas eu de réponses sur le fil de discussion de la liste de diffusion...

Bonjour à tous,

Il est également hypothétiquement possible qu'un compilateur donné -c foo.c puisse de toute façon générer un chemin absolu dans le fichier dep.

Les fichiers de dépendance d'IAR v8 contiennent uniquement des chemins absolus.

Nous avons rencontré ce problème lors de la réalisation de builds hors source avec CMake/Ninja/IAR : les fichiers générés qui se retrouvent dans le répertoire binaire de CMake sont relatifs dans le manifeste Ninja, la sortie deps par IAR est absolue.

Pour moi, c'est clairement un problème Ninja : il ne devrait pas y avoir deux nœuds pour le même fichier, quoi qu'il arrive.

J'ai lu la suggestion de @bradking , mais je ne comprends pas vraiment la partie sur les liens symboliques et pourquoi getcwd() ne peut pas être utilisé. Cela vous dérangerait-il d'élaborer?

Je ne comprends pas vraiment la partie sur les liens symboliques et pourquoi getcwd() ne peut pas être utilisé

@sebknzl le problème est que les chemins absolus écrits dans build.ninja par le générateur peuvent contenir des liens symboliques qui ne sont intentionnellement pas résolus pour une raison ou une autre. getcwd() renvoie généralement un chemin avec des liens symboliques résolus. Si Ninja devait interpréter un chemin relatif dans le manifeste de construction ou un fichier dep relatif à getcwd() , le chemin absolu qu'il construit peut ne pas correspondre à ce que le générateur de manifeste de construction a utilisé et nous nous retrouverions toujours avec deux nœuds.

Le ninja_workdir que je propose dans le fil que vous avez lié indique essentiellement à Ninja ce que le générateur a utilisé comme base pour les chemins relatifs. En pratique, realpath(ninja_workdir) == realpath(getcwd()) devrait toujours être vrai, mais cela ne signifie pas ninja_workdir == getcwd() . Une autre alternative serait pour Ninja de tout realpath avant de créer des nœuds, mais cela signifierait que $in ne s'étendrait pas à ce que le générateur avait prévu.

@jhasse s'il vous plaît voir ce problème et ma proposition pour y remédier.

Pourquoi ne pas générer un _build.ninja_ avec des chemins absolus contrôlés par un CMAKE_NINJA_GENERATOR_OPTION_ ?

c'est-à-dire comme ceci, qui fonctionne:

Claus-MBP:build clausklein$ cat build.ninja 

# project dir
p = /Users/clausklein/Downloads
# object dir
o = /Users/clausklein/Downloads/.ninjatst.build

rule cp
  command = cp $in $out

rule cc
  depfile = $out.d
  deps = gcc
  command = cc -I$o -c $in -o $out -MD -MT $out -MF $out.d

# All absolute paths works
build all: phony $o/foo.o

# All absolute paths works
build $o/foo.h: cp $p/foo.h.in
  IN = $p/foo.h.in

# All absolute paths works
build $o/foo.o: cc $p/foo.c || $o/foo.h
  IN = "$p/foo.c"

default all

Claus-MBP:build clausklein$ 

généré avec ninjatst.bash.txt

@ClausKlein , nous avons essayé d'apprendre à CMake à utiliser des chemins absolus. Voir les discussions que j'ai liées dans https://github.com/ninja-build/ninja/issues/1251#issuecomment -282322776. Je préfère ne pas ajouter une option qui dit "faire les choses d'une manière différente qui résout certains cas et en casse d'autres".

Nous avons vraiment besoin de la fonctionnalité Ninja dans la proposition que j'ai liée dans https://github.com/ninja-build/ninja/issues/1251#issuecomment -487618865 pour résoudre ce problème correctement.

OK bien

Alors ce correctif pour le système mesonbuild serait également disponible ;-)

Suis 12.03.2020 à 12:56 schrieb Brad King [email protected] :

@ClausKlein https://github.com/ClausKlein , nous avons essayé d'apprendre à CMake à utiliser des chemins absolus. Voir les discussions que j'ai liées dans # 1251 (commentaire) https://github.com/ninja-build/ninja/issues/1251#issuecomment-282322776 . Je préfère ne pas ajouter une option qui dit "faire les choses d'une manière différente qui résout certains cas et en casse d'autres".

Nous avons vraiment besoin de la fonctionnalité Ninja dans la proposition que j'ai liée dans # 1251 (commentaire) https://github.com/ninja-build/ninja/issues/1251#issuecomment-487618865 pour résoudre ce problème correctement.


Vous recevez ceci parce que vous avez été mentionné.
Répondez directement à cet e-mail, consultez-le sur GitHub https://github.com/ninja-build/ninja/issues/1251#issuecomment-598146822 , ou désabonnez-vous https://github.com/notifications/unsubscribe-auth/AAN7QWWEDHMDA45DQVPLOUDRHDEVDANCNFSM4DBNL6GA .

Disons que Ninja utiliserait ninja_workdir pour faire correspondre les informations du fichier dep et nous avons la situation où ninja_workdir != getcwd() cause d'un lien symbolique. Et si le compilateur imprime maintenant des chemins absolus en utilisant getcwd() ?

Le compilateur ne doit pas utiliser getcwd() pour quoi que ce soit à moins que ces éléments n'aient été transmis en tant que chemins relatifs, auquel cas le générateur de système de construction doit probablement en assumer la responsabilité.

Ou nous pouvons envisager d'essayer de normaliser à la fois ninja_workdir et getcwd() .

Eh bien, le compilateur ne devrait pas non plus renvoyer un chemin absolu dans le depfile lorsqu'il reçoit des chemins relatifs ;)

@ClausKlein , nous avons essayé d'apprendre à CMake à utiliser des chemins absolus. Voir les discussions que j'ai liées dans #1251 (commentaire). Je préfère ne pas ajouter une option qui dit "faire les choses d'une manière différente qui résout certains cas et en casse d'autres".

Qu'est-ce qui s'est cassé exactement lorsque vous avez utilisé des chemins absolus comme suggéré par @ClausKlein ?

Si le compilateur reçoit des chemins absolus, le fichier dep qu'il génère a des chemins absolus, et ceux-ci ne sont pas réconciliés avec les chemins relatifs aux en-têtes dans le manifeste de construction, par exemple pour les en-têtes générés. Voir le lien ninja-bug.bash.txt dans mon premier message en haut de ce numéro. Il montre un exemple étape par étape de ce qui se passe et est exprimé uniquement en termes de Ninja et non de CMake.

J'ai lu cela, mais pourquoi ne pas utiliser https://github.com/ninja-build/ninja/issues/1251#issuecomment -284533599 ? Simplement parce que Ninja "déconseille" les chemins absolus ? Si oui, s'agit-il d'un changement de documentation ?

Les fichiers build.ninja sont beaucoup plus petits sans répéter les chemins absolus partout, ce qui les rend plus rapides. Ils sont également plus beaux, plus faciles à déboguer et plus appropriés pour la complétion par tabulation des noms de cibles de construction dans les shells. IMO c'est une bonne recommandation pour Ninja. Ninja a juste besoin d'un peu plus d'informations pour concilier cette affaire, et c'est ce que je propose.

Les chemins relatifs @bradking peuvent ne pas toujours être courts :

build jsoncpp@sha/src_lib_json_json_reader.cpp.o: cpp_COMPILER ../../../../../Users/clausklein/Workspace/cpp/jsoncpp/src/lib_json/json_reader.cpp
 DEPFILE = jsoncpp@sha/src_lib_json_json_reader.cpp.o.d
 ARGS = -Ijsoncpp<strong i="7">@sha</strong> -I. -I../../../../../Users/clausklein/Workspace/cpp/jsoncpp -I../../../../../Users/clausklein/Workspace/cpp/jsoncpp/include -I../../../../../Users/clausklein/Workspace/cpp/jsoncpp/dir1 -I../../../../../Users/clausklein/Workspace/cpp/jsoncpp/dir2 -fdiagnostics-color=always -pipe -Wall -Winvalid-pch -Wnon-virtual-dtor -std=c++17 -O3

mon exemple https://github.com/ninja-build/ninja/issues/1251#issuecomment -597877775 est plus joli !

Les générateurs de CMake ont pour règle de ne pas utiliser les séquences ../ qui quittent l'arborescence de construction. Dans les versions entièrement hors source, nous utilisons des chemins absolus vers l'arborescence source et des chemins relatifs dans l'arborescence de construction. Ces derniers ne démarrent jamais dans ../ car ils sont sous l'arborescence de construction.

Je sais, il a été généré avec _mesonbuild_ . ;-)

Mais alors, pourquoi ne pas nier la génération dans l'arbre des sources ?

Nous pouvons débattre indéfiniment des mérites des chemins relatifs et absolus. Ninja ne devrait pas avoir d'opinion à ce sujet. Le problème ici est de concilier les cas où les deux sont utilisés dans une seule version. Le générateur de buildsystem ne peut pas toujours contrôler ce que les outils feront avec les chemins. Ninja devrait prendre en charge les chemins mixtes absolus/relatifs vers le même fichier et peut le faire avec une approche simple que j'ai décrite dans ma proposition. Pour le cas d'utilisation motivant, les modifications sont isolées de l'analyse depfile.

Ninja devrait prendre en charge les chemins mixtes absolus/relatifs vers le même fichier

Je suis d'accord!

Merci pour toutes ces explications, je commence à comprendre.

Et si Ninja (lorsqu'il rencontrait un chemin absolu dans le fichier dep) realpath à la fois cwd et le chemin qu'il a trouvé? Ensuite, il supprimerait le cwd realpathed du depfile-path realpathed pour obtenir le chemin relatif à faire correspondre à l'en-tête généré. Est-ce que ça marcherait ?

getcwd() est toujours déjà un chemin réel, donc cette étape n'est pas nécessaire. Si Ninja devait realpath() le chemin absolu fourni par depfile et rechercher un préfixe cwd qui pourrait fonctionner. Cependant, realpath() est un appel système éventuellement coûteux, tandis que mon ninja_workdir proposé peut réconcilier les chemins uniquement en mémoire via le traitement des chaînes.

Le mélange dans l'autre sens devrait également être autorisé : un chemin absolu dans le manifeste de construction, mais un chemin relatif dans le fichier dep. Je ne pense pas que Ninja devrait avoir à realpath() chaque chemin absolu lors de l'analyse build.ninja . Ce serait probablement lent.

Nous pourrions utiliser le résultat pour déterminer le workdir. Par exemple:

getcwd() : /var/xyz/build
entrée depfile : /home/foo/build/bar.h
realpath (entrée du fichier dep): /var/xyz/build/bar.h
chemin réel relatif : bar.h
supprimez cela de l'entrée depfile : /home/foo/build -> ninja_workdir

De cette façon, nous n'avons besoin d'appeler realpath qu'une seule fois.

Je ne pense pas qu'il soit possible de dériver automatiquement ninja_workdir en général. Comment savoir combien de composants logiques du chemin logique original contenant le lien symbolique correspondent au workdir ? Nous pourrons peut-être le faire en prenant un composant à la fois jusqu'à ce que son chemin réel corresponde au cwd, mais cela semble hacky et sujet aux erreurs. Il semble risqué de faire confiance au premier lien symbolique qui ressemble à ceci. De plus, nous devrons exécuter realpath() sur chaque chemin absolu que nous rencontrons jusqu'à ce que l'on résolve de cette façon.

Le générateur de système de construction sait exactement quel chemin logique vers le workdir il a utilisé lors de la génération de chemins absolus dans les instructions de construction et les lignes de commande dans build.ninja . Il s'agit donc de la source d'informations la plus fiable pour le chemin workdir. Nous avons juste besoin d'un moyen de communiquer ces informations à Ninja, d'où ma proposition de liaison ninja_workdir .

Je ne suis pas sûr de comprendre, désolé. Pouvez-vous donner un exemple où ma logique de détection ne fonctionnerait pas ?

Il pourrait se casser si le générateur de buildsystem met un lien symbolique à l'intérieur de l'arbre de construction (pointant ailleurs dans l'arbre de construction ou tout à fait à l'extérieur):

getcwd() : /var/xyz/build
entrée depfile : /home/foo/build/subdir-link/bar.h
realpath (entrée du fichier dep): /var/xyz/build/subdir-real/bar.h
chemin réel relatif : subdir-real/bar.h
supprimez cela de l'entrée depfile : ???

CMake ne le fait pas, mais en général, un générateur de buildsystem pourrait le faire.

Même si nous sommes prêts à dire que ce n'est pas pris en charge, la détection pourrait toujours être confrontée à :

getcwd() : /var/xyz/build
1000 entrées de fichier dep: /home/foo/ext-lib/bar{1,2,...}.h
1000 realpath (entrées depfile): /var/xyz/ext-lib/bar{1,2,...}.h
1000 chemins réels relatifs : aucun sous cwd

Imaginez maintenant que cela apparaisse dans 1000 depfiles de sources et qu'il n'y ait jamais de résultat. Cela représente 1 million d'appels realpath() sans correspondance pour cette heuristique. Et cela se répète à chaque fois qu'une source est reconstruite et que son depfile est réanalysé.

lien symbolique à l'intérieur de l'arborescence de construction -> oui, nous ne pouvons pas vraiment supporter cela, cela entraînera de toute façon toutes sortes d'autres problèmes (sans realpath-ing partout).

Le deuxième exemple semble plutôt artificiel. Normalement, les fichiers dep commencent par les dépendances locales, et non par les en-têtes système.

S'il s'avère vraiment être un problème de performances, nous pourrions mettre en cache le workdir dans .ninja_deps ?

Dans une construction hors source, très peu d'entrées depfile pointeront même vers l'arborescence de construction. Ce sera très courant :

getcwd() : /var/xyz/build
1 000 entrées de fichier dep : /home/foo/project-source/bar{1,2,...}.h
1000 realpath (entrées depfile): /var/xyz/project-source/bar{1,2,...}.h
1000 chemins réels relatifs : aucun sous cwd

Ninja devra appeler realpath() sur tous ceux au cas où, ou maintenir une sorte de tableau de résultats pour éviter les appels système réels. Il ne peut pas savoir à l'avance quand il rencontrera un chemin de lien symbolique qui se résout en cwd, et ne sait même pas s'il en trouvera un.

Étant donné que le mélange de chemins absolus et réels dans le depfile ne fonctionne pas actuellement, je ne vois pas en quoi cela serait "très courant" ??

depfiles du formulaire dans mon exemple sont déjà très courants même lorsqu'ils n'utilisent pas de liens symboliques ou de chemins mixtes. Je les ai dans la plupart de mes arbres de construction. Ninja ne peut pas savoir à l'avance si l'heuristique est nécessaire, il devra donc bloquer les appels système realpath() au cas où.

J'ai peut-être mal compris ton exemple. Voulez-vous dire un depfile avec 3000 entrées ou ces 3 exemples distincts pour les depfiles avec 1000 entrées chacun?

Je voulais dire 1000 entrées depfile réparties sur un nombre quelconque de depfiles. Ça pourrait être un. Il pourrait y en avoir plusieurs. Il peut y avoir 10 000 entrées dans un projet. Leurs chemins peuvent pointer n'importe où sur le système de fichiers et peuvent ou non pointer vers l'arbre de construction.

Pouvez-vous donner un exemple CMakeLists.txt qui aboutit à un tel mélange de chemins (il n'est pas nécessaire qu'il y ait 1000, juste un de chaque) ?

Il est difficile de l'afficher dans un fichier CMakeLists.txt car CMake prend actuellement soin d'éviter de mélanger les chemins dans la plupart des cas. Cependant, il existe des problèmes dans le suivi des problèmes de CMake concernant des problèmes qui ne peuvent pas être résolus sans que Ninja ne les corrige en premier. Voir par exemple CMake Issue 13894 . Les utilisateurs veulent pouvoir donner des chemins absolus au compilateur même pour les sources (et peut-être inclure des répertoires) dans l'arborescence de construction, ou lors de constructions dans la source. Cela fonctionne bien avec le générateur Makefile de CMake. Si nous faisons cela avec Ninja, les fichiers dep reviennent avec des chemins absolus et ils ne correspondent pas aux chemins relatifs dans build.ninja . Peut-être que nous pourrions passer à des chemins absolus pour tout, mais comme discuté ci-dessus ici, nous ne devrions pas avoir à le faire.

Peut-être que vous pouvez essayer ceci pour des tests https://github.com/ClausKlein/build-performance/commit/8013836486e3a459474eb374f6c3da5e20983443

Le problème présenté ici est basé sur https://github.com/ninja-build/ninja/issues/1251#issue -210080507
Il génère autant de cible que vous le souhaitez. c'est-à-dire 2 subduers chacun avec 2 fichiers sources :

PWD=/Users/clausklein/Workspace/build-performance/build

rule cp
  command = cp $in $out

rule cc
  depfile = $out.d
  deps = gcc
  command = gcc -c -I$PWD $IN -o $out $FLAGS -MMD -MT $out -MF $out.d

rule link
  command = gcc -o $out $in $LINK_PATH $LINK_LIBRARIES

build foo: phony foo.h
build foo.h: cp foo.h.in

build bin/main0.o: cc /Users/clausklein/Workspace/build-performance/build/subdir0/main.c || foo.h
  IN = /Users/clausklein/Workspace/build-performance/build/subdir0/main.c
build /Users/clausklein/Workspace/build-performance/build/subdir0/file0.o: cc /Users/clausklein/Workspace/build-performance/build/subdir0/file0.c || foo.h
  IN = /Users/clausklein/Workspace/build-performance/build/subdir0/file0.c

build bin/main1.o: cc /Users/clausklein/Workspace/build-performance/build/subdir1/main.c || foo.h
  IN = /Users/clausklein/Workspace/build-performance/build/subdir1/main.c
build /Users/clausklein/Workspace/build-performance/build/subdir1/file0.o: cc /Users/clausklein/Workspace/build-performance/build/subdir1/file0.c || foo.h
  IN = /Users/clausklein/Workspace/build-performance/build/subdir1/file0.c

build bin/main0: link bin/main0.o /Users/clausklein/Workspace/build-performance/build/subdir0/file0.o 
build bin/main1: link bin/main1.o /Users/clausklein/Workspace/build-performance/build/subdir1/file0.o 

build all: phony foo bin/main0 bin/main1 
default all

Cela fonctionne bien avec le générateur Makefile de CMake.

Comment Make gère-t-il le problème du lien symbolique ?

Comment Make gère-t-il le problème du lien symbolique ?

Le générateur Makefile n'utilise pas actuellement depfiles et effectue sa propre analyse approximative. Cela sera probablement mis à jour dans le cadre de l'ajout de la prise en charge des modules C++20 au générateur Makefile, auquel cas l'interprétation des chemins depfile devra être réconciliée de la même manière que ce qui est proposé ici.

Une option consiste à ignorer ninja_workdir pour l'instant et au moins apprendre à Ninja à concilier les chemins mixtes en supposant que getcwd() est le sommet. De cette façon, au moins les chemins mixtes fonctionneront dans le cas courant sans lien symbolique. Ensuite, ninja_workdir peuvent être ajoutés pour prendre en charge les cas plus complexes ultérieurement.

S'il vous plaît, quelqu'un résout ce problème. Je suis tellement ennuyé à cause de ça.

J'utilise ARM-GCC avec CMake et VSCode. Lorsque j'utilise une construction dans la source, les chemins sont relatifs au répertoire "build" (au lieu du répertoire racine), ce qui empêche VSCode de résoudre les chemins, ce qui signifie que vous ne pouvez pas simplement cliquer sur le chemins dans la fenêtre de ligne de commande, à la place, vous devez localiser chaque fichier vous-même. Lorsque j'utilise une version CMake hors arbre, cela casse "IntelliSense" d'Eclipse et pose des problèmes avec les sous-projets CMake. Ma solution pour l'instant consiste à utiliser MakeFiles, car il utilise des chemins absolus par défaut. Mais Ninja est meilleur, il produit de meilleurs fichiers lisibles (rules.ninja...) et la sortie de construction sur la ligne de commande est meilleure. Make a des problèmes avec la sortie des avertissements sur la ligne de commande dans un contexte multithread, ce qui signifie que plusieurs avertissements sont entrelacés. Ce qui m'amène à construire un thread unique, ce qui est encore une fois super ennuyeux.

S'il vous plaît, quelqu'un résout ce problème. Je suis tellement ennuyé à cause de ça.

J'utilise ARM-GCC avec CMake et VSCode. Lorsque j'utilise un build in-source, les chemins sont relatifs au répertoire "build"...

Il existe une solution de contournement : choisissez le répertoire de construction en dehors de l'arborescence des sources ! c'est-à-dire _$TMPDIR/..._

Merci ClausKlein, mais la solution de contournement est une construction hors source, mais j'ai besoin des fichiers dans mon arbre, car il est référencé par d'autres scripts. Il s'agit également d'une exigence de construction non standard.

Ma solution pour l'instant est de changer CMake pour toujours utiliser des chemins absolus. Je ne comprends pas pourquoi il n'y a pas d'option pour cela. Cependant, si quelqu'un d'autre en a besoin, voici le patch de CMake v3.18.1 :

@@ -241,7 +241,7 @@ void cmNinjaTargetGenerator::AddIncludeFlags(std::string& languageFlags,
   // Add include directory flags.
   std::string includeFlags = this->LocalGenerator->GetIncludeFlags(
     includes, this->GeneratorTarget, language,
-    language == "RC", // full include paths for RC needed by cmcldeps
+    true, // full include paths for RC needed by cmcldeps
     false, config);
   if (this->GetGlobalGenerator()->IsGCCOnWindows()) {
     std::replace(includeFlags.begin(), includeFlags.end(), '\\', '/');
@@ -1133,8 +1133,7 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
   const std::string& fileConfig, bool firstForConfig)
 {
   std::string const language = source->GetLanguage();
-  std::string const sourceFileName =
-    language == "RC" ? source->GetFullPath() : this->GetSourceFilePath(source);
+  std::string const sourceFileName = source->GetFullPath();
   std::string const objectDir = this->ConvertToNinjaPath(
     cmStrCat(this->GeneratorTarget->GetSupportDirectory(),
              this->GetGlobalGenerator()->ConfigDirectory(config)));

Attention , il y avait un patch pour cmake, mais voir https://github.com/ninja-build/ninja/issues/1251

Nous avons besoin d'un patch pour Ninja !

Dans mon dernier commentaire, j'ai montré un correctif pour que CMake utilise des chemins absolus au lieu de chemins relatifs. Il s'avère que c'est une mauvaise idée, car cela rompt les dépendances d'en-tête CMake personnalisées avec Ninja (par exemple, un fichier d'en-tête généré dépend d'un fichier .json). Je suppose que ce problème découle de ce problème ici, que j'étais trop stupide pour comprendre.

Si quelqu'un est intéressé, j'utilise maintenant Ninja avec des chemins relatifs. J'ai créé une extension pour VSCode pour pouvoir cliquer sur des chemins relatifs à l'intérieur du terminal intégré. extension

@GrandChris Génial ! Une chance de le faire fonctionner également dans l'onglet Output ?

@weliveindetail N'hésitez pas à créer un nouveau problème sur https://github.com/GrandChris/TerminalRelativePath/issues et à décrire votre cas d'utilisation en détail. Mais l'onglet de sortie dans VSCode se comporte différemment du terminal intégré et je ne pense pas qu'il existe une API pour étendre le comportement à cet égard.

D'accord merci. Finalement, les chemins relatifs cliquables devraient probablement être résolus dans VSCode ou l'extension CMake. Will ping de leur côté.

Pour référence, cela est revenu dans CMake Issue 21865 . C'est un autre exemple de cas où il n'est pas facile (possible ?) de faire en sorte que les dépendances découvertes par depfile utilisent exactement la même représentation de chemin que build.ninja .

1917 ajoute la liaison ninja_workdir proposée ci-dessus en tant que fonctionnalité utile en soi. Une fois que cela est fusionné, je peux suivre avec un correctif pour ce problème.

@jhasse J'aimerais trouver une solution acceptable pour résoudre ce problème en amont. ninja_workdir résout le problème. J'ai plaidé mon cas ci-dessus. Quelle autre alternative proposez-vous ?

Comme vous l'avez souligné, le problème (le mélange de chemins absolus de depfile avec des chemins relatifs manifestes interrompt les reconstructions) est inhérent à la conception. Je pense que nous devrions créer des problèmes plus spécifiques, car nous avons abordé plusieurs problèmes dans la discussion (par exemple, créer un lien symbolique vers le répertoire de construction).

Pour les deux cas d'utilisation dans le commentaire initial, mes alternatives seraient :

Cela produit une meilleure sortie pour les IDE pour faire correspondre les messages d'erreur et se référer aux fichiers d'origine.

Corrigez l'IDE ou transmettez /FC ou -fabs-path-diagnostics au compilateur.

Cela peut également affecter les chemins enregistrés dans les informations de débogage.

Cela devrait également être corrigé par le compilateur. Je suggérerais de regarder -fdebug-prefix-map , mais je ne sais pas exactement quel est le problème.

Voici un script illustrant le problème : ninja-bug.bash.txt

Pas vraiment, cela démontre le comportement actuel de Ninja. Les deux problèmes

  1. "mon IDE ne peut pas faire correspondre la sortie du compilateur au bon fichier"
  2. "J'ai besoin de chemins absolus dans les informations de débogage"

besoin d'explications supplémentaires. Sinon, cela ressemble à un problème XY pour moi (X étant "mélangeant des chemins absolus et relatifs" et Y étant soit 1. soit 2.).

Je ne pense vraiment pas que la solution devrait être "contourner cela dans tous les autres outils".

1924 démontre un correctif de travail complet avec des tests, basé sur l'approche ninja_workdir . Un générateur utilisant cela peut résoudre tous les problèmes ci-dessus.

Moi non plus, car je ne les vois pas comme des solutions de contournement.

Ce ne sont PAS des options GNU gcc !

Suis 05.03.2021 à 16:58 schrieb Jan Niklas Hasse [email protected] :

Corrigez l'IDE ou passez /FC https://docs.microsoft.com/de-de/cpp/build/reference/fc-full-path-of-source-code-file-in-diagnostics ou -fabs- path-diagnostics https://reviews.llvm.org/D23816 au compilateur.

Cela peut également affecter les chemins enregistrés dans les informations de débogage.

Voici un script illustrant le problème : ninja-bug.bash.txt

Pas vraiment, cela démontre le comportement actuel de Ninja.

Mon message que vous avez cité reconnaît qu'il s'agit actuellement du comportement documenté.
L'objet de ce numéro est de remettre en cause le design en
démontrant une classe de cas d'utilisation qu'il ne sert pas.

Les deux questions ... (1) ... (2) ... nécessitent de plus amples explications.

Ce ne sont là que deux exemples de problèmes qui sont rendus plus faciles à résoudre en
passer des chemins absolus à l'outillage. Les chemins absolus ne sont pas déraisonnables
simplement parce que d'autres solutions sont disponibles dans des cas spécifiques de tels
problèmes (en utilisant des fonctionnalités spécifiques de l'outillage disponible auprès de certains fournisseurs).
Les chemins absolus aident à résoudre une grande classe de ces problèmes sans mises à jour
au reste de l'écosystème. Comme je l'ai posté précédemment :

Nous pouvons débattre indéfiniment des mérites des chemins relatifs et absolus. Ninja devrait
ne pas avoir d'opinion là-dessus. Le problème ici est de concilier les cas où
les deux sont utilisés dans une seule version. Le générateur de buildsystem ne peut pas toujours
contrôler ce que les outils feront avec les chemins.

Dans les systèmes de construction complexes du monde réel, il peut y avoir un nombre arbitraire de couches
de scripts, wrappers, outils, etc., (de toutes sortes de fournisseurs) entre le
les chemins écrits en build.ninja par le générateur de fichier de construction et les chemins réels
rencontré par Ninja dans un depfile. Parfois, un fichier donné peut être référencé par
un depfile d'un outil qui n'a pas reçu directement un chemin depuis build.ninja .
Pour que les depfiles fonctionnent sous la conception actuelle de Ninja, l'ensemble de l'outillage
pile doit savoir exactement comment le générateur build.ninja choisit d'exprimer
ces chemins sur les instructions de construction, et les fonctionnalités les conservent ou les convertissent
eux de la même manière. Ce n'est pas traitable en général.

Ninja peut résoudre ce problème avec un petit changement de conception : réconcilier un
chemin absolu dans un fichier dep avec un chemin relatif dans build.ninja (et vice-versa
versa). Je ne demande pas de réconcilier des chemins arbitraires vers le même fichier, seulement de
reconnaître que /path/to/some/file dans un fichier dep est le même que some/file dans
le fichier de construction /path/to/build.ninja .

Il existe un précédent pour de telles mises à jour de conception. Quand Ninja a commencé, l'espoir
était que les chemins seraient toujours rencontrés par ninja exactement de la même façon
représentation octet par octet que le générateur de fichier de construction a écrite dans
build.ninja . Exécutez git blame -M -C -w -- src/util.cc et regardez l'historique
de CanonicalizePath pour voir une série de cas qui ont été rencontrés où cela
la philosophie de conception devait être assouplie. Il s'agit d'une autre catégorie de tels cas.

Le truc c'est que je ne suis pas d'accord

Ninja ne devrait pas avoir d'opinion à ce sujet.

en premier lieu.

Ce n'est pas traitable en général.

Quel est donc le problème spécifique ? Désolé, je suis un peu confus.

Je ne suis pas d'accord avec "Ninja ne devrait pas avoir d'opinion à ce sujet" en premier lieu... Alors, quel est le problème spécifique ?

Il ne s'agit pas d'un problème spécifique, mais d'une classe entière de problèmes qui sont beaucoup plus faciles à résoudre avec des chemins absolus. Peu importe la raison pour laquelle les développeurs veulent transmettre des chemins absolus à leurs outils, seulement qu'ils veulent utiliser des chemins absolus pour les raisons qui s'appliquent à leur cas particulier. Les systèmes de construction existent pour servir leurs utilisateurs, pas pour dicter une politique. Ninja est censé être un langage d'assemblage pour les systèmes de construction, et n'a pourtant aucun moyen d'exprimer les systèmes de construction en utilisant des chemins de style mixte.

La politique de Ninja pour les modifications en amont est que les problèmes doivent être résolus par les générateurs de fichiers de construction, et non par Ninja en amont, s'ils peuvent être résolus sans perte d'efficacité . Dans ce cas, la seule façon de fournir une réconciliation de style ninja_workdir à usage général des chemins depfile à partir du générateur de fichiers de construction est d'injecter après chaque commande qui génère un depfile une commande supplémentaire pour réviser les chemins dans le depfile pour correspondre le fichier de construction avant que ninja ne le charge. Cette commande supplémentaire aura son propre coût d'exécution qui est bien supérieur à ce que fait #1924 (un petit nombre de recherches en mémoire supplémentaires dans le processus ninja ). Par conséquent, la réconciliation à usage général est plus efficace à fournir dans Ninja en amont, et est donc candidate à l'inclusion.

Même si vous utilisez des chemins absolus pour tout, plutôt que de mélanger des chemins absolus et relatifs, il y a un problème d'ergonomie ennuyeux. Si l'utilisateur demande à ninja de régénérer un fichier de sortie spécifique plutôt qu'une fausse cible, par exemple, ninja out/my_executable ou ninja out/foo/bar.o , il doit se rappeler de passer le chemin absolu, ou ninja échouera avec une erreur déroutante "cible inconnue". Le problème inverse existe également : l'utilisateur peut demander à ninja de reconstruire un chemin absolu alors que le fichier build.ninja utilise des chemins relatifs.

Dans un outil générateur Ninja que je maintiens, je contourne ce problème en faisant en sorte que chaque instruction build inclue à la fois le chemin relatif et son chemin absolu correspondant en tant que sorties. Cela fonctionne, mais cela ressemble vraiment à un hack pour contourner une limitation dans Ninja. (Edit: De plus, si le build.ninja n'utilise que des chemins relatifs et peut donc toujours fonctionner après avoir été déplacé vers un chemin absolu différent, l'ajout d'alias de chemin absolu annulerait cette capacité.)

Certes, ce n'est pas exactement le même problème que les depfiles, mais cela suggère que Ninja devrait être plus conscient des équivalences de chemin absolues et relatives en général.

@comex Merci, c'est une préoccupation valable. Pouvez-vous ouvrir un nouveau sujet pour cela ?

Peu importe pourquoi les développeurs veulent passer des chemins absolus vers leurs outils [...]

Je ne suis pas d'accord.

Dans ce cas, la seule façon de fournir une réconciliation de style ninja_workdir à usage général des chemins d'accès [...]

Pourquoi avez-vous besoin de la réconciliation de style ninja_workdir en premier lieu ?

Pourquoi avez-vous besoin de la réconciliation de style ninja_workdir en premier lieu ?

Il permet aux développeurs d'utiliser des chemins relatifs dans build.ninja tout en gérant les chemins absolus générés dans les fichiers dep par des outils qu'ils ne contrôlent pas. Sinon, ils peuvent être obligés d'utiliser des chemins absolus dans build.ninja afin de s'adapter à ces outils en combinaison avec la limitation de conception de ninja. Ma proposition n'empêche pas l'utilisation de chemins relatifs. Cela permet de les utiliser davantage.

J'ai ouvert #1925 pour implémenter le même rapprochement que #1924, mais sans la liaison ninja_workdir . Cela sépare la décision de réconcilier les chemins depfile de la décision de prendre en charge les chemins logiques workdir avec des liens symboliques.

[...] absolus générés dans les fichiers dep par des outils qu'ils ne contrôlent pas.

Existe-t-il un exemple d'un tel outillage ?

Nous ne pouvons pas prédire le comportement de tous les outils utilisés par tout le monde dans le monde. Même pour l'outillage que nous contrôlons, nous avons déjà discuté de plusieurs cas ci-dessus qui sont faciles à résoudre avec des chemins absolus, mais nécessitent des options spécifiques à l'outil et beaucoup de soin à résoudre avec des chemins relatifs. CMake préfère les chemins absolus dans plusieurs cas pour des raisons similaires. J'ai plusieurs rapports de bogues sur le générateur Ninja qui ne le fait pas alors que tous les autres générateurs le font. J'ai plusieurs fois passé des heures à rechercher un problème de dépendances pour découvrir qu'il s'agit d'une autre instance de chemins de depfile non réconciliés avec les chemins de manifeste de construction. Les outils fournissent les informations dont Ninja a besoin pour capturer les dépendances, mais Ninja les ignore.

Votre position apparaît comme une opinion selon laquelle les chemins relatifs sont universellement meilleurs. D'autres personnes ont une opinion différente selon laquelle les chemins absolus sont meilleurs dans certains cas. Je ne pense pas que ce soit la place d'un outil de build pour évangéliser les chemins relatifs.

Ma proposition ajoute une petite quantité d'infrastructure à Ninja. Qu'est-ce que ça fait mal? Ne pas l'avoir externalise un coût beaucoup plus important.

Oui c'est vrai!

Et avec les chemins absolus, cmake est capable d'éliminer les chemins d'inclusion du compilateur en double.
Cela réduit à nouveau le temps de construction.

Suis 09.03.2021 à 19:20 schrieb Brad King [email protected] :

Je ne pense pas que ce soit la place d'un outil de build pour évangéliser les chemins relatifs.

J'ai configuré le problème CMake concernant un problème auquel nous sommes confrontés avec les fichiers cpp générés par le compilateur rapide de Qt et la construction unity activée. Mes enquêtes locales ont montré que ninja est de loin le système de construction le plus rapide, mais dans cette constellation, il n'est pas fiable. Maintenant, je suis confronté au problème de savoir comment trouver une solution de contournement ou justifier l'augmentation du temps de construction.

CMake vient de rencontrer un problème de dépendances circulaires qui était, jusqu'à récemment, masqué par ce problème Ninja. Si ce problème avait été résolu, nous aurions découvert le problème CMake beaucoup plus tôt.

Cette page vous a été utile?
0 / 5 - 0 notes