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.