Ninja: Das Mischen absoluter Pfade von depfile mit relativen Pfaden von Manifesten unterbricht den Neuaufbau

Erstellt am 24. Feb. 2017  Â·  70Kommentare  Â·  Quelle: ninja-build/ninja

Das Ninja-Handbuch warnt vor einer solchen Mischung, aber es ist zu einer ernsthaften EinschrÀnkung geworden.

Das Problem ist, dass die Leute wollen, dass ihre Build-Systeme den Compiler mit einem absoluten Pfad zur Quelldatei aufrufen. Dies fĂŒhrt zu einer besseren Ausgabe fĂŒr IDEs, um Fehlermeldungen abzugleichen und auf die Originaldateien zurĂŒckzugreifen. Es kann sich auch auf die in Debug-Informationen aufgezeichneten Pfade auswirken. Dies steht jedoch im Widerspruch zu Ninjas Vorliebe fĂŒr relative Pfade im Build-Manifest.

Hier ist ein Skript, das das Problem demonstriert: ninja-bug.bash.txt

Hilfreichster Kommentar

Ich glaube wirklich nicht, dass die Lösung darin bestehen sollte, dies in allen anderen Werkzeugen zu umgehen.

1924 demonstriert einen vollstÀndig funktionierenden Fix mit Tests, basierend auf dem ninja_workdir -Ansatz. Ein Generator, der dies verwendet, kann alle oben genannten Probleme lösen.

Alle 70 Kommentare

Cc: @nico @chaoren

DrĂŒben in CMake gibt es relevante Diskussionen in Ausgabe 16675 , Ausgabe 13894 und MR 520 .

Als Problemumgehung können Sie das Objektausgabeverzeichnis explizit festlegen, sogar "." oder "..", aber der absolute Pfad funktioniert auch.
ninjatst.bash.txt

@zlolik IIUC Sie schlagen vor, absolute Pfade in den Diagrammknoten des Build-Manifests ( build.ninja ) zu platzieren. Sicherlich funktioniert das (und das tut CMake in Out-of-Source-Builds), aber mein Punkt hier ist, dass Ninja von der Verwendung absoluter Pfade abrÀt und IDEs sie dennoch in der Ausgabe erfordern.

Es ist auch hypothetisch möglich, dass ein Compiler, dem -c foo.c gegeben wird, trotzdem einen absoluten Pfad in der Depfile erzeugen könnte. Wenn das passiert, erkennt Ninja die AbhÀngigkeit aufgrund des gleichen hier gemeldeten Problems nicht.

Um dies zu beheben, muss Ninja erkennen können, wenn ein relativer Pfad und ein absoluter Pfad dieselbe Datei sind und intern nur einen Diagrammknoten anstelle von zwei haben. Dies nur fĂŒr die Depfile-Verarbeitung zu tun, kann ausreichend sein, da es vernĂŒnftig ist, die build.ninja -Generatoren zu bitten, Pfade innerhalb des Build-Manifests konsistent zu benennen.

@bradking ZunÀchst einmal stimme ich Ihnen zu, dass wir ein Problem mit Ninja haben, und ich schlage nur eine Problemumgehung vor.
Ich denke, es gibt 3 zusammenhÀngende Probleme:

  1. Logik mit absolutem/relativem Eingabepfad, mehr Details in #1152 .
  2. Logik zum Erzwingen des absoluten/relativen Ausgangspfads. Das Problem mit Compilern - die einzige Möglichkeit, dem Compiler zu sagen, dass Sie einen absoluten Pfad in der Ausgabe haben möchten, ist die Verwendung des absoluten Pfads in der Befehlszeile. Kein Ninja-Problem, sondern unseres.
  3. Logik zum Analysieren des absoluten/relativen Pfads der Depfile. Dieses Problem.

Ich verwende 2 Problemumgehungen:

  1. Verwenden Sie die PrĂ€fixe $p und $o im Pfad des Generators build.ninja , um die ersten beiden Probleme zu lösen. In meinem Fall sind $p und $o nicht absolut, sondern relativ zum aktuellen Verzeichnis, in dem der Generator build.ninja ausgefĂŒhrt wurde.
  2. Verwenden Sie ein Skript, um depfile in einen Ninja-kompatiblen Pfad zu konvertieren. Einige Compiler benötigen sogar einen separaten Aufruf, um depfile zu generieren. Aber es gibt dabei kein absolutes Pfadproblem.

Als Referenz habe ich einen Thread auf der ninja-build -Mailingliste mit einem Lösungsvorschlag gestartet.

Ein weiteres verwandtes Problem mit Debug- und Abdeckungsinformationen: Die Verwendung von Befehlen mit relativen Pfaden erstellt auch Debug-Informationsdateien mit relativen Pfaden. Das Problem ist, dass die Debug-Dateien normalerweise neben den Objektdateien platziert werden, nicht den Quelldateien, sodass die relativen Pfade dort auf nicht vorhandene Dateien verweisen.

Gibt es hierzu Neuigkeiten? Es gab keine Antworten auf den Mailinglisten-Thread ...

Hallo an alle,

Es ist auch hypothetisch möglich, dass ein Compiler, dem -c foo.c gegeben wird, trotzdem einen absoluten Pfad in der Depfile erzeugen könnte.

Die AbhÀngigkeitsdateien von IAR v8 enthalten nur absolute Pfade.

Wir sind auf dieses Problem gestoßen, wenn wir Out-of-Source-Builds mit CMake/Ninja/IAR erstellt haben: Generierte Dateien, die im BinĂ€rverzeichnis von CMake landen, sind im Ninja-Manifest relativ, die deps-Ausgabe von IAR ist absolut.

FĂŒr mich ist dies eindeutig ein Ninja-Problem: Es sollte keine zwei Knoten fĂŒr dieselbe Datei haben, egal was passiert.

Ich habe den Vorschlag von @bradking gelesen, aber ich verstehe den Teil ĂŒber symbolische Links nicht wirklich und warum getcwd() nicht verwendet werden kann. WĂŒrden Sie etwas ausarbeiten?

Ich verstehe den Teil ĂŒber symbolische Links nicht wirklich und warum getcwd() nicht verwendet werden kann

@sebknzl das Problem ist, dass die vom Generator in build.ninja geschriebenen absoluten Pfade symbolische Links enthalten können, die aus dem einen oder anderen Grund absichtlich nicht aufgelöst werden. getcwd() gibt normalerweise einen Pfad mit aufgelösten symbolischen Links zurĂŒck. Wenn Ninja einen relativen Pfad im Build-Manifest oder ein Depfile relativ zu getcwd() interpretieren wĂŒrde, stimmt der absolute Pfad, den es erstellt, möglicherweise nicht mit dem ĂŒberein, was der Build-Manifest-Generator verwendet hat, und wir wĂŒrden immer noch zwei Knoten haben.

Die ninja_workdir , die ich in dem von Ihnen verlinkten Thread vorschlage, sagen Ninja im Grunde, was der Generator als Basis fĂŒr relative Pfade verwendet hat. In der Praxis sollte realpath(ninja_workdir) == realpath(getcwd()) immer wahr sein, aber das bedeutet nicht ninja_workdir == getcwd() . Eine andere Alternative wĂ€re fĂŒr Ninja, alles realpath zu machen, bevor Knoten erstellt werden, aber das wĂŒrde bedeuten, dass $in nicht auf das erweitert wĂŒrde, was der Generator beabsichtigt hat.

@jhasse Bitte sehen Sie sich dieses Problem und meinen Vorschlag an, es anzugehen.

Warum nicht eine _build.ninja_ mit absoluten Pfaden generieren, die von einer CMAKE_NINJA_GENERATOR_OPTION_ gesteuert werden?

dh so, was funktioniert:

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$ 

generiert mit ninjatst.bash.txt

@ClausKlein Wir haben versucht, CMake beizubringen, absolute Pfade zu verwenden. Siehe die Diskussionen, die ich in https://github.com/ninja-build/ninja/issues/1251#issuecomment -282322776 verlinkt habe. Ich möchte lieber keine Option hinzufĂŒgen, die besagt, dass "Dinge auf eine andere Weise tun, die einige FĂ€lle behebt und andere kaputt macht".

Wir brauchen wirklich die Ninja-Funktion in dem Vorschlag, den ich unter https://github.com/ninja-build/ninja/issues/1251#issuecomment -487618865 verlinkt habe, um dies richtig zu beheben.

Okay, gut

Dann wĂ€re dieser Fix auch fĂŒr das Mesonbuild-System verfĂŒgbar ;-)

Am 12.03.2020 um 12:56 schrieb Brad King [email protected] :

@ClausKlein https://github.com/ClausKlein Wir haben versucht, CMake beizubringen, absolute Pfade zu verwenden. Siehe die Diskussionen, die ich in #1251 (Kommentar) https://github.com/ninja-build/ninja/issues/1251#issuecomment-282322776 verlinkt habe. Ich möchte lieber keine Option hinzufĂŒgen, die besagt, dass "Dinge auf eine andere Weise tun, die einige FĂ€lle behebt und andere kaputt macht".

Wir brauchen wirklich die Ninja-Funktion in dem Vorschlag, den ich in #1251 (Kommentar) https://github.com/ninja-build/ninja/issues/1251#issuecomment-487618865 verlinkt habe, um dies richtig zu beheben.

—
Sie erhalten dies, weil Sie erwÀhnt wurden.
Antworten Sie direkt auf diese E-Mail, zeigen Sie sie auf GitHub https://github.com/ninja-build/ninja/issues/1251#issuecomment-598146822 an oder kĂŒndigen Sie https://github.com/notifications/unsubscribe-auth/AAN7QWWEDHMDA45DQVPLOUDRHDEVDANCNFSM4DBNL6GA .

Nehmen wir an, Ninja wĂŒrde ninja_workdir verwenden, um Depfile-Informationen abzugleichen, und wir haben die Situation, in der ninja_workdir != getcwd() wegen eines Symlinks. Was ist, wenn der Compiler jetzt absolute Pfade mit getcwd() ?

Der Compiler sollte getcwd() fĂŒr nichts verwenden, es sei denn, diese Dinge wurden als relative Pfade ĂŒbergeben, in diesem Fall muss wahrscheinlich der Buildsystem-Generator die Verantwortung ĂŒbernehmen.

Oder wir können versuchen, sowohl ninja_workdir als auch getcwd() zu normalisieren.

Nun, der Compiler sollte auch keinen absoluten Pfad in der Depfile zurĂŒckgeben, wenn relative Pfade angegeben werden ;)

@ClausKlein Wir haben versucht, CMake beizubringen, absolute Pfade zu verwenden. Siehe die Diskussionen, die ich in # 1251 (Kommentar) verlinkt habe. Ich möchte lieber keine Option hinzufĂŒgen, die besagt, dass "Dinge auf eine andere Weise tun, die einige FĂ€lle behebt und andere kaputt macht".

Was genau ist kaputt gegangen, als Sie absolute Pfade verwendet haben, wie von @ClausKlein vorgeschlagen?

Wenn dem Compiler absolute Pfade gegeben werden, hat das von ihm generierte Depfile absolute Pfade, und diese werden nicht mit relativen Pfaden zu Headern im Build-Manifest abgeglichen, z. B. fĂŒr generierte Header. Siehe den ninja-bug.bash.txt -Link in meinem ersten Beitrag oben in dieser Ausgabe. Es zeigt ein Schritt-fĂŒr-Schritt-Beispiel dessen, was passiert, und wird nur in Bezug auf Ninja und kein CMake ausgedrĂŒckt.

Ich habe das gelesen, aber warum nicht https://github.com/ninja-build/ninja/issues/1251#issuecomment -284533599 verwenden? Einfach weil Ninja von absoluten Pfaden „abrĂ€t“? Wenn ja, handelt es sich um eine DokumentationsĂ€nderung?

build.ninja -Dateien sind viel kleiner, ohne dass sich ĂŒberall absolute Pfade wiederholen, und das macht sie schneller. Sie sehen auch schöner aus, sind einfacher zu debuggen und eignen sich besser fĂŒr die Tab-VervollstĂ€ndigung von Build-Zielnamen in Shells. Meiner Meinung nach ist es eine gute Empfehlung fĂŒr Ninja. Ninja braucht nur ein bisschen mehr Informationen, um diesen Fall in Einklang zu bringen, und das ist, was ich vorschlage.

@bradking relative Pfade sind möglicherweise nicht immer kurz:

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

mein Beispiel https://github.com/ninja-build/ninja/issues/1251#issuecomment -597877775 sieht schöner aus!

Die Generatoren von CMake haben eine Regel, keine ../ -Sequenzen zu verwenden, die den Build-Baum verlassen. In vollstÀndig out-of-source Builds verwenden wir absolute Pfade zum Quellbaum und relative Pfade innerhalb des Build-Baums. Letztere beginnen nie in ../ , da sie sich unter dem Build-Baum befinden.

Ich weiß, es wurde mit _mesonbuild_ generiert. ;-)

Aber warum nicht die Generierung in den Quellbaum verweigern?

Wir können ewig ĂŒber die VorzĂŒge von relativen vs. absoluten Pfaden diskutieren. Ninja sollte darĂŒber nicht voreingenommen sein. Das Problem hier ist die Abstimmung von FĂ€llen, in denen beide innerhalb eines einzigen Builds verwendet werden. Der Buildsystem-Generator kann nicht immer kontrollieren, was die Tools mit Pfaden machen. Ninja sollte gemischte absolute/relative Pfade zu derselben Datei unterstĂŒtzen und kann dies mit einem einfachen Ansatz tun, den ich in meinem Vorschlag skizziert habe. FĂŒr den motivierenden Anwendungsfall werden die Änderungen auf das Depfile-Parsing isoliert.

Ninja sollte gemischte absolute/relative Pfade zu derselben Datei unterstĂŒtzen

Ich stimme zu!

Danke fĂŒr die ganzen ErklĂ€rungen, ich fange an zu verstehen.

Was wĂ€re, wenn Ninja (wenn er auf einen absoluten Pfad in der Depfile stĂ¶ĂŸt) realpath sowohl cwd als auch den gefundenen Pfad eingeben wĂŒrde? Dann wĂŒrde es das realpathed cwd aus dem realpathed depfile-path entfernen, um den relativen Pfad zu erhalten, der mit dem generierten Header ĂŒbereinstimmt. Funktioniert das?

getcwd() ist immer bereits ein realpath, so dass dieser Schritt nicht notwendig ist. Wenn Ninja realpath() den von depfile bereitgestellten absoluten Pfad verwenden und nach einem cwd-PrĂ€fix suchen wĂŒrde, das funktionieren könnte. Allerdings ist realpath() ein möglicherweise teurer Syscall, wĂ€hrend mein vorgeschlagenes ninja_workdir Pfade rein im Speicher ĂŒber String-Verarbeitung abgleichen kann.

Das Mischen in die andere Richtung sollte auch erlaubt sein: ein absoluter Pfad im Build-Manifest, aber ein relativer Pfad im Depfile. Ich denke nicht, dass Ninja jeden absoluten Pfad realpath() beim Analysieren build.ninja haben sollte. Das wÀre wahrscheinlich langsam.

Wir könnten das Ergebnis verwenden, um das Arbeitsverzeichnis zu bestimmen. Z.B:

getcwd(): /var/xyz/build
depfile-Eintrag: /home/foo/build/bar.h
realpath(depfile-Eintrag): /var/xyz/build/bar.h
relativer realpath: bar.h
entferne das aus dem Depfile-Eintrag: /home/foo/build -> ninja_workdir

Auf diese Weise mĂŒssen wir realpath nur einmal aufrufen.

Ich glaube nicht, dass die automatische Ableitung ninja_workdir im Allgemeinen möglich ist. Woher wissen wir, wie viele logische Komponenten des ursprĂŒnglichen Symlink-enthaltenden logischen Pfads dem Arbeitsverzeichnis entsprechen? Wir können es vielleicht tun, indem wir eine Komponente nach der anderen nehmen, bis ihr realpath mit cwd ĂŒbereinstimmt, aber das fĂŒhlt sich hacky und fehleranfĂ€llig an. Es fĂŒhlt sich riskant an, dem ersten Symlink zu vertrauen, der zufĂ€llig so aussieht. Außerdem mĂŒssten wir realpath() auf jedem absoluten Pfad ausfĂŒhren, auf den wir stoßen, bis einer auf diese Weise aufgelöst wird.

Der Buildsystem-Generator weiß genau, welchen logischen Pfad zum Arbeitsverzeichnis er beim Generieren absoluter Pfade in Build-Anweisungen und Befehlszeilen in build.ninja verwendet hat. Es ist daher die zuverlĂ€ssigste Informationsquelle fĂŒr den Workdir-Pfad. Wir brauchen nur eine Möglichkeit, Ninja diese Informationen mitzuteilen, daher meine vorgeschlagene ninja_workdir Bindung.

Ich bin mir nicht sicher, ob ich das verstehe, sorry. Können Sie ein Beispiel geben, wo meine Erkennungslogik nicht funktionieren wĂŒrde?

Es könnte brechen, wenn der Buildsystem-Generator einen Symlink in den Build-Baum einfĂŒgt (der auf eine andere Stelle im Build-Baum oder ganz nach außen zeigt):

getcwd(): /var/xyz/build
depfile-Eintrag: /home/foo/build/subdir-link/bar.h
realpath(depfile-Eintrag): /var/xyz/build/subdir-real/bar.h
relativer realpath: subdir-real/bar.h
Entfernen Sie das aus dem depfile-Eintrag: ???

CMake tut dies nicht, aber im Allgemeinen könnte ein Buildsystem-Generator dies tun.

Auch wenn wir bereit sind zu sagen, dass dies nicht unterstĂŒtzt wird, könnte die Erkennung dennoch auftreten:

getcwd(): /var/xyz/build
1000 Depfile-EintrÀge: /home/foo/ext-lib/bar{1,2,...}.h
1000 realpath (depfile-EintrÀge): /var/xyz/ext-lib/bar{1,2,...}.h
1000 relative realpaths: keine unter cwd

Stellen Sie sich nun vor, das erscheint in den Depfiles von 1000 Quellen und es gibt nie einen Treffer. Das sind 1 Million realpath()-Aufrufe ohne Übereinstimmung fĂŒr diese Heuristik. Und das wiederholt sich jedes Mal, wenn eine Quelle neu erstellt und ihr Depfile erneut analysiert wird.

Symlink innerhalb des Build-Baums -> ja, das können wir nicht wirklich unterstĂŒtzen, es wird sowieso zu allen möglichen anderen Problemen fĂŒhren (ohne ĂŒberall Realpath-ing).

Das zweite Beispiel klingt ziemlich kĂŒnstlich. Normalerweise beginnen Depfiles mit den lokalen AbhĂ€ngigkeiten, nicht mit Systemheadern.

Wenn sich herausstellt, dass es sich wirklich um ein Leistungsproblem handelt, könnten wir das Arbeitsverzeichnis in .ninja_deps ?

In einem Out-of-Source-Build zeigen nur sehr wenige Depfile-EintrÀge auf den Build-Baum. Dies wird sehr hÀufig sein:

getcwd(): /var/xyz/build
1000 Depfile-EintrÀge: /home/foo/project-source/bar{1,2,...}.h
1000 realpath(depfile-EintrÀge): /var/xyz/project-source/bar{1,2,...}.h
1000 relative realpaths: keine unter cwd

Ninja muss fĂŒr alle FĂ€lle realpath() aufrufen oder eine Art Ergebnistabelle fĂŒhren, um die eigentlichen Systemaufrufe zu vermeiden. Es kann nicht im Voraus wissen, wann es auf einen Symlink-Pfad stoßen wird, der in cwd aufgelöst wird, und weiß nicht einmal, ob es einen finden wird.

Angesichts der Tatsache, dass das Mischen von absoluten und relativen Pfaden in der Depfile derzeit nicht funktioniert, sehe ich nicht, wie das "sehr hÀufig" wÀre?

Depfiles der Form in meinem Beispiel sind bereits sehr verbreitet, auch wenn keine Symlinks oder gemischte Pfade verwendet werden. Ich habe sie in den meisten meiner BaubĂ€ume. Ninja kann nicht im Voraus wissen, ob die Heuristik benötigt wird, also muss sie fĂŒr alle FĂ€lle realpath() Systemaufrufe blockieren.

Vielleicht habe ich dein Beispiel falsch verstanden. Meinst du eine Depfile mit 3000 EintrĂ€gen oder waren das 3 separate Beispiele fĂŒr Depfiles mit jeweils 1000 EintrĂ€gen?

Ich meinte 1000 Depfile-EintrĂ€ge, die auf eine beliebige Anzahl von Depfiles verteilt sind. Es könnte einer sein. Es könnten viele sein. Ein Projekt kann 10000 EintrĂ€ge enthalten. Ihre Pfade können ĂŒberall im Dateisystem zeigen und können tatsĂ€chlich in den Build-Baum zeigen oder auch nicht.

Können Sie ein Beispiel geben CMakeLists.txt , das zu einer solchen Mischung von Pfaden fĂŒhrt (muss nicht 1000 sein, nur einer von jedem)?

Es ist schwierig, dies in einer CMakeLists.txt -Datei anzuzeigen, da CMake derzeit darauf achtet, dass Pfade in den meisten FĂ€llen nicht gemischt werden. Es gibt jedoch Probleme im Issue Tracker von CMake zu Problemen, die nicht behoben werden können, ohne dass Ninja dies zuerst behebt. Siehe zum Beispiel CMake Issue 13894 . Benutzer möchten in der Lage sein, dem Compiler absolute Pfade selbst fĂŒr Quellen (und vielleicht Include-Verzeichnisse) im Build-Baum oder bei In-Source-Builds zu geben. Dies funktioniert gut mit dem Makefile-Generator von CMake. Wenn wir das mit Ninja machen, kommen die Depfiles mit absoluten Pfaden zurĂŒck und sie stimmen nicht mit den relativen Pfaden in build.ninja ĂŒberein. Vielleicht könnten wir fĂŒr alles zu absoluten Pfaden wechseln, aber wie oben hier besprochen, sollten wir das nicht tun mĂŒssen.

Vielleicht können Sie dies fĂŒr Tests versuchen https://github.com/ClausKlein/build-performance/commit/8013836486e3a459474eb374f6c3da5e20983443

Das hier gezeigte Problem basiert auf https://github.com/ninja-build/ninja/issues/1251#issue -210080507
Es generiert so viel Ziel, wie Sie möchten. dh 2 Subduer mit jeweils 2 Quelldateien:

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

Dies funktioniert gut mit dem Makefile-Generator von CMake.

Wie geht Make mit dem Symlink-Problem um?

Wie geht Make mit dem Symlink-Problem um?

Der Makefile-Generator verwendet derzeit keine Depfiles und fĂŒhrt seine eigenen ungefĂ€hren Scans durch. Dies wird wahrscheinlich aktualisiert, wenn dem Makefile-Generator UnterstĂŒtzung fĂŒr C++20-Module hinzugefĂŒgt wird. An diesem Punkt muss die Interpretation von depfile-Pfaden Ă€hnlich wie hier vorgeschlagen abgeglichen werden.

Eine Möglichkeit besteht darin, ninja_workdir vorerst zu ĂŒberspringen und Ninja zumindest beizubringen, die gemischten Pfade in Einklang zu bringen, vorausgesetzt, dass getcwd() die Spitze ist. Auf diese Weise funktionieren zumindest die gemischten Pfade im ĂŒblichen Fall ohne Symlink. Dann kann ninja_workdir hinzugefĂŒgt werden, um spĂ€ter die komplexeren FĂ€lle zu unterstĂŒtzen.

Bitte behebt das jemand. Ich bin so genervt deswegen.

Ich verwende ARM-GCC mit CMake und VSCode. Wenn ich einen In-Source-Build verwende, sind die Pfade relativ zum „Build“-Verzeichnis (anstelle des Stammverzeichnisses), was dazu fĂŒhrt, dass VSCode die Pfade nicht mehr auflösen kann, was bedeutet, dass Sie nicht einfach auf klicken können Pfade im Befehlszeilenfenster, stattdessen mĂŒssen Sie jede Datei selbst suchen. Wenn ich einen CMake-Out-of-Tree-Build verwende, wird „IntelliSense“ von Eclipse unterbrochen und es treten Probleme mit CMake-Unterprojekten auf. Meine Lösung fĂŒr den Moment ist die Verwendung von MakeFiles, da es standardmĂ€ĂŸig absolute Pfade verwendet. Aber Ninja ist besser, es produziert besser lesbare Dateien (rules.ninja...) und die Build-Ausgabe auf der Kommandozeile ist besser. Make hat Probleme mit der Ausgabe von Warnungen auf der Kommandozeile in einem Multithread-Kontext, d.h. mehrere Warnungen werden verschachtelt. Was dazu fĂŒhrt, dass ich Single-Threaded baue, was wiederum super nervig ist.

Bitte behebt das jemand. Ich bin so genervt deswegen.

Ich verwende ARM-GCC mit CMake und VSCode. Wenn ich einen In-Source-Build verwende, sind die Pfade relativ zum "Build"-Verzeichnis ...

Es gibt eine Problemumgehung: WĂ€hlen Sie das Build-Verzeichnis außerhalb des Quellbaums! dh _$TMPDIR/..._

Danke, ClausKlein, aber die Problemumgehung ist ein Out-of-Source-Build, aber ich brauche die Dateien in meinem Baum, weil andere Skripte darauf verweisen. Es ist auch eine nicht standardmĂ€ĂŸige Build-Anforderung.

Meine Lösung fĂŒr den Moment ist, CMake so zu Ă€ndern, dass immer nur absolute Pfade verwendet werden. Ich verstehe nicht, warum es dafĂŒr keine Option gibt. Falls jedoch jemand anderes dies benötigt, hier ist der Patch von 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)));

Achtung , es gab einen Patch fĂŒr cmake, aber siehe https://github.com/ninja-build/ninja/issues/1251

Wir brauchen einen Patch fĂŒr Ninja!

In meinem letzten Kommentar habe ich einen Patch fĂŒr CMake gezeigt, um absolute Pfade anstelle von relativen Pfaden zu verwenden. Es stellt sich heraus, dass dies eine schlechte Idee ist, da benutzerdefinierte CMake-Header-AbhĂ€ngigkeiten mit Ninja unterbrochen werden (z. B. ist eine generierte Header-Datei von einer .json-Datei abhĂ€ngig). Ich schĂ€tze, dieses Problem stammt von diesem Problem hier, das ich zu dumm war, um es zu verstehen.

Falls es jemanden interessiert, ich verwende jetzt Ninja mit relativen Pfaden. Ich habe eine Erweiterung fĂŒr VSCode erstellt, um relative Pfade innerhalb des integrierten Terminals anklicken zu können. VerlĂ€ngerung

@GrandChris Großartig! Gibt es eine Chance, es auch auf der Registerkarte Output zum Laufen zu bringen?

@weliveindetail FĂŒhlen Sie sich frei, ein neues Problem auf https://github.com/GrandChris/TerminalRelativePath/issues zu erstellen und Ihren Anwendungsfall im Detail zu beschreiben. Aber die Registerkarte Ausgabe in VSCode verhĂ€lt sich anders als das integrierte Terminal, und ich glaube nicht, dass es eine API gibt, um das Verhalten in dieser Hinsicht zu erweitern.

OK danke. Schließlich sollten anklickbare relative Pfade wahrscheinlich in VSCode oder der CMake-Erweiterung gelöst werden. Wird auf ihrer Seite pingen.

Als Referenz tauchte dies in CMake Issue 21865 erneut auf. Dies ist ein weiteres Beispiel fĂŒr einen Fall, in dem es nicht einfach (möglich?) ist, von Depfile erkannte AbhĂ€ngigkeiten dazu zu bringen, genau dieselbe Pfaddarstellung wie build.ninja zu verwenden.

1917 fĂŒgt die oben vorgeschlagene ninja_workdir -Bindung als eigenstĂ€ndig nĂŒtzliches Feature hinzu. Sobald das zusammengefĂŒhrt ist, kann ich dieses Problem beheben.

@jhasse Ich wĂŒrde gerne eine akzeptable Lösung finden, um dies im Upstream zu beheben. ninja_workdir löst das Problem. Ich habe meinen Fall oben argumentiert. Welche andere Alternative schlagen Sie vor?

Wie Sie darauf hingewiesen haben, ist das Problem (das Mischen von absoluten Pfaden aus depfile mit relativen Pfaden von Manifesten unterbricht die Neuerstellung) beabsichtigt. Ich denke, wir sollten spezifischere Themen erstellen, da wir in der Diskussion mehrere Themen berĂŒhrt haben (z. B. Symlinking des Build-Verzeichnisses).

FĂŒr die beiden AnwendungsfĂ€lle im ersten Kommentar wĂ€ren meine Alternativen:

Dies fĂŒhrt zu einer besseren Ausgabe fĂŒr IDEs, um Fehlermeldungen abzugleichen und auf die Originaldateien zurĂŒckzugreifen.

Reparieren Sie entweder die IDE oder ĂŒbergeben Sie /FC oder -fabs-path-diagnostics an den Compiler.

Es kann sich auch auf die in Debug-Informationen aufgezeichneten Pfade auswirken.

Dies sollte auch vom Compiler behoben werden. Ich wĂŒrde vorschlagen, sich -fdebug-prefix-map , aber ich bin mir nicht sicher, wo genau das Problem liegt.

Hier ist ein Skript, das das Problem demonstriert: ninja-bug.bash.txt

Nicht wirklich, es zeigt Ninjas aktuelles Verhalten. Die zwei Themen

  1. "Meine IDE kann die Ausgabe des Compilers nicht der richtigen Datei zuordnen"
  2. "Ich brauche absolute Pfade in den Debug-Informationen"

bedĂŒrfen weiterer ErklĂ€rung. Ansonsten sieht das fĂŒr mich wie ein XY-Problem aus (X ist "Mischen absoluter und relativer Pfade" und Y ist entweder 1. oder 2.).

Ich glaube wirklich nicht, dass die Lösung darin bestehen sollte, dies in allen anderen Werkzeugen zu umgehen.

1924 demonstriert einen vollstÀndig funktionierenden Fix mit Tests, basierend auf dem ninja_workdir -Ansatz. Ein Generator, der dies verwendet, kann alle oben genannten Probleme lösen.

Ich auch nicht, weil ich das nicht als Workarounds sehe.

Dies sind KEINE GNU-gcc-Optionen!

Am 05.03.2021 um 16:58 schrieb Jan Niklas Hasse [email protected] :

Reparieren Sie entweder die IDE oder ĂŒbergeben Sie /FC https://docs.microsoft.com/de-de/cpp/build/reference/fc-full-path-of-source-code-file-in-diagnostics oder -fabs- path-diagnostics https://reviews.llvm.org/D23816 zum Compiler.

Es kann sich auch auf die in Debug-Informationen aufgezeichneten Pfade auswirken.

Hier ist ein Skript, das das Problem demonstriert: ninja-bug.bash.txt

Nicht wirklich, es zeigt Ninjas aktuelles Verhalten.

Mein von Ihnen zitierter Beitrag bestÀtigt, dass dies derzeit das dokumentierte Verhalten ist.
Der Zweck dieser Ausgabe ist es, das Design von in Frage zu stellen
Demonstration einer Klasse von AnwendungsfÀllen, die es nicht bedient.

Die beiden Probleme ... (1) ... (2) ... bedĂŒrfen weiterer ErlĂ€uterung.

Das sind nur zwei Beispiele fĂŒr Probleme, die dadurch einfacher zu lösen sind
Übergeben absoluter Pfade an Werkzeuge. Absolute Pfade sind nicht unvernĂŒnftig
nur weil andere Lösungen in bestimmten FĂ€llen verfĂŒgbar sind
Probleme (unter Verwendung bestimmter Funktionen von Werkzeugen, die von einigen Anbietern erhÀltlich sind).
Absolute Pfade helfen, eine große Klasse dieser Probleme ohne Updates zu lösen
zum Rest des Ökosystems. Wie ich bereits gepostet habe:

Wir können ewig ĂŒber die VorzĂŒge von relativen vs. absoluten Pfaden diskutieren. Ninja sollte
darĂŒber keine Meinung haben. Das Problem hier ist die Vereinbarkeit von FĂ€llen, in denen
beide werden innerhalb eines einzigen Builds verwendet. Der Buildsystem-Generator kann das nicht immer
steuern, was die Tools mit Pfaden machen.

In komplexen realen Build-Systemen kann es eine beliebige Anzahl von Schichten geben
von Skripten, Wrappern, Tools usw. (von allen möglichen Anbietern) zwischen den
Pfade, die vom Build-Datei-Generator in build.ninja geschrieben wurden, und die tatsÀchlichen Pfade
von Ninja in einem Depfile getroffen. Manchmal kann auf eine bestimmte Datei verwiesen werden
ein Depfile von einem Tool, dem nicht direkt ein Pfad von build.ninja gegeben wurde.
Damit Depfiles unter Ninjas aktuellem Design funktionieren, muss das gesamte Tooling
Stack muss genau mitgeteilt werden, wie der build.ninja -Generator ausdrĂŒckt
diese Pfade in Build-Anweisungen und verfĂŒgen ĂŒber Funktionen, die sie beibehalten oder konvertieren
sie auf die gleiche Weise. Das ist im Allgemeinen nicht zu handhaben.

Ninja kann dieses Problem mit einer kleinen DesignÀnderung lösen: dem Abstimmen von an
absoluter Pfad in einem Depfile mit einem relativen Pfad in build.ninja (und vice
umgekehrt). Ich bitte nicht darum, beliebige Pfade mit derselben Datei abzugleichen, sondern nur mit
Erkennen Sie, dass /path/to/some/file in einem Depfile dasselbe ist wie some/file in
die Build-Datei /path/to/build.ninja .

Es gibt PrĂ€zedenzfĂ€lle fĂŒr solche Designaktualisierungen. Als Ninja anfing, die Hoffnung
war, dass Pfade von ninja immer genau gleich angetroffen wĂŒrden
Byte-fĂŒr-Byte-Darstellung, die der Build-Datei-Generator hineingeschrieben hat
build.ninja . FĂŒhren Sie git blame -M -C -w -- src/util.cc aus und sehen Sie sich den Verlauf an
von CanonicalizePath , um eine Reihe von FĂ€llen zu sehen, die dort aufgetreten sind
Designphilosophie musste entspannt werden. Dies ist eine andere Klasse solcher FĂ€lle.

Die Sache ist, dass ich nicht einverstanden bin

Ninja sollte darĂŒber nicht voreingenommen sein.

an erster Stelle.

Das ist im Allgemeinen nicht zu handhaben.

Was ist also das spezifische Problem? Entschuldigung, ich bin etwas verwirrt.

Ich bin ĂŒberhaupt nicht einverstanden mit "Ninja sollte darĂŒber keine Meinung haben" ... Also, was ist das spezifische Problem?

Hier geht es nicht um ein bestimmtes Problem, sondern um eine ganze Klasse von Problemen, die mit absoluten Pfaden viel einfacher zu lösen sind. Es sollte keine Rolle spielen, warum Entwickler absolute Pfade an ihre Tools ĂŒbergeben wollen, nur dass sie absolute Pfade aus welchen GrĂŒnden auch immer fĂŒr ihren speziellen Fall verwenden möchten. Build-Systeme existieren, um ihren Benutzern zu dienen, nicht um Richtlinien zu diktieren. Ninja soll eine Assemblersprache fĂŒr Build-Systeme sein, hat aber keine Möglichkeit, Build-Systeme mit gemischten Pfaden auszudrĂŒcken.

Ninjas Richtlinie fĂŒr Upstream-Änderungen lautet, dass Probleme von Build-Dateigeneratoren und nicht von Ninja Upstream gelöst werden sollten, wenn sie ohne Effizienzverlust gelöst werden können. In diesem Fall besteht die einzige Möglichkeit, eine allgemeine ninja_workdir -Ă€hnliche Abstimmung von Depfile-Pfaden aus dem Build-Datei-Generator bereitzustellen, darin, nach jedem Befehl, der ein Depfile generiert, einen zusĂ€tzlichen Befehl einzufĂŒgen, um Pfade in dem Depfile entsprechend zu ĂŒberarbeiten die Build-Datei, bevor Ninja sie lĂ€dt. Dieser zusĂ€tzliche Befehl hat seine eigenen Laufzeitkosten, die weit ĂŒber dem liegen, was #1924 tut (eine kleine Anzahl zusĂ€tzlicher In-Memory-Lookups innerhalb des ninja -Prozesses). Daher ist die Allzweck-Abstimmung effizienter in Ninja Upstream bereitzustellen, und ist somit ein Kandidat fĂŒr die Aufnahme.

Selbst wenn Sie fĂŒr alles absolute Pfade verwenden, anstatt absolute und relative Pfade zu mischen, gibt es ein Ă€rgerliches ergonomisches Problem. Wenn der Benutzer ninja auffordert, eine bestimmte Ausgabedatei anstelle eines falschen Ziels neu zu generieren, z. B. ninja out/my_executable oder ninja out/foo/bar.o , muss er daran denken, den absoluten Pfad oder Ninja zu ĂŒbergeben wird mit einem verwirrenden Fehler "unbekanntes Ziel" fehlschlagen. Es gibt auch das gegenteilige Problem: Der Benutzer kann Ninja auffordern, einen absoluten Pfad neu zu erstellen, wenn die Datei build.ninja relative Pfade verwendet.

In einem Ninja-Generator-Tool, das ich betreue, umgehe ich dies, indem ich jede einzelne build -Anweisung sowohl den relativen Pfad als auch den entsprechenden absoluten Pfad als Ausgabe einbeziehen lasse. Es funktioniert, aber es fĂŒhlt sich wirklich wie ein Hack an, eine EinschrĂ€nkung in Ninja zu umgehen. (Bearbeiten: Wenn die build.ninja nur relative Pfade verwendet und daher nach dem Verschieben auf einen anderen absoluten Pfad immer noch funktionieren kann, wĂŒrde das HinzufĂŒgen von absoluten Pfadaliasnamen diese FĂ€higkeit beeintrĂ€chtigen.)

Zugegebenermaßen ist dies nicht genau das gleiche Problem wie depfiles, aber es legt nahe, dass Ninja sich der absoluten vs. relativen PfadĂ€quivalenzen im Allgemeinen bewusster sein sollte.

@comex Danke, das ist ein berechtigtes Anliegen. Kannst du dafĂŒr ein neues Thema aufmachen?

Es sollte keine Rolle spielen, warum Entwickler absolute Pfade zu ihren Tools [...]

Ich bin nicht einverstanden.

In diesem Fall ist die einzige Möglichkeit, eine allgemeine ninja_workdir -artige Abstimmung von Depfile-Pfads [...]

Warum brauchen Sie ĂŒberhaupt die Versöhnung im ninja_workdir -Stil?

Warum brauchen Sie ĂŒberhaupt die Versöhnung im Stil von ninja_workdir?

Es ermöglicht Entwicklern, relative Pfade in build.ninja zu verwenden, wÀhrend sie weiterhin mit absoluten Pfaden umgehen, die in Depfiles von Tools erzeugt werden, die sie nicht kontrollieren. Andernfalls sind sie möglicherweise gezwungen, absolute Pfade in build.ninja zu verwenden, um solche Werkzeuge in Kombination mit Ninjas konstruktionsbedingten BeschrÀnkungen unterzubringen. Mein Vorschlag verhindert nicht die Verwendung relativer Pfade. Es ermöglicht eine stÀrkere Nutzung.

Ich habe #1925 geöffnet, um dieselbe Abstimmung wie #1924 zu implementieren, aber ohne die ninja_workdir -Bindung. Das trennt die Entscheidung, Depfile-Pfade in Einklang zu bringen, von der Entscheidung, logische Workdir-Pfade mit symbolischen Links zu unterstĂŒtzen.

[...] absoluten Pfade, die in Depfiles durch Werkzeuge erzeugt werden, die sie nicht kontrollieren.

Gibt es ein Beispiel fĂŒr solche Werkzeuge?

Wir können unmöglich das Verhalten aller Werkzeuge vorhersagen, die von jedem auf der Welt verwendet werden. Sogar fĂŒr Werkzeuge, die wir kontrollieren, haben wir oben bereits mehrere FĂ€lle besprochen, die mit absoluten Pfaden leicht zu lösen sind, aber werkzeugspezifische Optionen und viel Sorgfalt erfordern, um sie mit relativen Pfaden zu lösen. CMake bevorzugt aus Ă€hnlichen GrĂŒnden in mehreren FĂ€llen absolute Pfade. Ich habe mehrere Fehlerberichte darĂŒber, dass der Ninja-Generator dies nicht tut, wĂ€hrend alle anderen Generatoren dies tun. Ich habe mehrere Male Stunden damit verbracht, ein AbhĂ€ngigkeitsproblem aufzuspĂŒren, nur um festzustellen, dass dies eine weitere Instanz von Depfile-Pfaden ist, die nicht mit Build-Manifest-Pfaden abgeglichen werden. Die Tools liefern die Informationen, die Ninja benötigt, um AbhĂ€ngigkeiten zu erfassen, aber Ninja ignoriert sie.

Ihre Position kommt als Meinung rĂŒber, dass relative Pfade allgemein besser sind. Andere Leute sind anderer Meinung, dass absolute Pfade in manchen FĂ€llen besser sind. Ich glaube nicht, dass es der Ort eines Build-Tools ist, relative Pfade zu evangelisieren.

Mein Vorschlag fĂŒgt Ninja eine kleine Menge an Infrastruktur hinzu. Was tut weh? Wenn Sie es nicht haben, werden viel grĂ¶ĂŸere Kosten nach außen getragen.

Ja, das ist wahr!

Und mit absoluten Pfaden ist cmake in der Lage, doppelte Compiler-Include-Pfade zu eliminieren.
Dadurch verkĂŒrzt sich die Bauzeit nochmals.

Am 09.03.2021 um 19:20 schrieb Brad King [email protected] :

Ich glaube nicht, dass es der Ort eines Build-Tools ist, relative Pfade zu evangelisieren.

Ich habe das CMake-Problem in Bezug auf ein Problem eingerichtet, mit dem wir konfrontiert sind, wenn der Quick-Compiler von Qt cpp-Dateien generiert und Unity Build aktiviert hat. Meine Recherchen vor Ort ergaben, dass Ninja das mit Abstand schnellste Bausystem ist, aber in dieser Konstellation unzuverlÀssig ist. Jetzt stehe ich vor dem Problem, wie ich einen Workaround finden oder die Build-Zeit-Erhöhung rechtfertigen kann.

CMake ist gerade auf ein Problem mit zirkulĂ€ren AbhĂ€ngigkeiten gestoßen, das bis vor kurzem von diesem Ninja-Problem verdeckt wurde. Wenn dieses Problem behoben worden wĂ€re, hĂ€tten wir das CMake-Problem viel frĂŒher entdeckt.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen