I'm writing a makefile for handling the dependency of build units ONE and TWO -> build unit LIB.
By "build unit" I mean a directory containing directories src, lib, include and bin, as well as a makefile for compiling the source code in src. Libraries are placed in "lib" and library header-files in "include". The compiled binary is placed in "bin". A build unit accepts "make", "make all", "make lint" and "make clean".
When a change is made to a header-file in LIB, this makefile is meant to detect it and recompile + install (copy .a+.h-files to ONE and TWO) the new version of LIB before compiling.
.PHONY: ONE TWO CLEAN LINT
ALL: ONE TWO
%.a %.h:
@echo ---------- Compiling LIB ----------
@cd LIB && gmake.exe LIB
LIB_HEADERS := $(wildcard LIB/src/*.h)
ONE: ONE/lib/libLIB.a $(subst LIB/src/,ONE/include/,$(LIB_HEADERS))
@echo ---------- Compiling $@ ----------
@cd $@ && gmake.exe
TWO: TWO/lib/libLIB.a $(subst LIB/src/,TWO/include/,$(LIB_HEADERS))
@echo ---------- Compiling $@ ----------
@cd $@ && gmake.exe
CLEAN LINT:
@cd ONE && gmake.exe $@
@cd TWO && gmake.exe $@
@cd LIB && gmake.exe $@
(Assume the makefile for LIB handles copying into ONE and TWO)
- How come make does not run the rule "%.a %.h:" when I make a change to one of the header-files in LIB/src?
How do I generalize ONE and TWO into a single rule? I want to do this (but a target cannot be used in dependencies, at least this way):
ONE TWO: $@/lib/libLIB.a $(subst LIB/src/,$@/include/,$(LIB_HEADERS)) @echo ---------- Compiling $@ ---------- @cd $@ && gmake.exe
UPDATE:
I found the solution by taking a step back, drawing Directed Acyclic Graphs, and thinking in terms of single files, instead of all files of a certain type.
Here is the (not very elegant) solution, for completeness:
.PHONY: ONE TWO CLEAN LINT
ALL: ONE TWO
LIB_HEADERS := $(sort $(subst name.h,,$(wildcard LIB/src/*.h)))
# ------------------------------------------------------------
ONE/include/%.h: LIB/src/%.h
@echo Copying $< to $@
@mkdir ONE\\include 2> NUL || :)
@copy $(subst /,\,$<) ONE\\include\\ 1> NUL
TWO/include/%.h: LIB/src/%.h
@echo Copying $< to $@
@mkdir TWO\\include 2> NUL || :)
@copy $(subst /,\,$<) TWO\\include\\ 1> NUL
# ------------------------------------------------------------
ONE/lib/liblib.a: LIB/bin/liblib.a
@echo Copying $< to $@
@mkdir ONE\\lib 2> NUL || :)
@copy $(subst /,\,$<) ONE\\lib\\ 1> NUL
TWO/lib/liblib.a: LIB/bin/liblib.a
@echo Copying $< to $@
@mkdir TWO\\lib 2> NUL || :)
# Windows-equivalent of touch (discarding any output to stdout):
@copy $(subst /,\,$<) TWO\\lib\\ 1> NUL
# ------------------------------------------------------------
LIB/bin/liblib.a: $(LIB_HEADERS) $(wildcard LIB/src/*.cpp)
@echo ---------- Looking for changes to liblib ----------
@cd LIB && gmake.exe LIB
@copy /b $(subst /,\,$@) +,, 1> NUL || :)
# ------------------------------------------------------------
ONE: ONE/lib/liblib.a $(subst LIB/src/,ONE/include/,$(LIB_HEADERS))
@echo ---------- Compiling ONE ----------
@cd ONE && gmake.exe
TWO: TWO/lib/liblib.a $(subst LIB/src/,TWO/include/,$(LIB_HEADERS))
@echo ---------- Compiling TWO ----------
@cd TWO && gmake.exe
# ------------------------------------------------------------
CLEAN LINT:
@cd ONE && gmake.exe $@
@cd TWO && gmake.exe $@
@cd LIB && gmake.exe $@
I very much welcome tips on how to generalize ONE and TWO further.