Reputation: 37626
I have the following project structure:
lib/
Makefile
src/...
inc/...
build/
inc/...
lib/libmylib.a
subproj1/
src/main.cpp
Makefile
The Makefile
in the lib
folder is designed to create the file libmylib.a
and copy the relevant header files to the build/inc
folder.
I want the Makefile
in subproj1
to always call make -C ../lib
, but only re-compile file if headers have changed, and re-link only if necessary (one object file or libmylib.a
is newer).
I have the following (non-defined variables such as CC
are defined in another file):
LIBDIR = ../lib
SRCDIR = src
OBJDIR = obj
SRCS = $(SRCDIR)/main.cpp
MAIN=myexe
OBJS = $(SRCS:$(SRCDIR)/%.cpp=$(OBJDIR)/%.o)
DEPS = $(OBJS:.o=.d)
all: $(MAIN)
debug: CFLAGS += -g -DDEBUG
debug: LFLAGS += -g
debug: $(MAIN)
$(MAIN): $(OBJS) $(LIBDIR)/build/lib/libmylib.a
$(CC) $^ -o $@ $(LIBS) $(LFLAGS)
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp $(LIBDIR)/build/lib/libmylib.a
mkdir -p $(OBJDIR)
$(CC) -c -o $@ $(CFLAGS) $(INCS) -MD -MF $(patsubst %.o, %.d, $@) $<
$(LIBDIR)/build/lib/libmylib.a:
make -C $(LIBDIR)
-include $(DEPS)
.PHONY: clean $(LIBDIR)/build/lib/libmylib.a
clean:
$(RM) obj/* $(MAIN)
The above will re-compile main.cpp
even if nothing has changed in the lib folder. If I remove $(LIBDIR)/build/lib/libmylib.a
from the $(OBJDIR)/%.o
rule, the .cpp
file will not be re-compiled if a header changed (I would need to run make
twice).
Is there a way to have the .cpp
files in subproj1
being compiled only if the header files in lib
have changed (or if the .cpp
files themselves have changed), and to get myexe
built only if one of the .cpp
has been re-compiled (newer .o
) or if libmylib.a
is newer?
Upvotes: 2
Views: 294
Reputation: 1825
This might be a bit cleaner.
LIBDIR = ../lib
SRCDIR = src
OBJDIR = obj
SRCS = $(SRCDIR)/main.cpp
MAIN=myexe
OBJS = $(SRCS:$(SRCDIR)/%.cpp=$(OBJDIR)/%.o)
DEPS = $(OBJS:.o=.d)
all: makelib
$(MAKE) $(MAIN)
debug: CFLAGS += -g -DDEBUG
debug: LFLAGS += -g
debug: $(MAIN)
$(MAIN): $(OBJS)
$(CC) $^ -o $@ $(LIBS) $(LFLAGS)
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp
mkdir -p $(OBJDIR)
$(CC) -c -o $@ $(CFLAGS) $(INCS) -MD -MF $(patsubst %.o, %.d, $@) $<
makelib:
make -C $(LIBDIR)
-include $(DEPS)
.PHONY: clean makelib
clean:
$(RM) obj/* $(MAIN)
The main target all
requires makelib
to be built, and then it recursively calls itself for the target $(MAIN)
(so all of $(MAIN)
's dependencies will be recalculated after makelib
has finished building).
Upvotes: 0
Reputation: 136355
With recursive makefiles you need to execute the sub-project makefiles in correct order because the dependency tree is incomplete (e.g. this makefile does not know that updating $(LIBDIR)/build/lib/libmylib.a
also updates those headers). It is easy to do that with a shell script or a top-level makefile.
Alternatively, your makefile must execute the sub-makefiles unconditionally in correct order, which can be done with shell
function, e.g.:
LIBDIR := ../lib
pid := $(shell ps -o ppid= $$$$)
$(shell ${MAKE} -C ${LIBDIR} >/proc/$(pid)/fd/1 2>/proc/$(pid)/fd/2)
That $(LIBDIR)/build/lib/libmylib.a
rule should be removed, the object files should not depend on the .a
and it should not be marked as .PHONY
.
This makes sure that building in ${LIBDIR}
happens before this makefile analyzes file timestamps in ${LIBDIR}
.
Now your auto-generated header dependencies should just work.
Upvotes: 1