Programmteile mittels Makefile steuern



  • Hallo ihr Lieben,

    ich probiere mich daran Programmteile beim Kompilieren ein- bzw. auszubauen. Bisher habe ich folgendes Minimalbeispiel samt Makefile.

    Ich kann also beim Kompilieren entscheiden, ob Hello World! ausgegeben werden soll, indem ich entweder make HELLO=true oder make HELLO=false eintippe.

    Wobei ich mir den ersten Fall sparen kann, weil true als Default Wert gesetzt wurde.

    Ist das okay so? Oder gibt es da elegantere Wege? Ich habe z.B. gemerkt, dass das Makefile ziemlich schnell ziemlich komplex wird, wenn ich versuche die verschiedenen Fälle abzudecken.

    Weiterhin muss ich im Quellcode viele #ifdef / #endif setzen.

    Okay, das ist Arbeit, aber mir irgendwann lieber als jedes Mal im Quellcode irgendwelche Zeilen auskommentieren.

    Gruß,
    Klaus.

    #include <iostream>
    
    int main()
    {
    
      #ifdef HELLO
    	  std::cout << "Hello World!" << std::endl;
      #endif
    
    	return 0;
    }
    
    CC=g++
    CCOPT=-Wall -pedantic -std=c++11 -c
    OPTI=-O2
    MAIN=me
    LINK=-Wall -pedantic -std=c++11 -o "$(MAIN)" $(MAIN).o
    
    HELLO=false
    
    # Linking it all together
    $(MAIN): $(MAIN).o
    	$(CC) $(LINK) 
    
    ifeq ($(HELLO),true)
    me.o: me.cpp
    	$(CC) $(CCOPT) $(OPTI) -DHELLO $(MAIN).cpp
    endif
    
    ifeq ($(HELLO),false)
    me.o: me.cpp
    	$(CC) $(CCOPT) $(OPTI) $(MAIN).cpp
    endif
    
    run:
    	./$(MAIN)
    

  • Mod

    Möglich ist das, aber es ist unüblich, dies so zu handhaben. Üblicherweise dient das Makefile wirklich nur dem Erstellen und Installieren eines Programmpakets, die Konfiguration wird üblicherweise in einem früheren Schritt gemacht. Je nach benutzter Toolchain ist das oft ein configure-Script oder ähnliches*. Diese Scripte erstellen dann beispielsweise einen Konfigurationsheader, in dem dann entsprechende Makros gesetzt werden, je nach gewünschter Konfiguration.

    Dein Makefile ist noch etwas uneinheitlich bezüglich deiner Benutzung von me.cpp und $(MAIN).cpp.

    Es gäbe für Makefiles auch noch tausende implizite Regeln, die man hier nutzen könnte, aber das ist ein anderes Thema.

    *: "Ähnliches" kann durchaus auch bedeuten, dass das Makefile selber zur Konfiguration benutzt wird. Aber eben vor dem Schritt, der das Paket baut.



  • Hallo,

    SeppJ schrieb:

    [..], die Konfiguration wird üblicherweise in einem früheren Schritt gemacht. Je nach benutzter Toolchain ist das oft ein configure-Script oder ähnliches*. Diese Scripte erstellen dann beispielsweise einen Konfigurationsheader, in dem dann entsprechende Makros gesetzt werden, je nach gewünschter Konfiguration.

    Ich verstehe. Ich habe schon ein Config-File um Parameter durchstimmen zu können, s.d. das Programm nicht jedes Mal neu kompiliert werden muss.

    Ich wollte in diesem Zusammenhang allerdings darauf verzichten im Quellcode dann jede Menge if-Abfragen einzubauen, die über das Config-File gesteuert werden, sondern direkt beim Kompilieren entscheiden, ob ein Programmteil mitgenommen wird oder nicht.

    Das heißt ich muss jetzt ein configure-script schreiben? So wie hier oder dort ?

    SeppJ schrieb:

    Dein Makefile ist noch etwas uneinheitlich bezüglich deiner Benutzung von me.cpp und $(MAIN).cpp.

    Ja, das ist dem Zusammenkopieren geschuldet, um schnell ein lauffähiges Minimalbeispiel zu erzeugen.

    Gruß,
    Klaus.


  • Mod

    Klaus82 schrieb:

    Hallo,

    SeppJ schrieb:

    [..], die Konfiguration wird üblicherweise in einem früheren Schritt gemacht. Je nach benutzter Toolchain ist das oft ein configure-Script oder ähnliches*. Diese Scripte erstellen dann beispielsweise einen Konfigurationsheader, in dem dann entsprechende Makros gesetzt werden, je nach gewünschter Konfiguration.

    Ich verstehe. Ich habe schon ein Config-File um Parameter durchstimmen zu können, s.d. das Programm nicht jedes Mal neu kompiliert werden muss.

    Ich wollte in diesem Zusammenhang allerdings darauf verzichten im Quellcode dann jede Menge if-Abfragen einzubauen, die über das Config-File gesteuert werden, sondern direkt beim Kompilieren entscheiden, ob ein Programmteil mitgenommen wird oder nicht.

    Nein, ich meine eine Compilezeit Konfigurationsdatei. Die config.h aus dem Wikipediaartikel.

    Das heißt ich muss jetzt ein configure-script schreiben? So wie hier oder dort ?

    Ja, sofern du die GNU autotools nutzen möchtest. Beziehungsweise nein, da, wie du in den verlinkten Texten siehst, das Konfiurationsskript normalerweise nicht selber schreibst, sondern eine Art proto-Skript für den Konfigurations- und Makevorgang aus dem dann die configure- und make-Skripte erzeugt werden. Wobei auch das Schreiben dieser Proto-Skripte wiederum teilweise automatisierbar ist.

    Es gibt auch viele andere Buildsysteme, aber prinzipiell haben die alle die Absicht, diese Vorgänge möglichst zu automatisieren, so dass der Gesamtvorgang sowohl für Entwickler als auch für den Anwender möglichst nutzerfreundlich ist. Früher waren die GNU Autotools unangefochten, aber in den letzten ~10 Jahren haben sie viel gute Konkurrenz bekommen.

    Das ganze ist halt eine lange Kette: Makefiles automatisieren das Compilieren und Linken, andere Tools automatisieren das Schreiben von Makefiles, andere Tools automatisieren die automatisierte Erstellung der Makefiles, usw. 😃 . Man braucht sicher nicht für jedes Popelprojekt die volle Toolchain.



  • So, habe tatsächlich ein Minimalbseispiel hinbekommen.

    Nachdem ich autoconf eingeben habe, kann ich mittels ./configure oder ./configure --enable-hello entscheiden, ob anschließend im Makefile HELLO=false oder HELLO=true steht.

    Das ist doch mal ein Anfang!

    Der nächste Schritt wäre nun, dass die if Abfrage vom Makefile direkt ins Configure File geschoben wird? 😕

    Viele Grüße,
    Klaus.

    AC_INIT(me.cpp)
    
    HELLO="false"
    
    AC_ARG_ENABLE(hello,
      [ --enable-hello Print Hello to screen!],
    	[ HELLO="true" ]
    	)
    
    AC_SUBST(HELLO)
    
    AC_OUTPUT(Makefile)
    

    und

    CC=g++
    CCOPT=-Wall -pedantic -std=c++11 -c
    OPTI=-O2
    MAIN=me
    LINK=-Wall -pedantic -std=c++11 -o "$(MAIN)" $(MAIN).o
    
    HELLO=@HELLO@
    
    # Linking it all together
    $(MAIN): $(MAIN).o
    	$(CC) $(LINK)
    
    ifeq ($(HELLO),true)
    me.o: me.cpp
    	$(CC) $(CCOPT) $(OPTI) -DHELLO $(MAIN).cpp
    endif
    
    ifeq ($(HELLO),false)
    me.o: me.cpp
    	$(CC) $(CCOPT) $(OPTI) $(MAIN).cpp
    endif
    
    run:
    	./$(MAIN)
    

  • Mod

    Die Antwort ist nach wie vor die bereits erwähnte config.h. Wie oft soll ich das noch sagen?


Log in to reply