# Main makefile, alternative implementation to project.mk # Simplified, according to these design goals: # (1) no recursive make[1] # (2) all build targets and intermediates go into separate build # (3) one platform per make invokation (parameterized) # (4) collect all code in a single .a to avoid .a order problems # (5) a build can have multiple output targets, which all link against the main .a # (6) shun phony targets ("make clean" should be just "rm -rf build") # (7) allow a simple "list of modules" approach # Recursive make is not a good approach[1]. For multiple target # platforms, it is simpler to parameterize the makefile over the # target platform, instead of including multiple target rules in the # main makefile. Supporting simple individual target builts # [1] http://miller.emu.id.au/pmiller/books/rmch/ # Disable all implicit rules MAKEFLAGS += --no-builtin-rules .SUFFIXES: BUILD_ID := $(shell date +%Y%m%d-%H%M%S) .DELETE_ON_ERROR: # These are overridden in the Makefile generated by configure. SRC = $(shell readlink -f ..) BUILD = $(shell readlink -f .) TARGET = Linux LDFLAGS := CFLAGS := -g -O0 -Wall -std=gnu99 -fPIC # -Wno-deprecated-declarations CPPFLAGS := \ -I$(BUILD) \ -I$(SRC) \ -DBUILD_ID=\"$(BUILD_ID)\" \ -DTARGET=\"$(TARGET)\" \ -DPRIM_HOME=\"$(SRC)/\" \ -DHAVE_LEAF # To use the libprim build system with libprim source tree embedded in # a larger tree, this variable needs to be set. Note that $(SRC) then # refers to the larger source tree. -include $(SRC)/target/$(TARGET).mk # $(TARGET).mk can define LIBPRIM_SUBTREE, which allows libprim # extensions, re-using the libprim build system. LIBPRIM_SRC := $(SRC)/$(LIBPRIM_SUBTREE) LIBPRIM_BUILD := $(BUILD)/$(LIBPRIM_SUBTREE) CPPFLAGS += -I$(LIBPRIM_SRC) -I$(LIBPRIM_BUILD) GCC := $(TOOL_PREFIX)gcc AS := $(TOOL_PREFIX)as AR := $(TOOL_PREFIX)ar LD := $(TOOL_PREFIX)ld CC := $(GCC) MZSCHEME := mzscheme -S $(LIBPRIM_SRC)/rkt .PHONY: all all: g_OUT swig # Makefile template for the module.mk context. Once expanded, it # gathers module-specific data from the local m_ variables and # collects info in global g_ variables. Note that '$' varrefs are # expanded at template expansion-time, while '$$' varrefs survive as # '$' refs in the expanded code. define module_template m_C := m_O := m_D := m_H := m_ELF := m_TEST := m_SO := m_SRC := $(SRC)/$(1) m_BUILD := $(BUILD)/$(1) m_LDFLAGS := include $$(m_SRC)/module.mk g_C += $$(addprefix $$(m_SRC)/,$$(m_C)) g_O += $$(addprefix $$(m_BUILD)/,$$(m_C:.c=.o)) g_D += $$(addprefix $$(m_BUILD)/,$$(m_C:.c=.d)) g_H += $$(addprefix $$(m_BUILD)/,$$(m_H)) g_ELF += $$(addprefix $$(m_BUILD)/,$$(m_ELF)) g_TEST += $$(addprefix $$(m_BUILD)/,$$(m_TEST)) g_SO += $$(addprefix $$(m_BUILD)/,$$(m_SO)) g_LDFLAGS += $$(m_LDFLAGS) endef # Expand template for each module and include the dependency files. # Note that initialization of the g_ accumulators is necessary to turn # them into simply expanded variables, since the default is recursive # expanding variables. g_C := g_O := g_D := g_H := g_ELF := g_TEST := g_SO := g_LDFLAGS := g_MISC := $(foreach prog,$(MODULES),$(eval $(call module_template,$(prog)))) # g_D / g_O is only for the .o in lib.a g_OUT_D := $(g_ELF:.elf=.d) $(g_SO:.so=.d) $(g_TEST:.test=.d) g_OUT_O := $(g_OUT_D:.d=.o) g_ELF += $(g_TEST:.test=.elf) .PHONY: g_OUT g_OUT: $(g_ELF) $(g_SO) $(g_TEST) $(g_MISC) -include $(g_D) -include $(g_OUT_D) # This is necessary to allow .d files to be generated properly. GENERATED_H := $(g_H) $(BUILD)/config.h # All build rules are shared for the project. It is not worth the # complexity to have sub-project dependent build flags. If this is # necessary, abstract the subproject in a library dependency. # Remove the '@' character for more verbose compilation. # compile = @mkdir -p $(dir $(1)) ; echo [$(2)] $(notdir $(1)) ; $(3) compile = echo $(3); mkdir -p $(dir $(1)) ; echo [$(2)] $(notdir $(1)) ; $(3) # Gather dependencies from .c file depstx := sed -r 's,\s(\w+/), $(LIBPRIM_BUILD)/\1,g' $(g_D) $(g_OUT_D): $(BUILD)/%.d: $(SRC)/%.c $(GENERATED_H) $(call compile,$@,d,$(CC) $(CPPFLAGS) -M -MG -MT $(@:.d=.o) $< | $(depstx) >$@) _CC := $(CC) $(CPPFLAGS) $(CFLAGS) # Intermediate object $(g_O) $(g_OUT_O): $(BUILD)/%.o: $(SRC)/%.c $(BUILD)/%.d $(call compile,$@,o,$(_CC) -o $@ -c $<) # Executable $(g_ELF): $(BUILD)/%.elf: $(BUILD)/%.o $(BUILD)/lib.a $(call compile,$@,elf,$(_CC) $*.o $(BUILD)/lib.a $(g_LDFLAGS) -o $@) # Shared library. $(g_SO): $(BUILD)/%.so: $(BUILD)/%.o $(BUILD)/lib.a $(call compile,$@,so,$(_CC) $*.o $(BUILD)/lib.a $(g_LDFLAGS) -rdynamic -shared -o $@) # Archive all object files from sources listed in m_C variables. $(BUILD)/lib.a: $(g_O) $(call compile,$@,a,rm -f $@ ; $(AR) -r $@ $(g_O) 2>/dev/null) # Generated header files $(BUILD)/config.h: $(call compile,$@,h,echo '#include ' > $@) $(g_H): $(BUILD)/%.g.h: $(SRC)/%.c $(call compile,$@,h,$(MZSCHEME) $(dir $<)gen_prims.ss $< $@) # Preprocess only $(BUILD)/%.E.c: $(SRC)/%.c $(GENERATED_H) $(call compile,$@,c,$(CC) $(CPPFLAGS) -E $< -o $@) # Test $(g_TEST): $(BUILD)/%.test: $(BUILD)/%.elf $(call compile,$@,test,$(LIBPRIM_SRC)/bin/run_test $< $@) # Swig PYTHON_VER := 3.5 PYTHON_SO := $(BUILD)/swig/python/_libprim.so PYTHON_O := $(BUILD)/swig/python/_libprim.o PYTHON_C := $(BUILD)/swig/python/_libprim.c PYTHON_CFLAGS := $(shell pkg-config python-$(PYTHON_VER) --cflags) PYTHON_LIBS := $(shell pkg-config python-$(PYTHON_VER) --libs) $(PYTHON_C): $(SRC)/swig/libprim.i $(call compile,$@,i,cd $(SRC) ; swig -python -py3 -o $@ $<) $(PYTHON_O): $(PYTHON_C) $(call compile,$@,o,$(_CC) $(PYTHON_CFLAGS) -o $@ -c $<) $(PYTHON_SO): $(PYTHON_O) $(BUILD)/lib.a $(call compile,$@,so,$(_CC) $(PYTHON_O) $(BUILD)/lib.a $(g_LDFLAGS) $(PYTHON_LIBS) -rdynamic -shared -o $@) swig: $(PYTHON_SO) # Do not use .SECONDARY: enabled by default. # # While it useful to look at intermediate build resuilts, it also has # some odd behaviors. If you want to build an intermediate, build it # explicitly using absolute paths using: # # make vars.sh ; . vars.sh # make $PROJECT_DIR/ # # From [1]: "...one of the side effects of a target being declared # secondary is that make doesn't consider it out of date when it # doesn't exist." # # [1] http://www.mail-archive.com/bug-make@gnu.org/msg03942.html