Discussion:
Ueberfluessige *.o- und sonstige Dateien
(zu alt für eine Antwort)
Stefan Reuther
2020-08-22 08:03:59 UTC
Permalink
Hallo,

ich baue diverse Programme, wie man das halt so macht: *.c/*.cpp nach
*.o compilieren, in *.a einpacken, Binaries draus machen.

Nun passiert es gelegentlich, dass beim Refactoring ein *.cpp und damit
ein *.o entfällt. *.a wird ohne dieses neu gebaut, soweit alles fein.

Allerdings liegt dann noch das alte *.o rum. Das an sich wäre kein
Problem. Beim Bauen mit Coverage-Analyse stürzt sich dann allerdings
lcov auf die dazugehörigen *.gcno/*.gcda Dateien und mault (a) dass es
dazu keinen Quelltext mehr findet und (b) dass dafür keine Testabdeckung
besteht.

Kennt da jemand best practices wie man mit sowas umgeht - außer
gelegentlich eben alles plattmachen und neu bauen?


Stefan
Dietrich Clauss
2020-08-22 15:34:23 UTC
Permalink
Post by Stefan Reuther
ich baue diverse Programme, wie man das halt so macht: *.c/*.cpp nach
*.o compilieren, in *.a einpacken, Binaries draus machen.
Welches Buildsystem? Ich nehme mal an, `make`.
Post by Stefan Reuther
Nun passiert es gelegentlich, dass beim Refactoring ein *.cpp und damit
ein *.o entfällt. *.a wird ohne dieses neu gebaut, soweit alles fein.
Nicht ganz, s.u.
Post by Stefan Reuther
Allerdings liegt dann noch das alte *.o rum. Das an sich wäre kein
Problem. Beim Bauen mit Coverage-Analyse stürzt sich dann allerdings
lcov auf die dazugehörigen *.gcno/*.gcda Dateien und mault (a) dass es
dazu keinen Quelltext mehr findet und (b) dass dafür keine Testabdeckung
besteht.
Kennt da jemand best practices wie man mit sowas umgeht - außer
gelegentlich eben alles plattmachen und neu bauen?
Best practice ist da vmtl. wirklich ein `make clean`. Bei ordentlich
aufgebauten Makefiles reicht ein `make clean` im entsprechenden
Verzeichnis.

Alternativ kann man im Zuge des Refactoring das betreffende *.o einfach
mit löschen. Das reicht aber noch nicht. Man muß auch alle
Folgeprodukte löschen. Das *.a wird sonst gar nicht neu gebaut, denn
keines der benötigten *.o ist jünger als dieses.

- Dietrich
Stefan Reuther
2020-08-23 07:31:17 UTC
Permalink
Post by Dietrich Clauss
Post by Stefan Reuther
ich baue diverse Programme, wie man das halt so macht: *.c/*.cpp nach
*.o compilieren, in *.a einpacken, Binaries draus machen.
Welches Buildsystem? Ich nehme mal an, `make`.
Das tritt mit den verschiedensten Buildsystemen auf. In der Firma mit
CMake, das Makefiles macht. Daheim hab ich mir versehentlich einen
Generator gefrickelt, der Makefiles oder ninja ausspuckt.
Post by Dietrich Clauss
Post by Stefan Reuther
Kennt da jemand best practices wie man mit sowas umgeht - außer
gelegentlich eben alles plattmachen und neu bauen?
Best practice ist da vmtl. wirklich ein `make clean`. Bei ordentlich
aufgebauten Makefiles reicht ein `make clean` im entsprechenden
Verzeichnis.
Alternativ kann man im Zuge des Refactoring das betreffende *.o einfach
mit löschen. Das reicht aber noch nicht. Man muß auch alle
Folgeprodukte löschen. Das *.a wird sonst gar nicht neu gebaut, denn
keines der benötigten *.o ist jünger als dieses.
Das Problem mit dem *.a ist gelöst: Kommandozeile zum Bauen des *.a
geändert -> Bauprodukt wird gelöscht und neu erstellt. Ninja macht sowas
intern, in Makefiles geht das mit etwas Gebastel auch.

Das betreffende *.o zu löschen ist nicht so einfach, weil es das
mehrfach gibt: mehrere Build-Workspaces für verschiedene
Konfigurationen, teilweise auch unbeaufsichtigt (CI).


Stefan
Dietrich Clauss
2020-08-23 18:18:56 UTC
Permalink
[überflüssige *.o-Files]
Post by Stefan Reuther
Post by Dietrich Clauss
Post by Stefan Reuther
Kennt da jemand best practices wie man mit sowas umgeht - außer
gelegentlich eben alles plattmachen und neu bauen?
Best practice ist da vmtl. wirklich ein `make clean`. Bei ordentlich
aufgebauten Makefiles reicht ein `make clean` im entsprechenden
Verzeichnis.
Alternativ kann man im Zuge des Refactoring das betreffende *.o einfach
mit löschen. Das reicht aber noch nicht. Man muß auch alle
Folgeprodukte löschen. Das *.a wird sonst gar nicht neu gebaut, denn
keines der benötigten *.o ist jünger als dieses.
Das Problem mit dem *.a ist gelöst: Kommandozeile zum Bauen des *.a
geändert -> Bauprodukt wird gelöscht und neu erstellt. Ninja macht sowas
intern, in Makefiles geht das mit etwas Gebastel auch.
Das betreffende *.o zu löschen ist nicht so einfach, weil es das
mehrfach gibt: mehrere Build-Workspaces für verschiedene
Konfigurationen, teilweise auch unbeaufsichtigt (CI).
OK, Problem erkannt, aber eine wirklich saubere Lösung fällt mir dafür
auch nicht ein. Das Buildsystem kann zwar überflüssige *.o ermitteln,
aber es kann nicht wissen, zu welchen (Zwischen-)zielen sie gehört
haben.

Vmtl. würde ich hier in das CI-Buildscript eine Logik einbauen, die
entsprechende `gcov`-Warnungen erkennt und in dem Fall ein `make clean`
probiert, gefolgt von einem neuen Build-Lauf.

- Dietrich
Stefan Reuther
2020-08-24 07:55:01 UTC
Permalink
Post by Dietrich Clauss
Vmtl. würde ich hier in das CI-Buildscript eine Logik einbauen, die
entsprechende `gcov`-Warnungen erkennt und in dem Fall ein `make clean`
probiert, gefolgt von einem neuen Build-Lauf.
Das ist vermutlich gar keine so dumme Idee.

Statt dem `make clean` allerdings eher "den Build-Workspace komplett
wegwerfen"; das Problem ist ja gerade, dass die "*.gcno"-Dateien dem
Buildsystem und somit dem `make clean` gar nicht bekannt sind. Die
Relation *.o -> *.gcno/*.gcda hartzucodieren halte ich auch für gewagt,
es gibt ja auch andere Dateien, die da parallel anfallen könnten. Ich
hatte schon Toolchains in der Hand, die haben zu jedem *.o ein *.dbo
erzeugt.


Danke,
Stefan
Rainer Weikusat
2020-08-24 21:45:50 UTC
Permalink
[...]
Post by Dietrich Clauss
Vmtl. würde ich hier in das CI-Buildscript eine Logik einbauen, die
entsprechende `gcov`-Warnungen erkennt und in dem Fall ein `make clean`
probiert, gefolgt von einem neuen Build-Lauf.
Eventuell koennte man auch die .o-Datei, wegen der gewarnt wird, loeschen
(lassen) und dann das ganze nochmal versuchen (dh alles andere, was
bereits uebersetzt wurde, weiterbenutzen).
Bastian Blank
2020-08-22 16:17:35 UTC
Permalink
Post by Stefan Reuther
Kennt da jemand best practices wie man mit sowas umgeht - außer
gelegentlich eben alles plattmachen und neu bauen?
Man nimmt ein Buildsystem das weiß welche Dateien da sind und was daraus
gebaut wird. Dem ist es vollkommen egal, das dort noch ein foobar.o
rumliegt.

Bastian
Stefan Reuther
2020-08-23 07:32:47 UTC
Permalink
Post by Bastian Blank
Post by Stefan Reuther
Kennt da jemand best practices wie man mit sowas umgeht - außer
gelegentlich eben alles plattmachen und neu bauen?
Man nimmt ein Buildsystem das weiß welche Dateien da sind und was daraus
gebaut wird. Dem ist es vollkommen egal, das dort noch ein foobar.o
rumliegt.
Welches Buildsystem zum Beispiel?

Dass dort ein foobar.o rumliegt, ist CMake/Make/Ninja auch vollkommen
egal. Dem lcov ist aber nicht egal, dass dort noch ein foobar.gcno
rumliegt, und das wird auch in keinerlei Buildskript erwähnt.


Stefan
Sven Hartge
2020-08-24 13:19:21 UTC
Permalink
Post by Stefan Reuther
Allerdings liegt dann noch das alte *.o rum. Das an sich wäre kein
Problem. Beim Bauen mit Coverage-Analyse stürzt sich dann allerdings
lcov auf die dazugehörigen *.gcno/*.gcda Dateien und mault (a) dass es
dazu keinen Quelltext mehr findet und (b) dass dafür keine
Testabdeckung besteht.
Kennt da jemand best practices wie man mit sowas umgeht - außer
gelegentlich eben alles plattmachen und neu bauen?
"Gelegentlich"?

Die CI sollte doch immer eine saubere Umgebung aus z.B. dem GIT erzeugen
und gar keinen alten Müll beinhalten.

Alles andere ist doch nix Halbes, nix Ganzes.

S!
--
Sigmentation fault. Core dumped.
Stefan Reuther
2020-08-26 10:00:13 UTC
Permalink
Hi,
Post by Sven Hartge
Post by Stefan Reuther
Allerdings liegt dann noch das alte *.o rum. Das an sich wäre kein
Problem. Beim Bauen mit Coverage-Analyse stürzt sich dann allerdings
lcov auf die dazugehörigen *.gcno/*.gcda Dateien und mault (a) dass es
dazu keinen Quelltext mehr findet und (b) dass dafür keine
Testabdeckung besteht.
Kennt da jemand best practices wie man mit sowas umgeht - außer
gelegentlich eben alles plattmachen und neu bauen?
"Gelegentlich"?
Die CI sollte doch immer eine saubere Umgebung aus z.B. dem GIT erzeugen
und gar keinen alten Müll beinhalten.
Naja, warum denn die "saubere Umgebung"? Doch nur, weil 100%
zuverlässige inkrementelle Builds immer noch schwierig sind.

Bis auf das Problem mit den *.gcno/*.gcda meine ich, das Problem für
meine Software eigentlich gelöst zu haben und würde gerne die gewonnene
Zeit nutzen, stattdessen mehr Varianten (clang vs g++, x86 vs x64 vs ARM
usw.) zu bauen, ohne mir dafür einen dicken Serverschrank mit drölfzig
CPUs hinstellen zu müssen.


Stefan
Sven Hartge
2020-08-26 11:07:19 UTC
Permalink
Post by Stefan Reuther
Post by Sven Hartge
Post by Stefan Reuther
Allerdings liegt dann noch das alte *.o rum. Das an sich wäre kein
Problem. Beim Bauen mit Coverage-Analyse stürzt sich dann allerdings
lcov auf die dazugehörigen *.gcno/*.gcda Dateien und mault (a) dass es
dazu keinen Quelltext mehr findet und (b) dass dafür keine
Testabdeckung besteht.
Kennt da jemand best practices wie man mit sowas umgeht - außer
gelegentlich eben alles plattmachen und neu bauen?
"Gelegentlich"?
Die CI sollte doch immer eine saubere Umgebung aus z.B. dem GIT erzeugen
und gar keinen alten Müll beinhalten.
Naja, warum denn die "saubere Umgebung"? Doch nur, weil 100%
zuverlässige inkrementelle Builds immer noch schwierig sind.
Bis auf das Problem mit den *.gcno/*.gcda meine ich, das Problem für
meine Software eigentlich gelöst zu haben und würde gerne die
gewonnene Zeit nutzen, stattdessen mehr Varianten (clang vs g++, x86
vs x64 vs ARM usw.) zu bauen, ohne mir dafür einen dicken
Serverschrank mit drölfzig CPUs hinstellen zu müssen.
Warum dröflzig CPUs? Für soetwas wurden Container oder mindestens
chroots erfunden.

S!
--
Sigmentation fault. Core dumped.
Stefan Reuther
2020-08-26 20:13:44 UTC
Permalink
Post by Sven Hartge
Post by Stefan Reuther
Post by Sven Hartge
Die CI sollte doch immer eine saubere Umgebung aus z.B. dem GIT erzeugen
und gar keinen alten Müll beinhalten.
Naja, warum denn die "saubere Umgebung"? Doch nur, weil 100%
zuverlässige inkrementelle Builds immer noch schwierig sind.
Bis auf das Problem mit den *.gcno/*.gcda meine ich, das Problem für
meine Software eigentlich gelöst zu haben und würde gerne die
gewonnene Zeit nutzen, stattdessen mehr Varianten (clang vs g++, x86
vs x64 vs ARM usw.) zu bauen, ohne mir dafür einen dicken
Serverschrank mit drölfzig CPUs hinstellen zu müssen.
Warum dröflzig CPUs? Für soetwas wurden Container oder mindestens
chroots erfunden.
Das soll halt auch irgendwann mal fertig werden.

Ich baue in der Tat in einer Sandbox (konkret: unter Zuhilfenahme von
<https://github.com/BobBuildTool/bob>, was mit User Namespaces im
Wesentlichen sowas wie Container macht).

Gerade bei dem Privatkram bin ich nicht die QA-Abteilung, die den
hunderten Entwicklern auf die Finger klopft, sondern der neugierige
Entwickler, der wissen will, in welcher Konfiguration das jetzt wieder
nicht klappt.

Und beim Dienstkram hab ich schon entgegnet bekommen "dein
Codereview-Fund ist absolut berechtigt, aber die (nicht inkrementell
bauende) Pipeline braucht aktuell 6 Stunden, das änder ich jetzt nicht
mehr".

Also inkrementell Bauen für mehr Geschwindigkeit ist schon schön.


Stefan

Loading...