I am struggling with a C project having multiple subdirectories where the .o
files should reside in a subdirectory "obj/". Like this:
/hzg/src/
/hzg/src/adaemon
/hzg/src/adaemon/obj
/hzg/src/bdaemon
/hzg/src/bdaemon/obj
/hzg/src/notrelateddir
C files are in *daemon/
, matching .o
files in *daemon/obj
.
A main Makefile should reside in /hzg/src
and there should be a Makefile in every /hzg/src/*daemon
I have defined my $(SOURCES)
and derived the $(OBJECTS)
with $(subst...)
.
What I am struggling with is to get the prerequisites in a rule properly defined...
Here's what I have so far:
(Sub-)Makefile in adaemon:
[...]
SOURCES = $(wildcard *.c)
OBJECTS = $(patsubst %.c, obj/%.o, $(SOURCES))
all: $(OBJECTS)
$(OBJECTS): obj/%.o : %.c $(HEADERS)
$(CC) $(CLFAGS) -c $< -o $@
This works like a charm. What I am struggling with is the "master" Makefile. How can I tell make to take the .o
from the obj/
directory and search for the matching .c
files?
Makefile
[...]
SUBDIRS := common:hzgd:masterd:mqttd:
SOURCES = $(wildcard $(subst :,/*.c , $(SUBDIRS)))
OBJECTS = $(subst /,/obj/,$(patsubst %.c,%.o,$(SOURCES)))
BIN = hzgmasterd
all : $(BIN)
$(BIN) : $(OBJECTS)
$(CC) $(CFLAGS) -rdynamic -o $(BIN) $(OBJECTS) $(LIBS)
@echo "Server done."
$(OBJECTS) : obj/%.o : %.c $(HEADERS)
$(CC) $(CFLAGS) -c $< -o $@
Oh, I would not mind using the "make -C" command but in this case it should only descend into the directory when an .o
file needs to be recompiled.
CodePudding user response:
Here is one way to structure your top-level makefile:
SUBDIRS := common hzgd masterd mqttd
SOURCES := $(wildcard $(addsuffix /*.c ,$(SUBDIRS)))
OBJECTS := $(foreach D,$(SUBDIRS),$(patsubst $D/%.c,$D/obj/%.c,$(SOURCES)))
BIN = hzgmasterd
all : $(BIN)
$(BIN) : $(OBJECTS)
$(CC) $(CFLAGS) -rdynamic -o $@ $^ $(LIBS)
@echo "Server done."
$(OBJECTS): $(SUBDIRS) ;
$(SUBDIRS):
$(MAKE) -C $@
.PHONY: $(SUBDIRS)
I didn't actually try this but I think it will work. By adding the semicolon these are actual rules and make will check the timestamps on the targets.
If you wanted to create a library in each subdirectory you'd define a rule that did that, probably naming the library after the directory it was in, that listed all the objects as prerequisites, then in this makefile you'd list one library per subdirectory as the prerequisites.
CodePudding user response:
thanks @MadScientist. Some minor glitches and types (ie foreach did not work) and I have a working solutions now.
"Master"-Makefile:
SUBDIRS := common hzgd masterd mqttd
CSUBDIRS := client
CFLAGS = -Wall
LIBS := -lconfig -lcurl -ljson-c -lm -lmodbus -lmosquitto -lownet -lpthread -lsystemd -lical
SOURCES := $(wildcard $(addsuffix /*.c ,$(SUBDIRS)))
OBJECTS := $(subst /,/obj/,$(subst .c,.o,$(SOURCES)))
HEADERS := $(wildcard *h)
CSOURCES := $(wildcard $(addsuffix /*.c ,$(CSUBDIRS)))
COBJECTS := $(subst /,/obj/,$(subst .c,.o,$(CSOURCES)))
CHEADERS := $(wildcard client/*h)
BIN := hzgmasterd
CBIN := client/hzgclnt
all : $(BIN) $(CBIN)
server : $(BIN)
client : $(CBIN)
#====================== Master ============================
$(BIN) : $(OBJECTS)
$(CC) $(CFLAGS) -rdynamic -o $@ $^ $(LIBS)
@echo "Server done."
$(OBJECTS) : $(SUBDIRS) ;
.PHONY: $(SUBDIRS)
$(SUBDIRS) :
$(MAKE) -C $@
#====================== Client ============================
.PHONY: $(CBIN)
$(CBIN) : $(CSUBDIRS)/
$(MAKE) -C $<
#====================== Aufräumen ============================
.PHONY : clean
clean :
rm -f $(BIN) $(OBJECTS) $(COBJECTS)
"Sub"-Makefiles:
[...]
SOURCES = $(wildcard *.c)
HEADERS = $(wildcard ../*h)
OBJECTS = $(patsubst %.c, obj/%.o, $(SOURCES))
all: $(OBJECTS)
#==================================================
$(OBJECTS): obj/%.o : %.c $(HEADERS)
$(CC) $(CLFAGS) -c $< -o $@
#====================== Aufräumen ============================
.PHONY: clean
clean:
rm -f *.o obj/*.o
A minor glitch is now make
descends into every subdirectory and executes another make process to decide if the target is up to date.
I understand this is by design even though it will cause additional steps.... however, it is working now even though I do not understand everything in the Makefile you posted.
Thanks a lot! /Christian