Wie je ook vraagt hoe je software op de juiste manier bouwt, komt met Make als een van de antwoorden. Op GNU/Linux-systemen is GNU Make [1] de open-sourceversie van de originele Make die meer dan 40 jaar geleden - in 1976 - werd uitgebracht. Make werkt met een Makefile - een gestructureerd tekstbestand met die naam dat het best kan worden omschreven als de constructiehandleiding voor het softwarebouwproces. De Makefile bevat een aantal labels (targets genoemd) en de specifieke instructies die moeten worden uitgevoerd om elk doel te bouwen.
Simpel gezegd, Make is een bouwtool. Het volgt het recept van taken uit de Makefile. Hiermee kunt u de stappen op een geautomatiseerde manier herhalen in plaats van ze in een terminal te typen (en waarschijnlijk fouten te maken tijdens het typen).
Lijst 1 toont een voorbeeld Makefile met de twee doelen "e1" en "e2" evenals de twee speciale doelen "alle" en "schoon.Het uitvoeren van "make e1" voert de instructies voor doel "e1" uit en maakt het lege bestand aan. Het uitvoeren van "make e2" doet hetzelfde voor doel "e2" en maakt het lege bestand twee. De aanroep van "make all" voert de instructies uit voor doel e1 eerst en e2 volgende. Om de eerder gemaakte bestanden één en twee te verwijderen, voert u eenvoudig de oproep "make clean" uit.”
Aanbieding 1
alle: e1 e2e1:
raak er een aan
e2:
twee aanraken
schoon:
rm een twee
Lopend merk
Het gebruikelijke geval is dat u uw Makefile schrijft en vervolgens het commando "make" of "make all" uitvoert om de software en zijn componenten te bouwen. Alle doelen zijn gebouwd in seriële volgorde en zonder enige parallellisatie. De totale bouwtijd is de som van de tijd die nodig is om elk afzonderlijk doel te bouwen.
Deze aanpak werkt goed voor kleine projecten, maar duurt vrij lang voor middelgrote en grotere projecten. Deze aanpak is niet langer up-to-date aangezien de meeste huidige CPU's zijn uitgerust met meer dan één kern en de uitvoering van meer dan één proces tegelijk mogelijk maken. Met deze ideeën in het achterhoofd kijken we of en hoe het bouwproces parallel kan lopen. Het doel is om simpelweg de bouwtijd te verkorten.
Verbeteringen aanbrengen
Er zijn een paar opties die we hebben - 1) vereenvoudig de code, 2) distribueer de afzonderlijke taken naar verschillende computerknooppunten, bouw de code daar en verzamel het resultaat vanaf daar, 3) bouw de code parallel op een enkele machine, en 4) combineer opties 2 en 3.
Optie 1) is niet altijd gemakkelijk. Het vereist de wil om de runtime van het geïmplementeerde algoritme en kennis over de compiler te analyseren, i.e., hoe vertaalt de compiler de instructies in de programmeertaal naar processorinstructies?.
Optie 2) vereist toegang tot andere computerknooppunten, bijvoorbeeld speciale computerknooppunten, ongebruikte of minder gebruikte machines, virtuele machines van cloudservices zoals AWS of gehuurde rekenkracht van services zoals LoadTeam [5]. In werkelijkheid wordt deze aanpak gebruikt om softwarepakketten te bouwen. Debian GNU/Linux gebruikt het zogenaamde Autobuilder-netwerk [17] en RedHat/Fedors gebruikt Koji [18]. Google noemt zijn systeem BuildRabbit en wordt perfect uitgelegd in de talk van Aysylu Greenberg [16]. distcc [2] is een zogenaamde gedistribueerde C-compiler waarmee u code op verschillende knooppunten parallel kunt compileren en uw eigen bouwsysteem kunt opzetten.
Optie 3 maakt gebruik van parallellisatie op lokaal niveau. Dit kan voor u de optie zijn met de beste kosten-batenverhouding, omdat er geen extra hardware voor nodig is zoals bij optie 2. De vereiste om Make parallel uit te voeren, is het toevoegen van de optie -j in de aanroep (afkorting van -jobs). Dit specificeert het aantal taken dat tegelijkertijd wordt uitgevoerd. De onderstaande lijst vraagt aan Make om 4 taken parallel uit te voeren:
Aanbieding 2
$ make --jobs=4Volgens de wet van Amdahl [23] zal dit de bouwtijd met bijna 50% verkorten. Houd er rekening mee dat deze aanpak goed werkt als de afzonderlijke doelen niet van elkaar afhankelijk zijn; de uitvoer van doel 5 is bijvoorbeeld niet vereist om doel 3 te bouwen.
Er is echter één neveneffect: de uitvoer van de statusberichten voor elk Maak doel lijkt willekeurig en deze kunnen niet langer duidelijk worden toegewezen aan een doel. De uitvoervolgorde is afhankelijk van de werkelijke volgorde van de taakuitvoering.
Definieer uitvoeringsvolgorde maken
Zijn er uitspraken die Make helpen begrijpen welke doelen van elkaar afhankelijk zijn?? Ja! Het voorbeeld Makefile in Listing 3 zegt dit:
* om doel "alles" te bouwen, voer je de instructies uit voor e1, e2 en e3
* target e2 vereist dat target e3 eerder is gebouwd
Dit betekent dat de doelen e1 en e3 parallel kunnen worden gebouwd, eerst, dan volgt e2 zodra de bouw van e3 is voltooid, tenslotte.
Lijst 3
alle: e1 e2 e3e1:
raak er een aan
e2: e3
twee aanraken
e3:
drie aanraken
schoon:
rm een twee drie
Visualiseer de maak afhankelijkheden
De slimme tool make2graph van het makefile2graph [19]-project visualiseert de Make-afhankelijkheden als een gerichte acyclische grafiek. Dit helpt om te begrijpen hoe de verschillende doelen van elkaar afhankelijk zijn. Make2graph voert grafiekbeschrijvingen uit in dot-indeling die u kunt omzetten in een PNG-afbeelding met behulp van de dot-opdracht van het Graphviz-project [22]. De oproep is als volgt:
Lijst 4
$ alles maken -Bnd | make2graph | punt -Tpng -o grafiek.pngEerst wordt Make aangeroepen met het doel "all" gevolgd door de opties "-B" om onvoorwaardelijk alle doelen te bouwen, "-n" (afkorting van "-dry-run") om te doen alsof de instructies per doel worden uitgevoerd, en " -d” (“-debug”) om foutopsporingsinformatie weer te geven. De uitvoer wordt doorgesluisd naar make2graph die de uitvoer doorstuurt naar de punt die de afbeeldingsbestandsgrafiek genereert.png in PNG-indeling.
De build-afhankelijkheidsgrafiek voor vermelding 3
Meer compilers en bouwsystemen
Zoals hierboven al uitgelegd, is Make meer dan vier decennia geleden ontwikkeld developed. In de loop der jaren is het parallel uitvoeren van taken steeds belangrijker geworden en sindsdien is het aantal speciaal ontworpen compilers en buildsystemen om een hoger niveau van parallellisatie te bereiken gegroeid. De lijst met tools omvat deze:
- Bazel [20]
- CMake [4]: afkorting voor platformonafhankelijke Make en maakt beschrijvingsbestanden die later door Make . worden gebruikt
- verschil [12]
- Distributed Make System (DMS) [10] (lijkt dood)
- dmake [13]
- LSF-merk (15)
- Apache Maven
- Meson
- Ninja-bouw
- NMake [6]: Maken voor Microsoft Visual Studio
- PyDoit [8]
- Qmake [11]
- opnieuw doen [14]
- SConen [7]
- wafel [9]
De meeste zijn ontworpen met het oog op parallellisatie en bieden een beter resultaat met betrekking tot de bouwtijd dan Make.
Conclusie
Zoals je hebt gezien, is het de moeite waard om na te denken over parallelle builds, omdat dit de bouwtijd tot een bepaald niveau aanzienlijk verkort. Toch is het niet gemakkelijk te bereiken en brengt het bepaalde valkuilen met zich mee [3]. Het wordt aanbevolen om zowel uw code als het buildpad te analyseren voordat u in parallelle builds stapt.
Links en referenties
- [1] GNU Make-handleiding: Parallelle uitvoering, https://www.gnu.org/software/make/manual/html_node/Parallel.html
- [2] distcc: https://github.com/distcc/distcc
- [3] John Graham-Cumming: de valkuilen en voordelen van GNU maken parallellisatie, https://www.cmkruispunt.com/article/valkuilen-en-voordelen-gnu-make-parallelization
- [4] CMake, https://cmake.org/
- [5] LoadTeam, https://www.loadteam.com/
- [6] NMaak, https://docs.microsoft.com/nl-nl/cpp/build/reference/nmake-reference?weergave=msvc-160
- [7] SCons, https://www.scons.org/
- [8] PyDoit, https://pydoit.org/
- [9] Waf, https://gitlab.com/ita1024/waf/
- [10] Distributed Make System (DMS), http://www.nongnu.org/dms/index.html
- [11] Qmake, https://doc.qt.io/qt-5/qmake-handleiding.html
- [12] distmake, https://sourceforge.net/projecten/distmake/
- [13] dmake, https://docs.orakel.com/cd/E19422-01/819-3697/dmake.html
- [14] opnieuw, https://redo.leesdedocs.io/nl/laatste/
- [15] LSF-merk, http://sunray2.mit.edu/kits/platform-lsf/7.0.6/1/guides/kit_lsf_guide_source/print/lsf_make.pdf
- [16] Aysylu Greenberg: Building a Distributed Build System at Google Scale, GoTo Conference 2016, https://gotocon.com/dl/goto-chicago-2016/slides/AysyluGreenberg_BuildingADistributedBuildSystemAtGoogleScale.pdf
- [17] Debian Build-systeem, Autobuilder-netwerk, https://www.debian.org/devel/buildd/index.en.html
- [18] koji - RPM-bouw- en volgsysteem, https://pagure.io/koji/
- [19] makefile2graph, https://github.com/lindenb/makefile2graph
- [20] Bazel, https://bazel.bouwen/
- [21] Makefile-zelfstudie, https://makefiletutorial.com/
- [22] Graphviz, http://www.grafviz.org
- [23] Wet van Amdahl, Wikipedia, https://en.wikipedia.org/wiki/Amdahl%27s_law