1 Punkte von GN⁺ 2024-09-22 | 2 Kommentare | Auf WhatsApp teilen
  • Auch wenn ständig neue Build-Tools erscheinen, bleibt das Makefile als leichtgewichtiges Standardwerkzeug nützlich, um wiederkehrende Aufgaben in Projekten zu bündeln
  • Dank konventioneller Befehle wie make, make build, make install und make dev kann man auch bei unbekannten Projekten schnell Build, Installation und Start des Entwicklungsservers ausprobieren
  • Unabhängig vom Stack – etwa Jekyll, Hugo, 11ty, Python-Web-Frameworks, Docker oder gulp – dient das Makefile als gemeinsame Ausführungsschnittstelle
  • In persönlichen Projekten reichen oft ein paar einfache Targets wie dev, build und deploy statt Bedingungen oder Flags
  • GNU Make ist weit verbreitet, und selbst wenn es fehlt, lassen sich die Shell-Befehle aus dem Makefile direkt ausführen, wodurch es auch in eingeschränkten Umgebungen wenig Hürden gibt

Unterschiedliche Projektbefehle in einem Einstiegspunkt bündeln

  • Ein Makefile wird genutzt, um Projekte mit unterschiedlichen Build-, Ausführungs- und Deployment-Methoden in eine vertraute Befehlsmenge zu verpacken
  • Wenn ein unbekanntes Projekt ein Makefile hat, kann man meist zuerst diese Befehle ausprobieren
    • make
    • make build
    • make install
  • Wenn man ein altes persönliches Projekt wieder öffnet, kann man es so einrichten, dass schon make dev alle nötigen Build-Schritte und den Start des Entwicklungsservers auf einmal erledigt
  • Auch bei unterschiedlichen Technologie-Stacks wie Jekyll, Hugo, 11ty oder verschiedenen Python-Web-Frameworks kann derselbe Einstiegspunkt erhalten bleiben
  • Selbst wenn Docker oder gulp verwendet werden, ersetzt das Makefile diese Tools nicht, sondern fungiert als Orchestrierungsschicht
    • Beispiel: make build baut die nötigen Docker-Images und übergibt dabei projektspezifische Zusatzargumente

Einfache Nutzung in persönlichen Projekten

  • Beim Einsatz von Makefiles liegt der Fokus eher auf Bündeln von Shell-Befehlen als auf komplexen Funktionen
    • Funktionen wie Bedingungen oder Flags werden nicht verwendet
    • Die Arbeitseinheit von make ist technisch gesehen ein Target, wird praktisch aber wie ein Task behandelt
    • Man könnte das auch als Bash-Skriptfunktion bauen, aber ein Makefile wird als einfacher und schneller angesehen
  • In persönlichen Projekten gibt es meist nur 2 bis 3 häufig genutzte Aufgaben
    • dev: Entwicklungsserver starten
    • build: Projekt bei Bedarf bauen
    • deploy: Projekt deployen oder veröffentlichen
    • watch: zusätzliche Aufgabe, um Build-Schritte bei Änderungen an Quelldateien automatisch erneut auszuführen
  • Das aktuelle Blog-Makefile hat nur ein einziges Target: dev
    • Unter dev: wird npm run dev ausgeführt
  • In komplexeren persönlichen Projekten werden folgende Aufgaben in einem Makefile gebündelt
    • dev: Entwicklungsserver mit bundle exec jekyll serve starten
    • build: Assets mit npm run gulp build bauen
    • watch: bestimmtes Verzeichnis mit npm run gulp watch überwachen
    • deploy: Jekyll für die Produktionsumgebung bauen und danach make encrypt, netlify deploy --prod ausführen
    • encrypt: HTML-Dateien im Ordner _site mit npx staticrypt verschlüsseln

Wichtige Einschränkungen und Vorteile

  • Im Beispiel wurden phony targets ausgelassen, aber wenn es Dateien mit Namen wie dev, build, watch, deploy oder encrypt gibt, funktioniert das Makefile möglicherweise nicht wie erwartet
  • GNU Make ist die Software, die makefiles ausführt; unter Linux ist sie vermutlich bereits installiert, und auch auf dem MacBook ist sie so verbreitet, dass man sich oft nicht einmal an eine separate Installation erinnert
  • Make verlangt nicht viele zusätzliche Abhängigkeiten und kann deshalb in eingeschränkten Umgebungen nützlich sein, in denen die Installation von Paketen aus Sicherheitsgründen schwierig oder unmöglich ist
  • Selbst wenn Make nicht vorhanden ist, lassen sich die Befehle aus dem Makefile direkt in die Shell kopieren und ausführen
    • Im Gegensatz dazu ist es schwierig, JavaScript-Code einfach direkt ins Terminal einzufügen und auszuführen, wenn gulp auf dem Server nicht vorhanden ist
  • Selbst wenn man ein besseres und schnelleres neues Build-Tool findet, kann Make weiterhin als gemeinsame Befehlsschicht genutzt werden, um unterschiedliche Tools und Konfigurationen zu verwalten

2 Kommentare

 
kayws426 2024-09-22

Wenn keine Abhängigkeiten definiert sind, bietet ein Ersatz des makefile durch justfile eine bessere Benutzerfreundlichkeit.

 
GN⁺ 2024-09-22
Hacker-News-Meinungen
  • Man muss sich in diesem Thread nicht davon entmutigen lassen, dass einem gesagt wird, man „benutze make falsch“. Einer der Gründe, warum Make ein gutes Tool ist: Man kann damit einfacher anfangen, als es auf den ersten Blick wirkt.
    Wenn man .PHONY nicht verwendet, kann das Probleme verursachen, aber bei einem kleinen Projekt ist das vielleicht eine Falle, in die man erst ein Jahr später tappt; und selbst dann ist es wahrscheinlich mit etwa einer Stunde Kopfkratzen erledigt. In 99 % der Fälle kann man einfach loslegen, ohne sich um die „Lehrbuchlösung“ zu kümmern, und Make verlangt nur so viel Komplexität, dass es nicht auseinanderfällt.

    • Eine der schlechtesten Eigenschaften von Make ist, dass es oberflächlich betrachtet einfach wirkt.
      Make nimmt Eingabedateien und Abhängigkeiten und erzeugt genau eine Ausgabedatei. Regeln, die keine Ausgabe erzeugen, wie install, all oder clean, sowie alle Targets des Artikels müssen von einem speziellen magischen Target wie .PHONY abhängen; .PHONY gab es in POSIX von 2017 (IEEE Std 1003.1-2017, https://pubs.opengroup.org/onlinepubs/9699919799/utilities/m...) noch nicht und ist erst im aktuellen Standard (IEEE Std 1003.1-2024, https://pubs.opengroup.org/onlinepubs/9799919799/utilities/m...) enthalten. Wenn man mehrere Dateien erzeugen will, etwa Objektdateien und Module oder vorkompilierte Header, muss man sich selbst fragile Workarounds bauen. Nicht jedes Make ist GNU Make; auch BSD, Solaris/Illumos und andere nix-artige Systeme existieren noch.
      Das heißt nicht, dass Make nutzlos wäre. Es ist nützlich für Projekte, die komplex genug sind, aber noch nicht so komplex, dass sie ein „besseres“ Build-System brauchen. Das Problem ist, dass solche Projekte mit wachsendem Code komplexer werden und am Ende Skripte/Programme haben, die ein Makefile oder Teile davon erzeugen – womit ein provisorisches Meta-Build-System entsteht.
      Das größere Problem ist nicht, dass man es verwendet, sondern dass es „allen“ als Lösung vorgeschlagen wird. Und sobald im Projekt-Root ein Verzeichnis oder eine Datei namens build oder dev auftaucht, funktioniert dieses Makefile nicht mehr.
    • Ein Beispiel für ein etwas komplexeres Makefile, das ich beim Start eines neuen TypeScript-Projekts verwende, gibt es hier: https://github.com/borisovg/node-ts-template/blob/main/Makef...
      Heutzutage würde ich zwar auf pnpm umstellen, aber besonders komplex finde ich es trotzdem nicht. Man muss die Syntax zwar ein Stück weit kennen, aber es ist weniger schwierig, als andere Tools von Anfang an korrekt zum Laufen zu bringen.
    • Ich habe make seit über 20 Jahren in vielen Projekten und mehreren Sprachen gut eingesetzt und hatte nie Probleme mit den .PHONY-Tasks, um die sich die Leute so viele Gedanken machen.
      Es ist einfach, gut lesbar, änderbar, kombinierbar und praktisch überall bereits installiert. Es tut, was auf der Oberfläche steht, und kaum mehr.
      Nebenbei: Wenn ich in anderen Projekten mit modischen oder albtraumhaften Build-Systemen umgehen muss, wickle ich sie ebenfalls mit make ein.
    • Stimme voll zu. Es ist besser, das passende Tool für die Aufgabe zu verwenden, und auch wenn man kein Experte ist, ist das viel besser, als aus Angst vor perfektionistischer Kritik das falsche Tool zu wählen.
      Jeder muss irgendwo anfangen, und sobald etwas erst einmal läuft, lassen sich schrittweise Verbesserungen leicht ergänzen.
    • Jedes makefile-Rezept sollte genau ein Ausgabeartefakt erzeugen: $@. Das gesamte Makefile kann beliebig viele Ausgaben erzeugen, weil Regeln von anderen Regeln abhängen können.
      Daraus ergibt sich eine saubere Faustregel für phony Targets: Wenn ein Rezept nicht nur $@ anfasst, sollte $@ als phony markiert werden. Es ist viel einfacher, phony Targets als Liste zu verwalten.
      phonies :=
      phonies += something
      something:
      ./do-something
      phonies += something-else
      something-else: something
      ./do-something-else
      # touches $@ and thus does not need to be phony
      create-file:
      ./generate-some-output > $@
      .PHONY: $(phonies)
  • Makefiles sind eine miserable Technik. Nur sind sie etwas weniger schlecht als die meisten anderen Build-Systeme, die wir gebaut haben, und werden dadurch in selbstquälerischem Sinne nützlich.
    Build-Systeme sind meist entweder so grundlegend, dass sie beim Bauen von mehr als Spielzeugprojekten im Chaos enden, oder so komplex, dass Vorwissen, Bürokratie, Synchronisierung und Boilerplate überhandnehmen, oder sie haben keine Standardbibliothek, sodass sich dieselben Build-Muster auf 10.000 inkompatible Implementierungen verteilen, oder sie sind so restriktiv, dass man bei wachsenden Anforderungen migrieren muss, oder sie enthalten zu viel Magie, oder die Syntax ist schwer verständlich und inkonsistent.

    • Meiner Meinung nach ist Makefile eine hervorragende Technik; viele haben sie nur nicht richtig gelernt oder nutzen sie nicht so, wie sie gedacht ist.
      Mehr als die Hälfte der Software, die ich nutze, verwendet nur ein schlichtes Makefile und gelegentlich ein configure-Skript. Ohne autotools optional ./configure ausführen und dann make, make install – und es funktioniert einfach. Das ist keineswegs eine Spielzeug-Konfiguration, sondern besteht aus kleinen Programmen, die jeweils eine Sache gut machen.
      Make und seine Funktionsweise sind zumindest für mich leicht zu verstehen. Ich glaube, die schlechten Erfahrungen, die Leute gemacht haben, liegen oft eher an schlechten Build-Konfigurationen komplexer Projekte oder an fehlendem nötigem Wissen als an Make selbst.
      Dass es keine Standardbibliothek gibt, ist als Werkzeugunabhängigkeit gedacht, und genau deshalb ist es universell auf verschiedene Werkzeuge, Sprachen und Einsatzzwecke anwendbar. Ich sehe das nicht als Fehler, sondern als Feature. Die einfache Ebene ist Dependency-Tracking, und Targets und Abhängigkeiten sind ebenfalls klar, daher wirkt es kaum magisch. Die Syntax könnte allerdings definitiv besser sein.
    • Die schlimmsten Build-Systeme sind jene, die um eine bestimmte Programmiersprache herum gebaut wurden. Wenn es N>>1 Sprachen gibt, gibt es auch N>>1 Build-Systeme, und die kognitive Last wird so groß, dass das nicht skaliert.
      Die einzigen allgemeinen Build-Systeme, die mehrere Sprachen abdecken, sind make oder Systeme wie CMake, die auf make abzielen. Der Grund, warum das nicht ideal ist, liegt darin, dass make nicht ideal ist. make richtig zu verwenden ist wirklich schwierig; es gibt Probleme wie rekursives Make und nicht-rekursives Make, viele inkompatible Varianten wie Unix/POSIX make, BSD make, GNU make und Windows nmake, und es ist ziemlich hässlich.
      Trotzdem ist korrekt eingesetztes make ziemlich gut. Es ist wirklich ein Glück, dass es make als kleinsten gemeinsamen Nenner gibt.
    • Zustimmung. Viele Alternativen sind ebenfalls nicht wie Make ein allgemeines Werkzeug zum „irgendetwas ausführen“, sondern auf bestimmte Sprachen fokussiert.
      Dass Make nicht einmal Unterverzeichnisse sauber handhaben kann, ist ziemlich absurd. Ich frage mich, ob es etwas Besseres als Make gibt. Ninja existiert zwar, ist aber nicht dafür entworfen, direkt von Menschen geschrieben zu werden.
    • Kann man wirklich sagen, dass dieses Chaos „sehr hypothetisch“ überhaupt nichts mit Compilern oder Sprachen ohne Module zu tun hat?
      Wie hoch würdest du den Anteil einschätzen? 20 %, 40 %, vielleicht 70 % trifft es doch ungefähr?
    • Bei „mehr als eins“ bleibt viel Spielraum. Meine Einschätzung ist: Makefile ist nicht zu grundlegend. Es kann zu komplex werden, aber das hängt davon ab, wie man es baut. Eine Standardbibliothek gibt es insofern, als es eingebaute Funktionen gibt. Zu restriktiv hat es sich für mich nie angefühlt, also würde ich nein sagen. Da Targets und Abhängigkeiten klar sind, gibt es auch nicht viel Magie. Nur die Syntax könnte definitiv besser sein; schon eine schlichte JSON-Datei wäre vermutlich besser.
  • Ich mag Make wirklich sehr. In den letzten 20 Jahren habe ich für jede Aufgabe oder jedes Projekt, an dem ich gearbeitet habe, mindestens eines geschrieben.
    Da ist nichts Cleveres dran, nur eine Sammlung von Schnipseln mit ein paar Variablen. Etwa make run, make test, make lint.
    make recent führt nach dem Linting das zuletzt geänderte Skript aus. Das ginge auch mit Bash oder einer anderen Shell, aber dann wird man in die Entwicklerwelt hineingezogen, die Komplexität steigt, und es entsteht kein zusätzlicher Wert. Make ist lediglich eine domänenspezifische Sprache für „diese Datei wird aus diesen Dateien erzeugt, und dabei werden diese ein oder zwei Befehle ausgeführt“. Genau deshalb ist es enorm mächtig.

    • Mir gefällt die Formulierung „diese Datei wird aus diesen Dateien erzeugt, und dabei werden diese ein oder zwei Befehle ausgeführt“.
      Vor Jahrzehnten habe ich in Java ein Test-Framework gebaut, in dem man Tests und abhängige Klassen mit einer make-ähnlichen Syntax angeben konnte. Es gab eine Menge von Testklassen, die ein „Basis-Testbündel“ definierten, und andere Ebenen von Testklassen, die davon abhingen und nur ausgeführt wurden, wenn die vorherige Stufe erfolgreich war.
      Ich weiß nicht, warum heutzutage alles so kompliziert gemacht wird. Ich habe immer geraten, bei den Standard-Unix-Werkzeugen und ihrer Arbeitsweise zu bleiben, also bei dem, was sich über die Zeit bewährt hat – sofern es nicht eine Situation ist, in der das absolut unmöglich ist. Zeit ist endlich, daher möchte ich sie für das Wesentliche der Problemlösung nutzen: System-/Programmdesign, Modellierung, Struktur, Patterns usw.; der Rest ist zweitrangig.
    • Jedes Makefile, das mir in der Praxis begegnet ist, tat deutlich mehr, als dass man sagen könnte: „Das ist alles.“
    • Bei mir ist es ähnlich. Früher habe ich es kaum verwendet, aber in meiner aktuellen Firma gibt es in fast jedem Repository ein Makefile.
      Es ist eine große Erleichterung zu wissen, dass make test funktioniert – unabhängig von Stack, Sprache oder Repository.
    • Das Problem von Make ist nicht Make selbst, sondern dass die Dinge, die Make aufruft, nicht mehr nach diesem Modell funktionieren.
      Im Makefile meines letzten Projekts gab es vier Hauptbefehle: build, test, frontend, deploy. build und test riefen maven auf, frontend rief npm auf, deploy rief docker und aws auf.
      Diese Werkzeuge haben alle eigenes State-Tracking, Caching und inkrementelle Verarbeitung, berichten aber nicht, was sie getan haben. Deshalb kann man keine atomaren Regeln wie „nur deployen, wenn der Build aktualisiert wurde“ schreiben. Denn maven/cargo/dotnet/npm/go legen diese Information nicht offen.
  • Der Autor verwendet nicht einmal mtime-basierte Abhängigkeitsverfolgung. Die Targets müssten außerdem .PHONY sein, sind aber nicht entsprechend markiert. Man hätte das auch durch ein Shell-Skript ersetzen können, das $1 liest, abgleicht und entscheidet, was zu tun ist.

    • Oder man könnte es durch einen einfachen Command-Runner wie just ersetzen.
      https://just.systems/
    • Es gibt eine Ein-Zeilen-Horrorgeschichte aus einem realen Projekt: .PHONY: $(MAKECMDGOALS)
      ./build.sh dev ist zwar weniger eindeutig als make dev. Ein weiterer Grund, Make zu verwenden, selbst wenn es gar keine nicht-phony Schritte gibt, ist aber, dass man solche Schritte später hinzufügen kann, falls man sie braucht. Natürlich stimme ich zu, dass der Autor {dev,build,deploy} als phony markieren sollte.
    • Technisch stimmt das, aber der Kernpunkt, den ich aus dem Artikel mitgenommen habe, ist, dass man Konsistenz in der Bedienung bekommt, nicht nur in den eigenen Projekten, sondern auch in Third-Party-Projekten.
      Das eigene Makefile ließe sich technisch verbessern, aber wichtiger ist, dass die „Getting started“-Erfahrung beim Einstieg in ein Projekt konsistent ist.
    • Wir waren alle einmal Anfänger. Um ein Tool zu lernen, hilft es, es tatsächlich zu benutzen, selbst wenn es auf unvollkommene Anfängerart geschieht. Man kann es beim Lernen schrittweise verbessern.
    • Die Schönheit von make und der Shell liegt darin, dass sie dem Unix-Prinzip folgen: einfach sein und eine Sache gut machen.
      Die Leute wollen, dass es viele andere Dinge tut – Skriptsprache, Dependency-Tracker usw. – und ziehen dafür aufgeblähte Tools heran. Neu heißt nicht automatisch besser. Autoconf und automake sind nicht make.
  • Technisch gesehen suchen all diese make-Targets nach Dateien mit demselben Namen wie das Target. Jedes Target sollte tatsächlich als .PHONY definiert werden.
    Früher habe ich solche Makefiles ständig verwendet, aber in den letzten Jahren bin ich zu just und justfiles gewechselt. Dieses Verhalten ist dort der Standard, und insgesamt ist es einfacher zu benutzen. Dinge wie Parameter sind ebenfalls einfacher.
    https://github.com/casey/just

    • Solche make-ähnlichen Systeme sind ziemlich gut, haben aber ein Problem: Make ist bereits auf allen Linux- und Mac-Systemen vorhanden und unter Windows recht leicht zu bekommen. Dass es nicht in Git Bash enthalten ist, ist wirklich schade. Ich sehe es als großen Vorteil von Make, dass man den kleinsten gemeinsamen Nenner verwendet.
    • Der große Fehler von Make war, phony Targets und Datei-Targets im selben Namensraum zu vermischen. Phony Targets hätten zum Beispiel mit : beginnen sollen, sodass man sie schon am Namen unterscheiden kann.
      Dafür ist es jetzt natürlich zu spät.
    • just ist wirklich gut, aber es ist oft nicht installiert, was etwas lästig ist.
      Es scheint an der Zeit für eine neue Art von coreutils-Distribution zu sein, die neue und nützliche Tools wie just und ripgrep bündelt und überall dort installiert wird, wo man sie verwenden möchte.
  • Es ist interessant, dass make so heftige Debatten auslöst. Das erinnert an die früheren, halb religiösen vi-gegen-emacs-Debatten.
    Ich stimme dem ursprünglichen Beitrag voll zu und halte insbesondere den Ansatz für klug, auch bei ausgefeilteren Build-Tools einen Top-Level-Makefile-Wrapper zu verwenden. Der Vorteil ist Standardisierung. Ich muss mir nichts merken: Wenn es ein Projekt von mir ist, tippe ich einfach make ein und weiß, dass es funktioniert.
    Wenn zum Beispiel jemand aus der C-Welt ein Rust-Projekt kompilieren will, muss er nicht nachschlagen, wie cargo benutzt wird, sondern kann einfach make oder gmake eingeben. Ich versuche, keine GNU-spezifischen Features zu verwenden und POSIX-konform zu bleiben, aber es stimmt auch, dass fast 100 % der realen make-Installationen gmake sind.
    Der Vorschlag, das zeitlose make als eine Art Top-Level-Treiber für Build-Systeme zu verwenden, dürfte wahrscheinlich auch in 250 Jahren noch funktionieren.

    • Es ist amüsant, dass ein so schlichter Titel eine Flamewar ausgelöst hat. Der Artikel selbst zeigt einen wahnsinnig einfachen Anwendungsfall für make und handelt davon, 2024 gulp zu verwenden; offensichtlich hat ihn niemand gelesen.
    • cargo ist ein schlechtes Beispiel, weil universell cargo build verwendet wird.
      Make selbst ist großartig, aber in den meisten C-Projekten, an denen ich gearbeitet habe, war es eine Kombination aus cmake/autotools und globaler Paketinstallation, und solche Dinge musste ich häufig nachschlagen.
    • Vielleicht nicht, wenn vorher bazel/blaze die Vorherrschaft übernimmt. Falls du daran zweifelst, schau dir Chrome gegen Firefox oder Kubernetes gegen docker-compose an.
  • Ich stimme der Stimmung hier zu, schreibe aber vieles auf Justfile um.
    https://github.com/casey/just
    Damit lassen sich viele der Makefile-typischen Eigenheiten vermeiden.

    • Es stimmt, dass GPT Makefiles beim Schreiben hilft und dem Makefile ein zweites Leben gegeben und seinen Tod hinausgezögert hat.
    • Geht mir genauso. Dass dieselbe Datei auch unter Windows funktioniert, ist ein Bonus.
  • Ja, Make ist großartig. Ich benutze es für unglaublich viele Dinge. Es ist eine gute Art, Aufgaben zu automatisieren.
    Meine persönliche Website zum Beispiel wird über ein Makefile betrieben, das Bash-Skripte aufruft, um aktualisierte Webseiten neu zu erstellen, dann per git push auf den Server überträgt, woraufhin ein Git-Hook auf dem Server Make aufruft und deployt. Allerdings möchte ich häufig geänderte binäre Brocken wie PDFs mit Vorlesungsmaterial nicht im Git-Repository haben. Kein Problem: Im Makefile gibt es ein Target uploads, das nur geänderte PDFs auf den Server hochlädt, und dieses Target ist eine Abhängigkeit des deploy-Targets, das den git push ausführt, sodass ich mich nicht darum kümmern muss.
    Außerdem legt ein anderes Makefile aktualisierte PDFs für Vorlesungsmaterial automatisch in den Quellbaum der Website. Mit diesem Makefile kann ich aus LaTeX-Quellen die PDFs erzeugen, die ich benutze, oder aus denselben Quellen alternative Versionen für Studierende, zum Beispiel ohne Lösungen zu Übungsaufgaben, und sie automatisch in der lokalen Website-Version veröffentlichen, um sie dann bei Bedarf auf die aktualisierte Website hochzuladen.
    Es ist eine Art endlose Kette von Makefiles. Ich mag Makefiles.

  • Was der Autor in diesem Fall wirklich braucht, ist nicht make, sondern just.
    https://just.systems/man/en/

    • just ist nur eine weitere Abhängigkeit. make ist überall.
  • Als Task Runner ist make nicht schlecht, aber heutzutage gibt es, wie in anderen Kommentaren erwähnt, bessere Alternativen wie just.
    Als Build-System ist make in Ordnung, bis man auf seine Nachteile stößt. make/Makefile ist nicht standardisiert, deshalb gibt es automake. Man schreibt also nicht direkt ein Makefile, sondern verwendet Templates und lässt das eigentliche makefile erzeugen. Wenn man die gesamte Toolchain selbst kontrolliert, ist das egal, aber die meisten tun das nicht; deshalb macht man es so, um portable Makefiles zu gewährleisten.
    make führt keinerlei Dependency Resolution durch und geht davon aus, dass alles Benötigte genau dort vorhanden ist. Deshalb gibt es configure-Skripte; und weil auch configure-Skripte kein Standard sind, erzeugt man das configure-Skript mit autoconf/autoreconf, bevor man make-Targets ausführt.
    make und benachbarte Tools wie automake/autoconf/autoreconf verwenden mtime, um zu entscheiden, ob Eingaben veraltet sind. Es kann passieren, dass man trotz Ausführung von autoconf/autoreconf/automake/configure in einen Zustand gerät, in dem die Eingaben dauerhaft als veraltet gelten und sich nichts mehr bauen lässt. Zur Einordnung: Viele Build-Systeme kommen mit mtime gut zurecht, sofern es ein ordentliches Dependency Tracking gibt.
    Insgesamt liegt der grundlegende Designfehler von make darin, dass es an der Unix-Philosophie ausgerichtet ist: „Tu eine Sache und tu sie gut.“ Diese eine Sache ist: „Wenn Eingaben veraltet sind, baue das Target neu.“ Das ist ein sehr eingeschränktes Tool, sodass moderne Build-Systeme viel darüberstapeln müssen, um es über einen einfachen Task Runner hinaus nützlich zu machen.

    • make könne keine Dependencies auflösen?
      dependency:
      ...
      target: dependency
      ...
    • Vielleicht eine naive Frage, aber ist Dependency Resolution nicht der Kern von make? Was genau ist hier gemeint?
    • Die alte Konvention dafür ist make configure. Das richtet die Dinge ein, die für make [build] nötig sind.
    • Was mir bei make wirklich fehlt, ist nur die Fähigkeit, mtime nach anderen Kriterien als mtime zu interpretieren.
      Deshalb verwendet man touchfiles; das ist zwar unsauber, funktioniert aber immer noch besser als vieles andere. Ich meine damit insbesondere das Caching von docker build.