alexandernst
alexandernst

Reputation: 15099

Multiple targets and libraries in Makefile

I have this folder/files structure:

./libs/
    helpers.c
    helpers.h
./a_app.c
./b_app.c
./c_app.c

Each app depends on helpers lib and GStreamer, so I need to compile helpers.o (inside libs/ folder) and then link each app.

Currently I have this Makefile:

CC      =   gcc
CFLAGS  =   -g -Wall -w
LFLAGS  =   -g -Wall -w -c

CFLAGS  +=  `pkg-config --cflags gstreamer-app-0.10`
LFLAGS  +=  `pkg-config --cflags gstreamer-app-0.10`

LDFLAGS =
LDFLAGS +=  `pkg-config --libs gstreamer-app-0.10`

all: examples

examples: helpers.o a_app
    $(info *** examples ***)

helpers.o:
    $(info *** helpers.o ***)
    $(CC) $(LFLAGS) libs/helpers.c -o libs/helpers.o $(LDFLAGS)

a_app: a_app.o
    $(CC) $(CFLAGS) libs/helpers.o a_app.o -o a_app $(LDFLAGS)

a_app.o: a_app.c
    $(info *** a_app.o ***)
    $(CC) $(LFLAGS) a_app.c $(LDFLAGS)

While I could add b_appand c_app I'm looking for another (more elegant) way of doing it. Can't I just say that I have a, b and c _app and let Makefile compile them all and link them against GStreamer and helpers?

Also, is there any way to make Makefile compile files without needing to tell it -o name_of_file (and perhaps make it compile them in the folder that they are, because of the helpers library).

Upvotes: 0

Views: 4966

Answers (1)

FrankieTheKneeMan
FrankieTheKneeMan

Reputation: 6810

Okay, so - as we discussed in the comments, make can figure out how to make the .o files, so those rules are unnecessary. To make a generalized rule for all your *_app files (assuming they all have the same dependency on helpers.h, you can do this:

%_app: %_app.o libs/helpers.o

Make uses the % as a wildcard, and in the rule/dependency line the wildcard will expand to the same thing in the dependencies as it did in the rule. In the actual execution, you can use $* to get the same string. So a single rule for all your *_app executables winds up looking a bit like this:

%_app: %_app.o libs/helpers.o
    $(CC) $(CFLAGS) libs/helpers.o $*_app.o -o $*_app $(LDFLAGS)

I was testing this on my machine (hence comments instead of answers, and wound up writing this Makefile:

CC      =   gcc
CFLAGS  =   -g -Wall -w
LFLAGS  =   -g -Wall -w -c

CFLAGS  +=  `pkg-config --cflags gstreamer-app-0.10`
LFLAGS  +=  `pkg-config --cflags gstreamer-app-0.10`

LDFLAGS =
LDFLAGS +=  `pkg-config --libs gstreamer-app-0.10`

new: clean all

clean:
    rm -rf *.o */*.o *_app

all: examples

examples: a_app b_app

%_app: %_app.o libs/helpers.o
    $(CC) $(CFLAGS) libs/helpers.o $*_app.o -o $*_app $(LDFLAGS)

Does that all make sense?

EDIT: It occurs to me that GNU Make can run some commands on the command line and store the string for its own purposes.

$(shell ls *_app.c | sed 's/.c//') will expand into all the apps you have in the current directory. so you can say:

examples: $(shell ls *_app.c | sed 's/\.c//')

Or, as I think is a little better:

...
ALLAPPS = $(shell ls *_app.c | sed 's/\.c//')
...
all: $(ALLAPPS)

That way make can be used to make everything, and make ?_app can be used to compile one app at a time.

Super ultra mega double EDIT:

Using a bald % operator as a target will bust up Make's ability to auto generate .o files. Here's the solution we worked out in chat:

CC      =   gcc
CFLAGS  =   -g -Wall -w
LFLAGS  =   -g -Wall -w -c

CFLAGS  +=  $(shell pkg-config --cflags gstreamer-app-0.10)
LFLAGS  +=  $(shell pkg-config --cflags gstreamer-app-0.10)

LDFLAGS =
LDFLAGS +=  $(shell pkg-config --libs gstreamer-app-0.10)

TARGETS = $(shell ls *.c | sed 's/\.c//')

new: clean all

clean:
rm -rf *.o */*.o *_app

all: examples

examples: $(TARGETS)

.SECONDEXPANSION:
$(TARGETS): libs/helpers.o $$@.o
$(CC) $(CFLAGS) libs/helpers.o $@.o -o $@ $(LDFLAGS)

Upvotes: 2

Related Questions