From 35e74ad7251678a0b0f527ede8ca6425d507e0cf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ren=C3=A9=20Kijewski?= <rene.kijewski@fu-berlin.de>
Date: Wed, 18 Jun 2014 11:00:33 +0200
Subject: [PATCH] make: refactor make system (parallelism, deduplication)

Almost everything was build sequentially in RIOT, because we employed
explicit for-loops to build directories (DIRS). This PR makes our make
system use normal dependencies to build directories.

All our compiling rules were duplicated, once for the application, once
for modules. This PR makes the application a normal module, removing
this duplication.
---
 Makefile             | 30 +++++-------------------------
 Makefile.application | 13 +++++++++++++
 Makefile.base        | 20 +++++++++++++++-----
 Makefile.include     | 30 ++++++++----------------------
 4 files changed, 41 insertions(+), 52 deletions(-)
 create mode 100644 Makefile.application

diff --git a/Makefile b/Makefile
index ec9bc9d31a..0df2757190 100644
--- a/Makefile
+++ b/Makefile
@@ -1,30 +1,10 @@
-ifeq (, $(__RIOTBUILD_FLAG))
-  all: welcome
-	@echo ""
-	@exit 1
-else
-  all:
-	mkdir -p $(BINDIR)
-	@for i in $(DIRS) ; do "$(MAKE)" -C $$i || exit 1; done ;
-endif
-
-DIRS = $(RIOTCPU)/$(CPU) core drivers sys
-
-ifneq (,$(filter embunit,$(USEMODULE)))
-	DIRS += tests/unittests/embunit/embUnit
-endif
+.all:
 
-ifneq (,$(filter embunit_textui,$(USEMODULE)))
-	DIRS += tests/unittests/embunit/textui
-endif
+.PHONY: all doc docclean welcome
 
-.PHONY: all clean doc docclean welcome
-
-clean:
-	@for i in $(DIRS) ; do "$(MAKE)" -C $$i clean || exit 1; done ;
-	-@if [ -d $(BINDIR) ] ; \
-	then rm -rf $(BINDIR) ; \
-	fi
+all: welcome
+	@echo ""
+	@exit 1
 
 doc:
 	"$(MAKE)" -BC doc/doxygen
diff --git a/Makefile.application b/Makefile.application
new file mode 100644
index 0000000000..5f1e1ae589
--- /dev/null
+++ b/Makefile.application
@@ -0,0 +1,13 @@
+MODULE = $(APPLICATION)
+
+DIRS += $(RIOTCPU)/$(CPU) $(RIOTBOARD)/$(BOARD)
+DIRS += $(RIOTBASE)/core $(RIOTBASE)/drivers $(RIOTBASE)/sys
+
+ifneq (,$(filter embunit,$(USEMODULE)))
+  DIRS += $(RIOTBASE)/tests/unittests/embunit/embUnit
+endif
+ifneq (,$(filter embunit_textui,$(USEMODULE)))
+  DIRS += $(RIOTBASE)/tests/unittests/embunit/textui
+endif
+
+include $(RIOTBASE)/Makefile.base
diff --git a/Makefile.base b/Makefile.base
index db9c68b9da..c2d547327f 100644
--- a/Makefile.base
+++ b/Makefile.base
@@ -4,11 +4,20 @@ endif
 
 MODULE ?= $(shell basename $(CURDIR))
 
-all: $(BINDIR)$(MODULE).a
-	@for i in $(DIRS); do $(MAKE) -C $$i || exit 1; done;
+.PHONY: all ${DIRS:%=ALL--%} ${DIRS:%=CLEAN--%}
 
-clean::
-	@for i in $(DIRS); do $(MAKE) -C $$i clean; done;
+all: $(BINDIR)$(MODULE).a ..nothing
+
+..nothing:
+	@:
+
+clean:: ${DIRS:%=CLEAN--%}
+
+${DIRS:%=ALL--%}:
+	"$(MAKE)" -C ${@:ALL--%=%}
+
+${DIRS:%=CLEAN--%}:
+	"$(MAKE)" -C ${@:CLEAN--%=%} clean
 
 ASMSRC = $(wildcard *.s)
 ASSMSRC = $(wildcard *.S)
@@ -21,7 +30,8 @@ endif
 OBJ = $(SRC:%.c=$(BINDIR)$(MODULE)/%.o)
 DEP = $(SRC:%.c=$(BINDIR)$(MODULE)/%.d)
 
-$(BINDIR)$(MODULE).a: $(OBJ) $(ASMOBJ)
+$(BINDIR)$(MODULE).a: $(OBJ) $(ASMOBJ) ${DIRS:%=ALL--%}
+	@mkdir -p $(BINDIR)$(MODULE)
 	$(AD)$(AR) -rc $(BINDIR)$(MODULE).a $(OBJ) $(ASMOBJ)
 
 # pull in dependency info for *existing* .o files
diff --git a/Makefile.include b/Makefile.include
index 067d1e0456..284d8bf525 100644
--- a/Makefile.include
+++ b/Makefile.include
@@ -1,4 +1,4 @@
-# Provide a shallow sanity check. You cannot call `make` in the root directory.
+# Provide a shallow sanity check. You cannot call `make` in a module directory.
 export __RIOTBUILD_FLAG := RIOT
 
 # set undefined variables
@@ -33,12 +33,14 @@ CPUDEF = $(shell echo $(CPU)|tr 'a-z' 'A-Z'|tr '-' '_')
 CFLAGS += -DBOARD_$(BB) -DCPU_$(CPUDEF)
 
 export CFLAGS
+export APPLICATION
 
 export BINDIRBASE ?= $(CURDIR)/bin
 export BINDIR ?= $(abspath $(BINDIRBASE)/$(BOARD))/
 
 ifeq ($(QUIET),1)
 	AD=@
+	MAKEFLAGS += --no-print-directory
 else
 	AD=
 endif
@@ -84,10 +86,8 @@ export ELFFILE ?= $(BINDIR)$(APPLICATION).elf
 export HEXFILE ?= $(ELFFILE:.elf=.hex)
 
 ## make script for your application. Build RIOT-base here!
-all: $(BINDIR)$(APPLICATION).a
-	@echo "Building application $(APPLICATION) for $(BOARD) w/ MCU $(MCU)."
-	"$(MAKE)" -C $(RIOTBOARD)/$(BOARD)
-	"$(MAKE)" -C $(RIOTBASE)
+all: ..build-message $(USEPKG:%=${BINDIR}%.a) $(APPDEPS)
+	"$(MAKE)" -C $(CURDIR) -f $(RIOTBASE)/Makefile.application
 ifeq (,$(RIOTNOLINK))
 ifeq ($(BUILDOSXNATIVE),1)
 	$(AD)$(LINK) $(UNDEF) -o $(ELFFILE) $(BASELIBS) $(LINKFLAGS) -Wl,-no_pie
@@ -98,14 +98,8 @@ endif
 	$(AD)$(OBJCOPY) $(OFLAGS) $(ELFFILE) $(HEXFILE)
 endif
 
-# string array of all names of c files in dir
-SRC = $(wildcard *.c)
-
-# string array of all names replaced .c with .o
-OBJ = $(SRC:%.c=${BINDIR}${APPLICATION}/%.o)
-
-$(BINDIR)$(APPLICATION).a: $(OBJ)
-	$(AD)$(AR) -rc $(BINDIR)$(APPLICATION).a $(OBJ)
+..build-message:
+	@echo "Building application $(APPLICATION) for $(BOARD) w/ MCU $(MCU)."
 
 # add extra include paths for packages in $(USEMODULE)
 export USEMODULE_INCLUDES =
@@ -119,7 +113,7 @@ INCLUDES += $(USEMODULE_INCLUDES_:%=-I%)
 
 # The `clean` needs to be serialized before everything else.
 ifneq (, $(filter clean, $(MAKECMDGOALS)))
-    $(OBJ) $(BASELIBS) $(USEPKG:%=$(RIOTBASE)/pkg/%/Makefile.include): clean
+    all $(BASELIBS) $(USEPKG:%=$(RIOTBASE)/pkg/%/Makefile.include): clean
 endif
 
 # include Makefile.includes for packages in $(USEPKG)
@@ -130,14 +124,6 @@ $(RIOTBASE)/pkg/%/Makefile.include::
 
 -include $(USEPKG:%=$(RIOTBASE)/pkg/%/Makefile.include)
 
-# pull in dependency info for *existing* .o files
--include $(OBJ:.o=.d)
-
-$(BINDIR)$(APPLICATION)/%.o: %.c $(APPDEPS) $(USEPKG:%=${BINDIR}%.a)
-	@echo; echo "Compiling.... $*.c"; echo
-	$(AD)mkdir -p "$(dir $@)"
-	$(AD)$(CC) $(CFLAGS) $(INCLUDES) -c "$<" -o "$@"
-
 $(USEPKG:%=${BINDIR}%.a):
 	@mkdir -p ${BINDIR}
 	"$(MAKE)" -C $(RIOTBASE)/pkg/$(patsubst ${BINDIR}%.a,%,$@)
-- 
GitLab