PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Makefile - Argumente f. unterschiedliche Builds?



shutdown
10-09-2008, 17:56
Hi,

ich schreibe momentan an einem Programm, das nun ein *optionales* GUI bekommen soll.
Die Frage ist nun, wie muss eine Makefile aussehen, damit ich über die Makefile steuern kann, ob der Code für das GUI mitkompiliert wird?
Der Code ist in 2 Dateien, gui.c und gui.h enthalten. gui.h wird in einer einzigen anderen Datei per #include eingebunden.

Mein Ziel ist es nun, ein "make" und ein "make no-gui" zu bekommen, in letzterem soll die GUI nicht mitkompiliert werden. (Um auch Systeme ohne X nutzen zu können)

Weiterer Haken: Für die GUI brauche ich CFLAGS und LIBS, die in der no-gui-Version ebenfalls nicht genutzt werden sollen.

Das Ganze ist ein Linuxprojekt, nur falls das noch etwas zur Sache tut.

Hier mal meine aktuelle Makefile:


CC = gcc
INSTALL = install
LIBS = `pkg-config --libs gtk+-2.0`
CFLAGS = -O2 -D_FILE_OFFSET_BITS=64 `pkg-config --cflags gtk+-2.0`

TARGET = chpchk
SRCS = intel.c amd.c toolkit.c gui.c chpchk.c
OBJS = intel.o amd.o toolkit.o gui.o chpchk.o
BLBS = intel_data.o amd_data.o

all: $(TARGET)

install: $(TARGET)
$(INSTALL) -s -m 0755 $(TARGET) /usr/bin/$(TARGET)

suid-install: $(TARGET)
$(INSTALL) -s -o root -g root -m 4755 $(TARGET) /usr/bin/$(TARGET)

intel_data.o:
ld -r -b binary -o intel_data.o intel.csv
amd_data.o:
ld -r -b binary -o amd_data.o amd.csv

$(TARGET): $(BLBS) $(OBJS)
$(CC) -o $(TARGET) $(OBJS) $(BLBS) $(LIBS)

%.o: %.c
$(CC) -o $@ -c $< $(CFLAGS)

clean:
rm -f $(OBJS) $(BLBS) core $(TARGET)

strip:
strip $(TARGET)

Alles was fett markiert ist, soll in der no-gui-Version aussen vor bleiben.

Wie stelle ich das Ganze an?
Ich habe mit Makefiles bisher kaum Erfahrung (ist um genau zu sein meine Erste).
Und wie schon gesagt, ich habe auch keine Ahnung, wie ich die #include gui.h-Zeile im Code dann "deaktivieren" kann...

Wäre für Hilfe extrem dankbar!!!

Peter

jan61
10-09-2008, 19:12
Moin,

zuerst die einfache Frage ;-) Optionales Einbinden kannst Du im Source natürlich mit #ifdef machen:

#ifdef GUI
#include gui.h
#endifDu definierst dann einfach ein Flag -DGUI für die GUI-Version und lässt ihn in der non-GUI-Version weg.

Für die non-GUI-Version definierst Du ein eigenes Target, die CFLAGS, SRCS und OBJS teilst Du in einen allgemeinen Teil und einen GUI-spezifischen und fütterst damit die Targets, z. B. so (ungetestet):

# ...
CFLAGS = -O2 -D_FILE_OFFSET_BITS=64
GUI_CFLAGS = -DGUI `pkg-config --cflags gtk+-2.0`

TARGET = chpchk
CLI_TARGET = cli_chpchk
SRCS = intel.c amd.c toolkit.c chpchk.c
GUI_SRCS = gui.c
OBJS = intel.o amd.o toolkit.o chpchk.o
GUI_OBJS = gui.o
BLBS = intel_data.o amd_data.o

all: $(TARGET)

# install-Targets noch anpassen

# ...

$(TARGET): $(BLBS) $(OBJS) $(GUI_OBJS)
$(CC) -o $(TARGET) $(OBJS) $(GUI_OBJS) $(BLBS) $(LIBS) $(GUI_LIBS)

$(CLI_TARGET): $(BLBS) $(OBJS)
$(CC) -o $(TARGET) $(OBJS) $(BLBS) $(LIBS)

$(OBJS): %.o: %.c
$(CC) -o $@ -c $< $(CFLAGS)

$(GUI_OBJS): %.o: %.c
$(CC) -o $@ -c $< $(CFLAGS) $(GUI_CFLAGS)

# usw.
Jan

shutdown
10-09-2008, 20:15
Sieht vielversprechend aus, als kleiner Hobby/Amateur-Programmierer werde ich das wohl nochmal lesen müssen um es zu 100% zu durchblicken :D
Das grobe Vorgehen habe ich jedenfalls verstanden, mit dem Beispiel kriege ich das gebacken - vielen Dank!!!

Peter

shutdown
10-09-2008, 21:05
$(OBJS): %.o: %.c
$(CC) -o $@ -c $< $(CFLAGS)

$(GUI_OBJS): %.o: %.c
$(CC) -o $@ -c $< $(CFLAGS) $(GUI_CFLAGS)Jan

Scheinbar gibt es hier noch ein Problem: Das -DGUI CFLAG wird hier nur den OBJS, die die GUI betreffen übergeben - d.h. das CFLAG wird in allen anderen OBJS nicht gesetzt und ich habe keine Möglichkeit, mit #ifdef zu prüfen, ob -DGUI gesetzt ist...

Peter

shutdown
10-09-2008, 21:28
Ich habe das Problem gelöst, allerdings mit einem wahrscheinlich etwas unschönem "Hack":


CC = gcc
INSTALL = install
LIBS =
LIBS_GUI = `pkg-config --libs gtk+-2.0`
CFLAGS = -O2 -D_FILE_OFFSET_BITS=64
CFLAGS_GUI = -DGUI `pkg-config --cflags gtk+-2.0`

TARGET = chpchk
TARGET_GUI = chpchk-gui
SRCS = intel.c amd.c toolkit.c terminal.c chpchk.c
SRCS_GUI = gui.c
OBJS = intel_.o amd_.o toolkit_.o terminal_.o chpchk_.o
OBJS_GUI = intel.o amd.o toolkit.o terminal.o chpchk.o gui.o
BLBS = intel_data.o amd_data.o

all: $(TARGET_GUI)

cmdline: $(TARGET)

install: $(TARGET)
$(INSTALL) -s -m 0755 $(TARGET) /usr/bin/$(TARGET)

suid-install: $(TARGET)
$(INSTALL) -s -o root -g root -m 4755 $(TARGET) /usr/bin/$(TARGET)

intel_data.o:
ld -r -b binary -o intel_data.o intel.csv
amd_data.o:
ld -r -b binary -o amd_data.o amd.csv

$(TARGET_GUI): $(BLBS) $(OBJS_GUI)
$(CC) -o $(TARGET) $(OBJS_GUI) $(BLBS) $(LIBS) $(LIBS_GUI)

$(TARGET): $(BLBS) $(OBJS)
$(CC) -o $(TARGET) $(OBJS) $(BLBS) $(LIBS)

$(OBJS): %_.o: %.c
$(CC) -o $@ -c $< $(CFLAGS)

$(OBJS_GUI): %.o: %.c
$(CC) -o $@ -c $< $(CFLAGS) $(CFLAGS_GUI)

clean:
rm -f $(OBJS) $(OBJS_GUI) $(BLBS) core $(TARGET)

strip:
strip $(TARGET)

Ein "make cmdline" erzeugt hier OBJS mit der Endung "_.o" und ein normales "make" bzw "make all" erzeugt ".o" OBJS. Damit kann ich die CFLAGS auf alle OBJS anwenden und es funktioniert wie gewollt.

Gibt es evtl "schönere" Lösungen?

Peter

undefined
11-09-2008, 17:42
Also du machst vieles sehr umständlich. Verwende AUTOMAKE mit libtool und nicht eine reines Make. Dann wird dir mehr wie 80% an Arbeit abgenommen. Einzelne Programme kannst du dann mit AC_ARG_WITH ein abschalten und mit einfachen IF Anweisungen in der Makefile.am einschränken.
siehe auch:
info:/autoconf/Generic Programs

Ich habe dir mal eines meiner Bibliotheken start Templates angehängt, hier kannst du vielleicht etwas besser ableiten.

jan61
11-09-2008, 18:57
Moin,


Also du machst vieles sehr umständlich. Verwende AUTOMAKE mit libtool und nicht eine reines Make.

ich halte es bei einem kleinen, überschaubaren Projekt schon für sinnvoll, auch mal in die Untiefen von Makefiles hinabzutauchen - das hilft mir u. a. oft, wenn ich die von anderen Projekten verstehen will (um herauszukriegen, warum zum Geier ein make mal wieder nicht durchläuft z. B.).

Wenn man dann in Zukunft professioneller arbeiten will, dann sind solche Hilfsmittel wie automake, autoconf etc. natürlich angebracht.

Jan

jan61
11-09-2008, 19:08
Moin,

das geht IMHO auch eleganter (wieder ungetestet):

# ...
CFLAGS = -O2 -D_FILE_OFFSET_BITS=64
GUI_CFLAGS = -DGUI `pkg-config --cflags gtk+-2.0`

TARGET = chpchk
CLI_TARGET = cli_chpchk
OBJS = intel.o amd.o toolkit.o chpchk.o
GUI_OBJS = $(OBJS) gui.o
BLBS = intel_data.o amd_data.o

all: $(TARGET)

# install-Targets analog

# ...

$(TARGET): $(BLBS) $(GUI_OBJS)
$(CC) -o $(TARGET) $(GUI_OBJS) $(BLBS) $(LIBS) $(GUI_LIBS)

$(CLI_TARGET): $(BLBS) $(OBJS)
$(CC) -o $(TARGET) $(OBJS) $(BLBS) $(LIBS)

$(OBJS): %.o: %.c
$(CC) -o $@ -c $< $(CFLAGS)

$(GUI_OBJS): %.o: %.c
$(CC) -o $@ -c $< $(CFLAGS) $(GUI_CFLAGS)

# usw.
Der Trick ist hier einfach, in die GUI-Objekte alle .o-Dateien aufzunehmen und die Abhängigkeiten entsprechend zu definieren.

2 Anmerkungen noch:

1. Die SRCS-Definitionen nutzt Du nirgends - müsste auch ohne diese Variablen funktionieren. Die Targets für die Objekt-Dateien nutzen ja eine Ersetzung der .o- durch .c-Endungen, um die Quellen zu definieren.

2. Wenn Du mehrmals nacheinander CLI- und GUI-Target kompilierst, dann musst Du drauf achten, zwischendurch ein make clean zu machen, weil sonst nicht alle Objekte mit den geänderten CFLAGS neu kompiliert werden (der Zeitstempel der Dateien ändert sich ja nicht).

Jan

shutdown
11-09-2008, 19:42
Nur eine kleine Info: offenbar geht ihr davon aus, dass ich in meinem Projekt mehrere verschiedene Programme habe - es handelt sich nur um ein einziges Programm, das eben eine optionale GUI bekommen soll bzw momentan bekommt.
autoconf & Co sind daher wohl wirklich ein bisschen Overkill, die Makefile habe ich auch nur, weil der Code mittlerweile unübersichtlich genug war, dass sich mehrere .c-Dateien lohnen.

Da es mein erstes etwas grösseres Projekt und meine erste Makefile sind, kenne ich mich auf dem Gebiet eben auch noch so gut wie gar nicht aus.
Wo müsste ich die $(SRCS) eigentlich nutzen? Die stehen wirklich ungenutzt rum...

Kann es sein, dass die irgendwo bei

$(OBJS): %.o: %.c
$(CC) -o $@ -c $< $(CFLAGS)
stehen sollten? (z.B. anstatt "%.c" ?)
Dadurch würden sich meine Probleme glaube ich auflösen, da die Sache sich an der Stelle IMHO etwas beisst.

Auf jeden Fall Danke für die Hilfe!!!

Peter

jan61
14-09-2008, 15:02
Moin,


Nur eine kleine Info: offenbar geht ihr davon aus, dass ich in meinem Projekt mehrere verschiedene Programme habe - es handelt sich nur um ein einziges Programm, das eben eine optionale GUI bekommen soll bzw momentan bekommt.

Nein, ich hatte Dich schon so verstanden. Deshalb auch mein Hinweis wegen des make clean - da es sich um die gleichen Zieldateien (.o und Executable) handelt, würde ein make mit neuem Target bei unveränderten Quellen sonst eben kein Neukompilieren mit geänderten Flags auslösen.


...Wo müsste ich die $(SRCS) eigentlich nutzen? Die stehen wirklich ungenutzt rum...

Kann es sein, dass die irgendwo bei

$(OBJS): %.o: %.c
$(CC) -o $@ -c $< $(CFLAGS)stehen sollten? (z.B. anstatt "%.c" ?)
Dadurch würden sich meine Probleme glaube ich auflösen, da die Sache sich an der Stelle IMHO etwas beisst.

Die musst Du gar nicht nutzen - Du kannst die Definitionen entfernen. Der Witz ist ja eben, dass die Konstruktion in obigem Target aus jeder in OBJS angegebenen Datei den Namen der als Abhängigkeit zu behandelnden Source über die Substitution (%.o: %.c) ermittelt. Du hast an der Stelle IMHO kein Problem.

Jan