From f49bd3e6608e7fdfffb8a196123259ce8acde4c3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ren=C3=A9=20Kijewski?= <rene.kijewski@fu-berlin.de>
Date: Mon, 29 Sep 2014 18:09:18 +0200
Subject: [PATCH] make: add Makefile.features telling the BOARDs' features

Please see #1715.
Closes #1715.

This PR implements the new Makefile variables "FEATURES_PROVIDED" and
"FEATURES_REQUIRED". A board *can* have a new file `Makefile.features`
which looks like:

```make
FEATURES_PROVIDED = transceiver
```

An application can have a corresponding line

```make
FEATURES_REQUIRED = transceiver
```

If the selected BOARD does not fulfil the requirements of the
application, then a *warning* is issued at compile time.

This change only includes the feature "transceiver", further features
are expected to be listed in further PRs. The requirement "transceiver"
is automatically added if the application uses the module
"defaulttransceiver".

`make buildtest` understands the new feature listing, so the user won't
need to add boards to `BOARD_BLACKLIST` manually.

Part of the change are the added Make targets
* `info-features-missing`, which prints the required features
  `\setminus` the provided features. The output is empty if there are no
  features missing.
* `info-boards-features-missing`, the same as `info-features-missing`
  but as a table for all boards, but heeded `BOARD_WHITELIST` and
  `BOARD_BLACKLIST`.

Applications don't have to use this new feature. This change does not
break existing Makefile.
---
 Makefile.buildtests                      | 50 ++++++++++++++++----
 Makefile.dep                             |  4 ++
 Makefile.include                         | 58 +++++++++++++++++-------
 boards/avsextrem/Makefile.features       |  1 +
 boards/chronos/Makefile.features         |  1 +
 boards/iot-lab_M3/Makefile.features      |  1 +
 boards/msb-430h/Makefile.features        |  1 +
 boards/msba2/Makefile.features           |  1 +
 boards/native/Makefile.features          |  1 +
 boards/pttu/Makefile.features            |  2 +
 boards/redbee-econotag/Makefile.features |  1 +
 boards/telosb/Makefile.features          |  1 +
 boards/wsn430-v1_3b/Makefile.features    |  1 +
 boards/wsn430-v1_4/Makefile.features     |  1 +
 boards/z1/Makefile.features              |  1 +
 examples/ccn-lite-client/Makefile        | 16 -------
 examples/ccn-lite-relay/Makefile         | 16 -------
 examples/rpl_udp/Makefile                | 17 +------
 tests/net_if/Makefile                    | 13 ------
 tests/pnet/Makefile                      | 15 ------
 20 files changed, 101 insertions(+), 101 deletions(-)
 create mode 100644 boards/avsextrem/Makefile.features
 create mode 100644 boards/chronos/Makefile.features
 create mode 100644 boards/iot-lab_M3/Makefile.features
 create mode 100644 boards/msb-430h/Makefile.features
 create mode 100644 boards/msba2/Makefile.features
 create mode 100644 boards/native/Makefile.features
 create mode 100644 boards/pttu/Makefile.features
 create mode 100644 boards/redbee-econotag/Makefile.features
 create mode 100644 boards/telosb/Makefile.features
 create mode 100644 boards/wsn430-v1_3b/Makefile.features
 create mode 100644 boards/wsn430-v1_4/Makefile.features
 create mode 100644 boards/z1/Makefile.features

diff --git a/Makefile.buildtests b/Makefile.buildtests
index 7dbc514759..1c161ef8ef 100644
--- a/Makefile.buildtests
+++ b/Makefile.buildtests
@@ -27,12 +27,9 @@ ifneq (, $(filter buildtest info-concurrency, $(MAKECMDGOALS)))
   endif
 endif
 
-BOARDS ?= $(shell find $(RIOTBOARD)/* -maxdepth 0 -type d \! -name *-common -printf '%f ')
-BOARDS := $(filter $(if $(BOARD_WHITELIST), $(BOARD_WHITELIST), %), $(BOARDS))
-BOARDS := $(filter-out $(BOARD_BLACKLIST), $(BOARDS))
-
 .PHONY: buildtest info-objsize info-buildsize info-buildsizes \
-        info-buildsizes-diff info-build info-boards-supported
+        info-buildsizes-diff info-build info-boards-supported \
+        info-features-missing info-boards-features-missing
 
 
 COLOR_GREEN  :=
@@ -54,7 +51,7 @@ buildtest:
 	@ \
 	BUILDTESTOK=true; \
 	rm -rf "$$BINDIRBASE"; \
-	for BOARD in $(BOARDS); do \
+	for BOARD in $$($(MAKE) -s info-boards-supported); do \
 		RIOTNOLINK=$$(case ' $(BOARD_INSUFFICIENT_RAM) ' in *" $${BOARD} "*) echo 1; esac); \
 		${COLOR_ECHO} -n "Building for $${BOARD} "; \
 		[ -n "$${RIOTNOLINK}" ] && ${COLOR_ECHO} -n "(no linking) "; \
@@ -107,7 +104,7 @@ info-buildsize:
 info-buildsizes: SHELL=bash
 info-buildsizes:
 	echo -e "   text\t   data\t    bss\t    dec\tboard"; \
-	for BOARD in $(BOARDS); do \
+	for BOARD in $$($(MAKE) -s info-boards-supported); do \
 		echo "$$(env -i \
 			HOME=$${HOME} \
 			PATH=$${PATH} \
@@ -122,7 +119,7 @@ info-buildsizes:
 info-buildsizes-diff: SHELL=bash
 info-buildsizes-diff:
 	echo -e "text\tdata\tbss\tdec\tBOARD/BINDIRBASE\n"; \
-	for BOARD in $(BOARDS); do \
+	for BOARD in $$($(MAKE) -s info-boards-supported); do \
 		for BINDIRBASE in $${OLDBIN} $${NEWBIN}; do \
 			env -i \
 				HOME=$${HOME} \
@@ -172,6 +169,9 @@ info-build:
 	@echo 'ELFFILE: $(ELFFILE)'
 	@echo 'HEXFILE: $(HEXFILE)'
 	@echo ''
+	@echo 'FEATURES_REQUIRED: $(sort $(FEATURES_REQUIRED))'
+	@echo 'FEATURES_PROVIDED: $(sort $(FEATURES_PROVIDED))'
+	@echo ''
 	@echo 'CC:      $(CC)'
 	@echo -e 'CFLAGS:$(patsubst %, \n\t%, $(CFLAGS))'
 	@echo ''
@@ -207,7 +207,39 @@ info-build:
 	@echo -e 'MAKEFILE_LIST:$(patsubst %, \n\t%, $(abspath $(MAKEFILE_LIST)))'
 
 info-boards-supported:
-	@echo "$(BOARDS)"
+	@echo $(BOARDS)
+
+info-features-missing:
+	@echo $(filter-out $(FEATURES_PROVIDED), $(FEATURES_REQUIRED))
+
+info-boards-features-missing:
+	@for f in $(BOARDS_FEATURES_MISSING); do echo $${f}; done | column -t
+
+ifneq (, $(filter info-boards-supported info-boards-features-missing info-build, $(MAKECMDGOALS)))
+  FEATURES_PROVIDED_BAK := $(FEATURES_PROVIDED)
+
+  define board_missing_features
+    FEATURES_PROVIDED :=
+    -include $${RIOTBOARD}/${1}/Makefile.features
+
+    FEATURES_MISSING := $$(filter-out $$(FEATURES_PROVIDED), $$(FEATURES_REQUIRED))
+    ifneq (, $${FEATURES_MISSING})
+      BOARDS_WITH_MISSING_FEATURES += ${1}
+      BOARDS_FEATURES_MISSING += "${1} $${FEATURES_MISSING}"
+    endif
+  endef
+
+  BOARDS ?= $(shell find $(RIOTBOARD)/* -maxdepth 0 -type d \! -name *-common -printf '%f ')
+  BOARDS := $(filter $(if $(BOARD_WHITELIST), $(BOARD_WHITELIST), %), $(BOARDS))
+  BOARDS := $(filter-out $(BOARD_BLACKLIST), $(BOARDS))
+
+  BOARDS_WITH_MISSING_FEATURES :=
+  BOARDS_FEATURES_MISSING :=
+  $(foreach BOARD, $(BOARDS), $(eval $(call board_missing_features,$(BOARD))))
+  BOARDS := $(filter-out $(BOARDS_WITH_MISSING_FEATURES), $(BOARDS))
+
+  FEATURES_PROVIDED := $(FEATURES_PROVIDED_BAK)
+endif
 
 info-concurrency:
 	@echo "$(NPROC)"
diff --git a/Makefile.dep b/Makefile.dep
index 706fe6f058..a8f7727818 100644
--- a/Makefile.dep
+++ b/Makefile.dep
@@ -107,3 +107,7 @@ endif
 ifneq (,$(filter libfixmath-unittests,$(USEMODULE)))
 	USEPKG += libfixmath
 endif
+
+ifneq (,$(filter defaulttransceiver,$(USEMODULE)))
+	FEATURES_REQUIRED += transceiver
+endif
diff --git a/Makefile.include b/Makefile.include
index 31cd74e76d..45f0e07c65 100644
--- a/Makefile.include
+++ b/Makefile.include
@@ -11,18 +11,6 @@ RIOTCPU := $(abspath $(RIOTCPU))
 RIOTBOARD ?= $(RIOTBASE)/boards
 RIOTBOARD := $(abspath $(RIOTBOARD))
 
-ifeq (,$(filter buildtest,$(MAKECMDGOALS)))
-	ifneq (,$(BOARD_WHITELIST))
-		ifeq (,$(filter $(BOARD),$(BOARD_WHITELIST)))
-$(error This application only runs on following boards: $(BOARD_WHITELIST))
-		endif
-	endif
-
-	ifneq (,$(filter $(BOARD),$(BOARD_BLACKLIST)))
-$(error This application does not run on following boards: $(BOARD_BLACKLIST))
-	endif
-endif
-
 BINDIRBASE ?= $(CURDIR)/bin
 BINDIR ?= $(abspath $(BINDIRBASE)/$(BOARD))/
 
@@ -89,6 +77,9 @@ ifeq ($(strip $(MCU)),)
 	MCU = $(CPU)
 endif
 
+# import list of provided features
+-include $(RIOTBOARD)/$(BOARD)/Makefile.features
+
 # if you want to publish the board into the sources as an uppercase #define
 BOARDDEF := $(shell echo $(BOARD) | tr 'a-z' 'A-Z' | tr '-' '_')
 CPUDEF := $(shell echo $(CPU) | tr 'a-z' 'A-Z' | tr '-' '_')
@@ -102,11 +93,6 @@ ifneq (0, $(shell mkdir -p $(BINDIR); $(AR) -rc $(BINDIR)empty-archive.a 2> /dev
 	AR := $(RIOTBASE)/dist/ar-wrapper $(AR)
 endif
 
-# Test if there where dependencies against a module in DISABLE_MODULE.
-ifneq (, $(filter $(DISABLE_MODULE), $(USEMODULE)))
-$(error "Required modules were disabled using DISABLE_MODULE: $(sort $(filter $(DISABLE_MODULE), $(USEMODULE)))")
-endif
-
 # Feature test default CFLAGS and LINKFLAGS for the set compiled.
 include $(RIOTBASE)/Makefile.cflags
 
@@ -217,3 +203,41 @@ include $(RIOTBASE)/Makefile.buildtests
 
 # Export variables used throughout the whole make system:
 include $(RIOTBASE)/Makefile.vars
+
+ifneq (, $(filter all, $(if $(MAKECMDGOALS), $(MAKECMDGOALS), all)))
+  EXPECT_ERRORS :=
+
+  # Test if there where dependencies against a module in DISABLE_MODULE.
+  ifneq (, $(filter $(DISABLE_MODULE), $(USEMODULE)))
+    $(shell $(COLOR_ECHO) "$(COLOR_RED)Required modules were disabled using DISABLE_MODULE:$(COLOR_RESET)"\
+                          "$(sort $(filter $(DISABLE_MODULE), $(USEMODULE)))" 1>&2)
+    EXPECT_ERRORS := 1
+  endif
+
+  # Test if all feature requirements were met by the selected board.
+  ifneq (, $(filter-out $(FEATURES_PROVIDED), $(FEATURES_REQUIRED)))
+    $(shell $(COLOR_ECHO) "$(COLOR_RED)There are unsatisfied feature requirements:$(COLOR_RESET)"\
+                          "$(filter-out $(FEATURES_PROVIDED), $(FEATURES_REQUIRED))" 1>&2)
+    EXPECT_ERRORS := 1
+  endif
+
+  # If there is a whitelist, then test if the board is whitelisted.
+  ifneq (, $(BOARD_WHITELIST))
+    ifeq (, $(filter $(BOARD_WHITELIST), $(BOARD)))
+      $(shell $(COLOR_ECHO) "$(COLOR_RED)The selected BOARD=${BOARD} is not whitelisted:$(COLOR_RESET) ${BOARD_WHITELIST}" 1>&2)
+      EXPECT_ERRORS := 1
+    endif
+  endif
+
+  # If there is a blacklist, then test if the board is blacklisted.
+  ifneq (, $(BOARD_BLACKLIST))
+    ifneq (, $(filter $(BOARD_BLACKLIST), $(BOARD)))
+      $(shell $(COLOR_ECHO) "$(COLOR_RED)The selected BOARD=${BOARD} is blacklisted:$(COLOR_RESET) ${BOARD_BLACKLIST}" 1>&2)
+      EXPECT_ERRORS := 1
+    endif
+  endif
+
+  ifneq (, $(EXPECT_ERRORS))
+    $(shell $(COLOR_ECHO) "\n\n$(COLOR_RED)EXPECT ERRORS!$(COLOR_RESET)\n\n" 1>&2)
+  endif
+endif
diff --git a/boards/avsextrem/Makefile.features b/boards/avsextrem/Makefile.features
new file mode 100644
index 0000000000..762734b956
--- /dev/null
+++ b/boards/avsextrem/Makefile.features
@@ -0,0 +1 @@
+FEATURES_PROVIDED = transceiver
diff --git a/boards/chronos/Makefile.features b/boards/chronos/Makefile.features
new file mode 100644
index 0000000000..762734b956
--- /dev/null
+++ b/boards/chronos/Makefile.features
@@ -0,0 +1 @@
+FEATURES_PROVIDED = transceiver
diff --git a/boards/iot-lab_M3/Makefile.features b/boards/iot-lab_M3/Makefile.features
new file mode 100644
index 0000000000..762734b956
--- /dev/null
+++ b/boards/iot-lab_M3/Makefile.features
@@ -0,0 +1 @@
+FEATURES_PROVIDED = transceiver
diff --git a/boards/msb-430h/Makefile.features b/boards/msb-430h/Makefile.features
new file mode 100644
index 0000000000..762734b956
--- /dev/null
+++ b/boards/msb-430h/Makefile.features
@@ -0,0 +1 @@
+FEATURES_PROVIDED = transceiver
diff --git a/boards/msba2/Makefile.features b/boards/msba2/Makefile.features
new file mode 100644
index 0000000000..762734b956
--- /dev/null
+++ b/boards/msba2/Makefile.features
@@ -0,0 +1 @@
+FEATURES_PROVIDED = transceiver
diff --git a/boards/native/Makefile.features b/boards/native/Makefile.features
new file mode 100644
index 0000000000..762734b956
--- /dev/null
+++ b/boards/native/Makefile.features
@@ -0,0 +1 @@
+FEATURES_PROVIDED = transceiver
diff --git a/boards/pttu/Makefile.features b/boards/pttu/Makefile.features
new file mode 100644
index 0000000000..bb7f2c751d
--- /dev/null
+++ b/boards/pttu/Makefile.features
@@ -0,0 +1,2 @@
+# Enable this after fixing https://github.com/RIOT-OS/RIOT/issues/659
+#FEATURES_PROVIDED = transceiver
diff --git a/boards/redbee-econotag/Makefile.features b/boards/redbee-econotag/Makefile.features
new file mode 100644
index 0000000000..762734b956
--- /dev/null
+++ b/boards/redbee-econotag/Makefile.features
@@ -0,0 +1 @@
+FEATURES_PROVIDED = transceiver
diff --git a/boards/telosb/Makefile.features b/boards/telosb/Makefile.features
new file mode 100644
index 0000000000..762734b956
--- /dev/null
+++ b/boards/telosb/Makefile.features
@@ -0,0 +1 @@
+FEATURES_PROVIDED = transceiver
diff --git a/boards/wsn430-v1_3b/Makefile.features b/boards/wsn430-v1_3b/Makefile.features
new file mode 100644
index 0000000000..762734b956
--- /dev/null
+++ b/boards/wsn430-v1_3b/Makefile.features
@@ -0,0 +1 @@
+FEATURES_PROVIDED = transceiver
diff --git a/boards/wsn430-v1_4/Makefile.features b/boards/wsn430-v1_4/Makefile.features
new file mode 100644
index 0000000000..762734b956
--- /dev/null
+++ b/boards/wsn430-v1_4/Makefile.features
@@ -0,0 +1 @@
+FEATURES_PROVIDED = transceiver
diff --git a/boards/z1/Makefile.features b/boards/z1/Makefile.features
new file mode 100644
index 0000000000..762734b956
--- /dev/null
+++ b/boards/z1/Makefile.features
@@ -0,0 +1 @@
+FEATURES_PROVIDED = transceiver
diff --git a/examples/ccn-lite-client/Makefile b/examples/ccn-lite-client/Makefile
index cf36ec9366..8439f360ab 100644
--- a/examples/ccn-lite-client/Makefile
+++ b/examples/ccn-lite-client/Makefile
@@ -28,22 +28,6 @@ CFLAGS += -DDEVELHELP
 QUIET ?= 1
 
 BOARD_INSUFFICIENT_RAM := chronos msb-430h telosb wsn430-v1_3b wsn430-v1_4 z1 redbee-econotag
-BOARD_BLACKLIST := arduino-due mbed_lpc1768 msb-430 pttu udoo qemu-i386 \
-                   stm32f0discovery stm32f3discovery stm32f4discovery pca10000 pca10005 \
-                   arduino-mega2560 msbiot yunjia-nrf51822 samr21-xpro
-# mbed_lpc1768:     see https://github.com/RIOT-OS/RIOT/issues/675
-# msb-430:          see https://github.com/RIOT-OS/RIOT/issues/658
-# pttu:             see https://github.com/RIOT-OS/RIOT/issues/659
-# qemu-i386:        no transceiver, yet
-# stm32f0discovery: no transceiver, yet
-# stm32f3discovery: no transceiver, yet
-# stm32f4discovery: no transceiver, yet
-# pca10000:         no transceiver, yet
-# pca10005:         no transceiver, yet
-# arduino-mega2560: no transceiver, yet
-# msbiot:           no transceiver, yet
-# yunjia-nrf51822:  no transceiver, yet
-# samr21-xpro:      no transceiver, yet
 
 # Modules to include:
 
diff --git a/examples/ccn-lite-relay/Makefile b/examples/ccn-lite-relay/Makefile
index fc250010e0..fbb279a0e7 100644
--- a/examples/ccn-lite-relay/Makefile
+++ b/examples/ccn-lite-relay/Makefile
@@ -28,22 +28,6 @@ CFLAGS += -DDEVELHELP
 QUIET ?= 1
 
 BOARD_INSUFFICIENT_RAM := chronos msb-430h telosb wsn430-v1_3b wsn430-v1_4 z1 redbee-econotag
-BOARD_BLACKLIST := arduino-due mbed_lpc1768 msb-430 pttu udoo qemu-i386 \
-                   stm32f0discovery stm32f3discovery stm32f4discovery \
-                   pca10000 pca10005 arduino-mega2560 msbiot yunjia-nrf51822 \
-                   samr21-xpro
-# mbed_lpc1768:     see https://github.com/RIOT-OS/RIOT/issues/675
-# msb-430:          see https://github.com/RIOT-OS/RIOT/issues/658
-# pttu:             see https://github.com/RIOT-OS/RIOT/issues/659
-# qemu-i386:        no transceiver, yet
-# stm32f0discovery: no transceiver, yet
-# stm32f3discovery: no transceiver, yet
-# stm32f4discovery: no transceiver, yet
-# pca10000/5:       no transceiver, yet
-# arduino-mega2560: no transceiver, yet
-# msbiot:           no transceiver, yet
-# yunjia-nrf51822:  no transceiver, yet
-# samr21-xpro:      no transceiver, yet
 
 # Modules to include:
 
diff --git a/examples/rpl_udp/Makefile b/examples/rpl_udp/Makefile
index 7499ac9183..a34484c4be 100644
--- a/examples/rpl_udp/Makefile
+++ b/examples/rpl_udp/Makefile
@@ -35,22 +35,9 @@ ifeq ($(shell $(CC) -Wno-cpp -E - 2>/dev/null >/dev/null dev/null ; echo $$?),0)
 endif
 
 BOARD_INSUFFICIENT_RAM := chronos msb-430h redbee-econotag telosb wsn430-v1_3b wsn430-v1_4 z1
-BOARD_BLACKLIST := arduino-due mbed_lpc1768 msb-430 pttu udoo qemu-i386 stm32f0discovery \
-                   stm32f3discovery stm32f4discovery pca10000 pca10005 arduino-mega2560 \
-                   msbiot yunjia-nrf51822 samr21-xpro
-# mbed_lpc1768:     see https://github.com/RIOT-OS/RIOT/issues/675
-# msb-430:          see https://github.com/RIOT-OS/RIOT/issues/658
-# pttu:             see https://github.com/RIOT-OS/RIOT/issues/659
-# qemu-i386:        no transceiver, yet
-# stm32f0discovery: no transceiver, yet
-# stm32f3discovery: no transceiver, yet
-# stm32f4discovery: no transceiver, yet
-# pca10000:         no transceiver, yet
-# pca10005:         no transceiver, yet
+
 # arduino-mega2560: time.h missing from avr-libc
-# msbiot:           no transceiver, yet
-# yunjia-nrf51822:  no transceiver, yet
-# samr21-xpro:	  	no transceiver, yet
+BOARD_BLACKLIST := arduino-mega2560
 
 # Modules to include:
 
diff --git a/tests/net_if/Makefile b/tests/net_if/Makefile
index 3921de0a40..c8020cd321 100644
--- a/tests/net_if/Makefile
+++ b/tests/net_if/Makefile
@@ -1,18 +1,5 @@
 APPLICATION = net_if
 
-BOARD_BLACKLIST = mbed_lpc1768 arduino-due udoo qemu-i386 stm32f0discovery stm32f3discovery \
-                  stm32f4discovery pca10000 pca10005 arduino-mega2560 msbiot yunjia-nrf51822 \
-                  samr21-xpro
-# qemu-i386:        no transceiver, yet
-# stm32f0discovery: no transceiver, yet
-# stm32f3discovery: no transceiver, yet
-# stm32f4discovery: no transceiver, yet
-# pca10000:         no transceiver, yet
-# pca10005:         no transceiver, yet
-# msbiot:           no transceiver, yet
-# yunjia-nrf51822: 	no transceiver, yet
-# samr21-xpro: 	    no transceiver, yet
-
 include ../Makefile.tests_common
 
 ifeq ($(BOARD),stm32f4discovery)
diff --git a/tests/pnet/Makefile b/tests/pnet/Makefile
index 856b098b62..07d95d9509 100644
--- a/tests/pnet/Makefile
+++ b/tests/pnet/Makefile
@@ -2,21 +2,6 @@ APPLICATION = pnet
 include ../Makefile.tests_common
 
 BOARD_INSUFFICIENT_RAM := chronos msb-430h redbee-econotag telosb wsn430-v1_3b wsn430-v1_4 z1
-BOARD_BLACKLIST := arduino-due mbed_lpc1768 msb-430 udoo qemu-i386 stm32f0discovery \
-                   stm32f3discovery stm32f4discovery pca10000 pca10005 arduino-mega2560 \
-                   msbiot yunjia-nrf51822 samr21-xpro
-# mbed_lpc1768:     see https://github.com/RIOT-OS/RIOT/issues/675
-# msb-430:          see https://github.com/RIOT-OS/RIOT/issues/658
-# qemu-i386:        no transceiver, yet
-# stm32f0discovery: no transceiver, yet
-# stm32f3discovery: no transceiver, yet
-# stm32f4discovery: no transceiver, yet
-# pca10000:         no transceiver, yet
-# pca10005:         no transceiver, yet
-# arduino-mega2560:  unknown type name ‘radio_packet_length_t’
-# msbiot:           no transceiver, yet
-# yunjia-nrf51822:  no transceiver, yet
-# yunjia-nrf51822: 	no transceiver, yet
 
 USEMODULE += posix
 USEMODULE += pnet
-- 
GitLab