CONAN exports vs. exports_sources

Seit eineinhalb Jahren darf bzw. muss ich mit CONAN zurecht kommen und langsam “hat man sich eingewöhnt”.

Jetzt kommt die Phase wo man feststellt, dass man von Anfang an vieles verkehrt aufgebaut hat, weil damals eben vieles falsch verstanden wurde.

Und ein solcher lästiger Punkt ist exports und exports_sources.


Nachdem ich nun meine Erkenntnisse schon ein paar mal verbal weiterverteilt habe, macht es Sinn alles niederzuschreiben und dann darauf zu verweisen.

OpenSource funktioniert anders

In der OpenSource Welt wird CONAN anders eingesetzt, als wir es in Firmen-internen Buildumgebungen tun.
Da gibt es:

  • ein Projekt, das den Build “irgendwie” durchführt und Ergebnisse produziert und publiziert.
  • und ein CONAN Projekt, das nur aus einem conanfile.py besteht.

conanfile.py implementiert dort eine source() Methode, die die Ergebnisse des OpenSource Projektes aus dem Internet herunterlädt (manchmal als Quellcodes, manchmal als fertige Binärdateien). Danach läuft falls erforderlich ein Build-Vorgang und danach wird ein CONAN Paket geschnürt.

Bei dieser Form von Trennung, hat das CONAN Projekt keine Abhängigkeiten zu anderen Dateien, weil es alles, was es braucht, während der Ausführung aus dem Netz herunterlädt. Manche Projekte nutzen dann zusätzlich exports: "\*", weil einige Lizenzdateien beiliegen, die sie immer dabei haben wollen.

Problem: exports: “*”

In unserem Build-System hingegen werden die Quellcodes der Projekte aus GIT geladen und dann wird das dort inkludierte conanfile.py mit conan create . aufgerufen um die Sourcen zu bauen und ein CONAN Paket zu schaffen.

Immer wieder stößt man dabei auf die Zeile exports: "*" bzw. exports: ( "*", "!private"). CONAN exportiert dann den gesamten Checkout-Ordner (ohne die Einträge, die durch ! ausgeschlossen wurden).
Danach springt die build() Methode an und kann “irgendwie” alles finden, bauen und fertigstellen.

Doch dieser Weg ist falsch!

exports soll nur all jenes exportieren oder “wegsichern”, was CONAN braucht um conanfile.py auszuführen. Siehe Doku.
Hat man also ein zweites Python Script mit Hilfsroutinen neben conanfile.py liegen und nutzt es aus dem CONAN Script heraus, dann muss es “exportiert” werden, um später für die Ausführung zur Verfügung zu stehen.

Wenn nun eine andere Komponente eine Abhängigkeit zu unserer erstellten deklariert, lädt CONAN alles “exportierte” zusammen mit conanfile.py herunter und führt Teile davon aus, um die Abhängigkeiten korrekt aufzulösen.
Da macht es keinen Sinn, dass Sourcecodes (oder noch schlimmer: Binärdateien) dabei sind, was bei exports: "\*" der Fall wäre.

Dieser falsche Weg wird eingeschlagen, weil alles, was durch exports markiert wird, automatisch auch im Build-Schritt den Build-Tools zur Verfügung steht.

Aber eben genau dafür existiert exports_sources, damit diese Inhalte in einem eigenen Ordner im CONAN Cache gespeichert werden. Bei einer Abhängigkeits-Auflösung werden diese Daten dann nämlich nicht mit heruntergeladen. Sehr wohl wird der Inhalt aber beim Build-Vorgang in den Build-Ordner kopiert, damit alles gebaut werden kann.

Fazit

Für meine Arbeitswelt existieren also zwei Formen der Nutzung von CONAN:

  • conanfile.py hat eine source() Methode, die die eigentlichen Daten von einem anderen Ort herunterlädt (oder irgendwie generiert)
  • oder conanfile.py liegt bei den Sourcen und speichert sich die Quellcodes per exports_sources im Cache weg, um sie dann nur beim Neubauen (Build-Schritt) einzusetzen.

Wir konnten jedenfalls durch die Umstellung von exports: "*" zu exports_sources: ( "include/*", "lib/*", "source/*") Downloads von mehreren 100 MB durch wenige Kilobytes ersetzen.

Und nachdem Dank Azure und andere Cloud-Dienste die Daten quer über den Planeten verschickt werden, bringt das am Ende einiges.
Trotzdem tauchen immer wieder kleinere Projekte auf, bei denen diese Umstellung noch nicht durchgeführt wurde.

Die CONAN Dokumentation ist aus meiner Sicht nicht deutlich genug um diese Ausprägungen zu beschreiben … und somit macht man es am Anfang leider oft falsch, bis man aus Schaden klug wird.

… wie so oft in unserer digitalen Welt.