- Laundry list
- makefiles should remove all content that it will generate.
- prefer library rules whenever possible or create library rules that are missing.
- dependency builds - A second invocation of make within a sandbox should always be a NOP.
- hardcoded values - avoid them like the plague. Use variable assignments, autogen paths and dynamic file gathering.
- platform specific - avoid this logic whenever possible.
- Code as little platform specific logic within a makefile as possible, a conditional and compiler flags at most should be needed. For ex use defines within sources to shift platform logic into your source code.
- If a unit test is platform specific write your makefile so it can be used on all platforms but only do work on the specific hardware or class of hardware.
- For classes of hardware (unix/windows) place your makefile in a subdirectory, unix/Makefile.in
- Always include dependencies when creating a target
- Initial make call should always be the workhorse: build, generate, deploy, install, etc.
- All subsequent make calls must become a NOP unless sources or dependencies change or have been removed.
- Incorrect dependencies will contribute to wasted cycles and can contribute to circular dependencies.
- Directory dependencies
- Do not use directories as a dependency for generated targets, ever. Any activity within a directory will alter inodes forcing targets to always be stale.
- For ex, individual unit tests would invalidate all prior test activity whenever a test touched a timestamp file in the directory to signal success.
- Parallel make: add an explicit timestamp dependency (.done) that make can synchronize threaded calls on to avoid a race condition.
# Transient directory for storing timestamps
TS=.ts
#####################################################
## Extra dep needed to synchronize parallel execution
#####################################################
$(TS): $(TS)/.done
$(TS)/.done:
$(MKDIR) -p $(dir $@)
touch $@
# "clean" target
GARBAGE_DIRS += $(TS)
- Maintain clean targets - makefiles should be able to remove all content that is generated so "make clean" will return the sandbox/directory back to a clean state.
targets = foo bar tans
timestampDIR = .ts
all: $(timestampDIR) $(targets)
%: %.c
$(CC) -o $@ $<
$(timestampDIR):
$(MKDIR) $@
# "clean" target
GARBAGE += $(targets)
GARBAGE_DIRS += $(timestampDIR)
- Wrapper check/unit tests with a ENABLE_TESTS conditional so tests can be disabled on demand.
ifdef ENABLE_TESTS
ifeq ($(NULL),$(filter WINNT OS2,$(OS_ARCH)))
DIRS += test
endif # WIN
endif # ENABLE_TESTS