diff --git a/Makefile.include b/Makefile.include
index 8aef22e6c44217927070b4688a0c96eb7cbbf10c..ef6d9316e132c41e1a239e8c8b0bd20982271191 100644
--- a/Makefile.include
+++ b/Makefile.include
@@ -1,8 +1,6 @@
 # include Makefile.local if it exists
 -include Makefile.local
 
-all: link
-
 # set undefined variables
 RIOTBASE       ?= $(dir $(lastword $(MAKEFILE_LIST)))
 CCACHE_BASEDIR ?= $(RIOTBASE)
@@ -63,37 +61,35 @@ MAKEOVERRIDES += $(foreach v,${__DIRECTORY_VARIABLES},${v}=${${v}})
 # Path to the current directory relative to RIOTPROJECT
 BUILDRELPATH ?= ${PWD:${RIOTPROJECT}/%=%}/
 
+# get host operating system
+OS := $(shell uname)
+
 # Include Docker settings near the top because we need to build the environment
 # command line before some of the variable origins are overwritten below when
 # using abspath, strip etc.
 include $(RIOTMAKE)/docker.inc.mk
 
-# Static code analysis tools provided by LLVM
-include $(RIOTMAKE)/scan-build.inc.mk
+# include color echo macros
+include $(RIOTMAKE)/color.inc.mk
 
-export RIOTBUILD_CONFIG_HEADER_C = $(BINDIR)/riotbuild/riotbuild.h
+GLOBAL_GOALS := buildtest info-boards-supported info-boards-features-missing info-buildsizes info-buildsizes-diff
+ifneq (, $(filter $(GLOBAL_GOALS), $(MAKECMDGOALS)))
+  BOARD=none
+endif
 
-COLOR_GREEN  :=
-COLOR_RED    :=
-COLOR_PURPLE :=
-COLOR_RESET  :=
-COLOR_ECHO   := /bin/echo
+ifeq (none,$(BOARD))
+  include $(RIOTMAKE)/info-global.inc.mk
+  include $(RIOTMAKE)/buildtests.inc.mk
+else
 
-OS := $(shell uname)
+all: link
 
-ifeq (0,  $(shell tput colors 2>&1 > /dev/null; echo $$?))
-  COLOR_GREEN  := \033[1;32m
-  COLOR_RED    := \033[1;31m
-  COLOR_YELLOW := \033[1;33m
-  COLOR_PURPLE := \033[1;35m
-  COLOR_RESET  := \033[0m
-  ifeq ($(OS),Darwin)
-    COLOR_ECHO   := echo -e
-    SHELL=bash
-  else
-    COLOR_ECHO   := /bin/echo -e
-  endif
-endif
+include $(RIOTMAKE)/info.inc.mk
+
+# Static code analysis tools provided by LLVM
+include $(RIOTMAKE)/scan-build.inc.mk
+
+export RIOTBUILD_CONFIG_HEADER_C = $(BINDIR)/riotbuild/riotbuild.h
 
 ifeq ($(OS),Darwin)
   OPEN   := open
@@ -224,6 +220,10 @@ ifneq ($(GNRC_NETIF_NUMOF),1)
   CFLAGS += -DGNRC_NETIF_NUMOF=$(GNRC_NETIF_NUMOF)
 endif
 
+# process provided features
+include $(RIOTMAKE)/features.inc.mk
+
+# process dependencies
 include $(RIOTBASE)/Makefile.dep
 
 USEMODULE += $(filter-out $(DISABLE_MODULE), $(DEFAULT_MODULE))
@@ -433,12 +433,6 @@ $(CURDIR)/eclipsesym.xml:
 	$(Q)printf "%s\n" $(CC) $(CFLAGS_WITH_MACROS) $(INCLUDES) | \
 		$(RIOTBASE)/dist/tools/eclipsesym/cmdline2xml.sh > $@
 
-# Extra make goals for testing and comparing changes.
-include $(RIOTMAKE)/buildtests.inc.mk
-
-# process provided features
-include $(RIOTMAKE)/features.inc.mk
-
 # Export variables used throughout the whole make system:
 include $(RIOTMAKE)/vars.inc.mk
 
@@ -535,9 +529,6 @@ endif
 help:
 	@$(MAKE) -qp | sed -ne 's/\(^[a-z][a-z_-]*\):.*/\1/p' | sort | uniq
 
-info-modules:
-	@for i in $(sort $(USEMODULE)); do echo $$i; done
-
 ifneq (,$(filter iotlab-m3 wsn430-v1_3b wsn430-v1_4,$(BOARD)))
   ifneq (,$(filter iotlab-%,$(MAKECMDGOALS)))
     include $(RIOTBASE)/dist/testbed-support/Makefile.iotlab
@@ -575,3 +566,4 @@ CFLAGS += -include '$(RIOTBUILD_CONFIG_HEADER_C)'
 
 # include multislot support
 include $(RIOTMAKE)/multislot.mk
+endif # BOARD=none
diff --git a/makefiles/buildtests.inc.mk b/makefiles/buildtests.inc.mk
index 714528402ae5eab7b35da25787998cf8fa3b4b32..d8f901c81d4de13ab235c858c91aaeae6095f87e 100644
--- a/makefiles/buildtests.inc.mk
+++ b/makefiles/buildtests.inc.mk
@@ -1,311 +1,23 @@
-ifneq (, $(filter buildtest info-concurrency, $(MAKECMDGOALS)))
-  ifeq (, $(strip $(NPROC)))
-    # Linux (utility program)
-    NPROC := $(shell nproc 2>/dev/null)
-
-    ifeq (, $(strip $(NPROC)))
-      # Linux (generic)
-      NPROC := $(shell grep -c ^processor /proc/cpuinfo 2>/dev/null)
-    endif
-    ifeq (, $(strip $(NPROC)))
-      # BSD (at least FreeBSD and Mac OSX)
-      NPROC := $(shell sysctl -n hw.ncpu 2>/dev/null)
-    endif
-    ifeq (, $(strip $(NPROC)))
-      # Fallback
-      NPROC := 1
-    endif
-
-    NPROC := $(shell echo $$(($(NPROC) + 1)))
-
-    ifneq (, $(NPROC_MAX))
-      NPROC := $(shell if [ ${NPROC} -gt $(NPROC_MAX) ]; then echo $(NPROC_MAX); else echo ${NPROC}; fi)
-    endif
-    ifneq (, $(NPROC_MIN))
-      NPROC := $(shell if [ ${NPROC} -lt $(NPROC_MIN) ]; then echo $(NPROC_MIN); else echo ${NPROC}; fi)
-    endif
-  endif
-endif
-
-.PHONY: buildtest info-objsize info-buildsize info-buildsizes \
-        info-buildsizes-diff info-build info-boards-supported \
-        info-features-missing info-boards-features-missing
+.PHONY: buildtest
 
 ifeq ($(BUILD_IN_DOCKER),1)
 buildtest: ..in-docker-container
 else
 buildtest:
 	@ \
-	BUILDTESTOK=true; \
-	APP_RETRY=0; \
-	for BOARD in ${BOARDS}; do \
-	  RIOTNOLINK=$$(echo $(BOARD_INSUFFICIENT_MEMORY) | grep "\<$${BOARD}\>" 2>&1 >/dev/null && echo 1); \
-	  ${COLOR_ECHO} -n "Building for $${BOARD} "; \
-	  [ -n "$${RIOTNOLINK}" ] && ${COLOR_ECHO} -n "(no linking) "; \
-	  for NTH_TRY in 1 2 3; do \
-	    ${COLOR_ECHO} -n ".. "; \
-	    if [ "$$NTH_TRY" != "3" ]; then export _CCACHE=$$CCACHE; else export _CCACHE=""; fi ; \
-	    LOG=$$(env -i \
-	        HOME=$${HOME} \
-	        PATH=$${PATH} \
-	        BOARD=$${BOARD} \
-	        CCACHE=$${_CCACHE} \
-	        $${CCACHE_DIR:+CCACHE_DIR=$${CCACHE_DIR}} \
-	        $${GIT_CACHE_DIR:+GIT_CACHE_DIR=$${GIT_CACHE_DIR}} \
-	        CCACHE_BASEDIR=$${CCACHE_BASEDIR} \
-	        RIOTBASE=$${RIOTBASE} \
-	        RIOTBOARD=$${RIOTBOARD} \
-	        RIOTCPU=$${RIOTCPU} \
-	        RIOTPKG=$${RIOTPKG} \
-	        BINDIRBASE=$${BINDIRBASE} \
-	        RIOTNOLINK=$${RIOTNOLINK} \
-	        RIOT_VERSION=$${RIOT_VERSION} \
-	        WERROR=$${WERROR} \
-	        LTO=$${LTO} \
-	        TOOLCHAIN=$${TOOLCHAIN} \
-	        MIPS_ELF_ROOT=$${MIPS_ELF_ROOT} \
-	        $(MAKE) -j$(NPROC) clean all 2>&1) ; \
-	    if [ "$${?}" = "0" ]; then \
-	      ${COLOR_ECHO} "${COLOR_GREEN}success${COLOR_RESET}"; \
-	      if [ -n "$${BUILDTEST_VERBOSE}" ]; then \
-	        echo "$${LOG}" | tail -n +2 | head -n -2 | grep -v -E '^Building application|^\"make|^patching' | awk 'NF'; \
-	      fi; \
-	    elif [ -n "$${RIOT_DO_RETRY}" ] && [ "$${APP_RETRY}" -lt "3" ] && [ $${NTH_TRY} != 3 ]; then \
-	      ${COLOR_ECHO} -n "${COLOR_PURPLE}retrying${COLOR_RESET} "; \
-	      continue; \
-	    else \
-	      ${COLOR_ECHO} "${COLOR_RED}failed${COLOR_RESET}"; \
-	      if [ -n "$${BUILDTEST_VERBOSE}" ]; then \
-	        echo "$${LOG}" | grep -v -E '^\"make'; \
-	      fi; \
-	      APP_RETRY=`expr $${APP_RETRY} + 1`; \
-	      BUILDTESTOK=false; \
-	    fi; \
-	    break; \
-	  done; \
-	  env -i \
-	    HOME=$${HOME} \
-	    PATH=$${PATH} \
-	    BOARD=$${BOARD} \
-	    CCACHE=$${CCACHE} \
-	    $${CCACHE_DIR:+CCACHE_DIR=$${CCACHE_DIR}} \
-	    CCACHE_BASEDIR=$${CCACHE_BASEDIR} \
-	    $${GIT_CACHE_DIR:+GIT_CACHE_DIR=$${GIT_CACHE_DIR}} \
-	    RIOTBASE=$${RIOTBASE} \
-	    RIOTBOARD=$${RIOTBOARD} \
-	    RIOTCPU=$${RIOTCPU} \
-	    RIOTPKG=$${RIOTPKG} \
-	    BINDIRBASE=$${BINDIRBASE} \
-	    RIOTNOLINK=$${RIOTNOLINK} \
-	    RIOT_VERSION=$${RIOT_VERSION} \
-	    MIPS_ELF_ROOT=$${MIPS_ELF_ROOT} \
-	    $(MAKE) clean-intermediates 2>&1 >/dev/null || true; \
-	done; \
-	$${BUILDTESTOK}
+	RESULT=true ; \
+	for board in $(BOARDS); do \
+		${COLOR_ECHO} -n "Building for $$board ... " ; \
+		BOARD=$${board} RIOT_CI_BUILD=1 RIOT_VERSION_OVERRIDE=buildtest \
+			$(MAKE) clean all -j $(NPROC) >/dev/null 2>&1; \
+		RES=$$? ; \
+		if [ $$RES -eq 0 ]; then \
+			${COLOR_ECHO} "$(COLOR_GREEN)success.${COLOR_RESET}" ; \
+		else \
+			${COLOR_ECHO} "$(COLOR_RED)failed!${COLOR_RESET}" ; \
+			RESULT=false ; \
+		fi ; \
+		$(MAKE) clean-intermediates >/dev/null 2>&1 || true; \
+	done ; \
+	$${RESULT}
 endif # BUILD_IN_DOCKER
-
-info-objsize:
-	@case "${SORTROW}" in \
-	  text) SORTROW=1 ;; \
-	  data) SORTROW=2 ;; \
-	  bss) SORTROW=3 ;; \
-	  dec) SORTROW=4 ;; \
-	  "") SORTROW=4 ;; \
-	  *) echo "Usage: $(MAKE) info-objsize SORTROW=[text|data|bss|dec]" ; return ;; \
-	esac; \
-	echo -e '   text\t   data\t    bss\t    dec\t    hex\tfilename'; \
-	$(SIZE) -d -B $(BASELIBS) | \
-	  tail -n+2 | \
-	  sed -e 's#$(BINDIR)##' | \
-	  sort -rnk$${SORTROW}
-
-info-buildsize:
-	@$(SIZE) -d -B $(BINDIR)/$(APPLICATION).elf || echo ''
-
-info-buildsizes: SHELL=bash
-info-buildsizes:
-	@echo -e "   text\t   data\t    bss\t    dec\tboard"; \
-	for BOARD in ${BOARDS}; do \
-	  echo "$$(env -i \
-	    HOME=$${HOME} \
-	    PATH=$${PATH} \
-	    BOARD=$${BOARD} \
-	    RIOTBASE=$${RIOTBASE} \
-	    RIOTBOARD=$${RIOTBOARD} \
-	    RIOTCPU=$${RIOTCPU} \
-	    RIOTPKG=$${RIOTPKG} \
-	    BINDIRBASE=$${BINDIRBASE} \
-	    MIPS_ELF_ROOT=$${MIPS_ELF_ROOT} \
-	    $(MAKE) info-buildsize 2>/dev/null | tail -n-1 | cut -f-4)" "$${BOARD}"; \
-	done;
-
-info-buildsizes-diff: SHELL=bash
-info-buildsizes-diff:
-	@echo -e "text\tdata\tbss\tdec\tBOARD/BINDIRBASE\n"; \
-	for BOARD in ${BOARDS}; do \
-	  for BINDIRBASE in $${OLDBIN} $${NEWBIN}; do \
-	    env -i \
-	      HOME=$${HOME} \
-	      PATH=$${PATH} \
-	      BOARD=$${BOARD} \
-	      RIOTBASE=$${RIOTBASE} \
-	      RIOTBOARD=$${RIOTBOARD} \
-	      RIOTCPU=$${RIOTCPU} \
-	      RIOTPKG=$${RIOTPKG} \
-	      BINDIRBASE=$${BINDIRBASE} \
-	      MIPS_ELF_ROOT=$${MIPS_ELF_ROOT} \
-	      $(MAKE) info-buildsize 2>/dev/null | tail -n-1 | cut -f-4; \
-	  done | \
-	  while read -a OLD && read -a NEW; do \
-	    for I in 0 1 2 3; do \
-	      if [[ -n "$${NEW[I]}" && -n "$${OLD[I]}" ]]; then \
-	        DIFF=$$(($${NEW[I]} - $${OLD[I]})); \
-	        if [[ "$${DIFF}" -gt 0 ]]; then $(COLOR_ECHO) -n "${COLOR_RED}"; fi; \
-	        if [[ "$${DIFF}" -lt 0 ]]; then $(COLOR_ECHO) -n "${COLOR_GREEN}"; fi; \
-	      else \
-	        DIFF="${COLOR_RED}ERR"; \
-	      fi; \
-	      echo -ne "$${DIFF}\t${COLOR_RESET}"; \
-	    done; \
-	    echo "$${BOARD}"; \
-	    for I in 0 1 2 3; do echo -ne "$${OLD[I]-${COLOR_RED}ERR${COLOR_RESET}}\t"; done; echo -e "$${OLDBIN}"; \
-	    for I in 0 1 2 3; do echo -ne "$${NEW[I]-${COLOR_RED}ERR${COLOR_RESET}}\t"; done; echo -e "$${NEWBIN}\n"; \
-	  done; \
-	done;
-
-info-build:
-	@echo 'APPLICATION: $(APPLICATION)'
-	@echo ''
-	@echo 'supported boards:'
-	@$(foreach board,$(BOARDS),echo ' * $(board)';)
-	@echo ''
-	@echo 'BOARD:   $(BOARD)'
-	@echo 'CPU:     $(CPU)'
-	@echo 'MCU:     $(MCU)'
-	@echo ''
-	@echo 'RIOTBASE:  $(RIOTBASE)'
-	@echo 'RIOTBOARD: $(RIOTBOARD)'
-	@echo 'RIOTCPU:   $(RIOTCPU)'
-	@echo 'RIOTPKG:   $(RIOTPKG)'
-	@echo ''
-	@echo 'DEFAULT_MODULE: $(sort $(filter-out $(DISABLE_MODULE), $(DEFAULT_MODULE)))'
-	@echo 'DISABLE_MODULE: $(sort $(DISABLE_MODULE))'
-	@echo 'USEMODULE:      $(sort $(filter-out $(DEFAULT_MODULE), $(USEMODULE)))'
-	@echo ''
-	@echo 'ELFFILE: $(ELFFILE)'
-	@echo 'HEXFILE: $(HEXFILE)'
-	@echo ''
-	@echo 'FEATURES_REQUIRED (excl. optional features):'
-	@echo '         $(or $(sort $(filter-out $(FEATURES_OPTIONAL), $(FEATURES_REQUIRED))), -none-)'
-	@echo 'FEATURES_OPTIONAL (strictly "nice to have"):'
-	@echo '         $(or $(sort $(FEATURES_OPTIONAL)), -none-)'
-	@echo 'FEATURES_PROVIDED (by the board or USEMODULE'"'"'d drivers):'
-	@echo '         $(or $(sort $(FEATURES_PROVIDED)), -none-)'
-	@echo 'FEATURES_MISSING (incl. optional features):'
-	@echo '         $(or $(sort $(filter-out $(FEATURES_PROVIDED), $(FEATURES_REQUIRED))), -none-)'
-	@echo 'FEATURES_MISSING (only non-optional features):'
-	@echo '         $(or $(sort $(filter-out $(FEATURES_OPTIONAL) $(FEATURES_PROVIDED), $(FEATURES_REQUIRED))), -none-)'
-	@echo ''
-	@echo 'FEATURES_CONFLICT:     $(FEATURES_CONFLICT)'
-	@echo 'FEATURES_CONFLICT_MSG: $(FEATURES_CONFLICT_MSG)'
-	@echo ''
-	@echo 'CC:      $(CC)'
-	@echo -e 'CFLAGS:$(patsubst %, \n\t%, $(CFLAGS))'
-	@echo ''
-	@echo 'CXX:     $(CXX)'
-	@echo -e 'CXXUWFLAGS:$(patsubst %, \n\t%, $(CXXUWFLAGS))'
-	@echo -e 'CXXEXFLAGS:$(patsubst %, \n\t%, $(CXXEXFLAGS))'
-	@echo ''
-	@echo 'LINK:    $(LINK)'
-	@echo -e 'LINKFLAGS:$(patsubst %, \n\t%, $(LINKFLAGS))'
-	@echo ''
-	@echo 'OBJCOPY: $(OBJCOPY)'
-	@echo 'OFLAGS:  $(OFLAGS)'
-	@echo ''
-	@echo 'FLASHER: $(FLASHER)'
-	@echo 'FFLAGS:  $(FFLAGS)'
-	@echo ''
-	@echo 'TERMPROG:  $(TERMPROG)'
-	@echo 'TERMFLAGS: $(TERMFLAGS)'
-	@echo 'PORT:      $(PORT)'
-	@echo ''
-	@echo 'DEBUGGER:       $(DEBUGGER)'
-	@echo 'DEBUGGER_FLAGS: $(DEBUGGER_FLAGS)'
-	@echo
-	@echo 'DOWNLOAD_TO_FILE:   $(DOWNLOAD_TO_FILE)'
-	@echo 'DOWNLOAD_TO_STDOUT: $(DOWNLOAD_TO_STDOUT)'
-	@echo 'UNZIP_HERE:         $(UNZIP_HERE)'
-	@echo ''
-	@echo 'DEBUGSERVER:       $(DEBUGSERVER)'
-	@echo 'DEBUGSERVER_FLAGS: $(DEBUGSERVER_FLAGS)'
-	@echo ''
-	@echo 'RESET:       $(RESET)'
-	@echo 'RESET_FLAGS: $(RESET_FLAGS)'
-	@echo ''
-	@echo -e 'MAKEFILE_LIST:$(patsubst %, \n\t%, $(abspath $(MAKEFILE_LIST)))'
-
-info-boards-supported:
-	@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
-
-FEATURES_REQUIRED += $(FEATURES_OPTIONAL)
-
-ifneq (, $(filter buildtest info-boards-supported info-boards-features-missing info-build info-buildsizes info-buildsizes-diff, $(MAKECMDGOALS)))
-  FEATURES_PROVIDED_BAK := $(FEATURES_PROVIDED)
-
-  define board_missing_features
-    FEATURES_PROVIDED := $(FEATURES_PROVIDED_BAK)
-    -include $${RIOTBOARD}/${1}/Makefile.features
-    ifdef BUILDTEST_MCU_GROUP
-      ifneq ($(BUILDTEST_MCU_GROUP), $$(FEATURES_MCU_GROUP))
-        BOARDS_FEATURES_MISSING += "${1} $${BUILDTEST_MCU_GROUP}"
-        BOARDS_WITH_MISSING_FEATURES += ${1}
-      endif
-    endif
-
-    FEATURES_MISSING := $$(filter-out $$(FEATURES_PROVIDED), $$(FEATURES_REQUIRED))
-    ifneq (, $${FEATURES_MISSING})
-      BOARDS_FEATURES_MISSING += "${1} $${FEATURES_MISSING}"
-      ifneq (, $$(filter-out $$(FEATURES_OPTIONAL), $$(FEATURES_MISSING)))
-        BOARDS_WITH_MISSING_FEATURES += ${1}
-      endif
-    endif
-  endef
-
-  BOARDS ?= $(shell find $(RIOTBOARD)/* -maxdepth 0 -type d \! -name "*-common" -exec basename {} \;)
-  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)"
-
-info-files: QUIET := 0
-info-files:
-	@( \
-	  echo "$(abspath $(shell echo "$(MAKEFILE_LIST)"))" | tr ' ' '\n'; \
-	  CSRC="$$($(MAKE) USEPKG="" -Bn | grep -o -e "[^ ]\+\.[csS]$$" -e "[^ ]\+\.[csS][ \']" | grep -v -e "^\s*-D")"; \
-	  echo "$$CSRC"; \
-	  echo "$(RIOTBASE)/Makefile.base"; \
-	  echo "$$CSRC" | xargs dirname -- | sort | uniq | xargs -I{} find {} -name "Makefile*"; \
-	  echo "$$CSRC" | xargs $(CC) $(CFLAGS) $(INCLUDES) -MM 2> /dev/null | grep -o "[^ ]\+\.h"; \
-	  if [ -n "$$SRCXX" ]; then \
-	    CPPSRC="$$($(MAKE) -Bn USEPKG="" | grep -o -e "[^ ]\+\.cpp" | grep -v -e "^\s*-D")"; \
-	    echo "$$CPPSRC"; \
-	    echo "$$CPPSRC" | xargs dirname -- | sort | uniq | xargs -I{} find {} -name "Makefile*"; \
-	    echo "$$CPPSRC" | xargs $(CXX) $(CXXFLAGS) $(INCLUDES) -MM 2> /dev/null | grep -o "[^ ]\+\.h"; \
-	  fi; \
-	  $(foreach pkg,$(USEPKG),find $(RIOTPKG)/$(pkg) -type f;) \
-	) | sort | uniq | sed 's#$(RIOTBASE)/##'
diff --git a/makefiles/color.inc.mk b/makefiles/color.inc.mk
new file mode 100644
index 0000000000000000000000000000000000000000..7a7b1204a9167ebfc13d2ca066b548ec9fffa680
--- /dev/null
+++ b/makefiles/color.inc.mk
@@ -0,0 +1,19 @@
+COLOR_GREEN  :=
+COLOR_RED    :=
+COLOR_PURPLE :=
+COLOR_RESET  :=
+COLOR_ECHO   := /bin/echo
+
+ifeq (0,  $(shell tput colors 2>&1 > /dev/null; echo $$?))
+  COLOR_GREEN  := \033[1;32m
+  COLOR_RED    := \033[1;31m
+  COLOR_YELLOW := \033[1;33m
+  COLOR_PURPLE := \033[1;35m
+  COLOR_RESET  := \033[0m
+  ifeq ($(OS),Darwin)
+    COLOR_ECHO   := echo -e
+    SHELL=bash
+  else
+    COLOR_ECHO   := /bin/echo -e
+  endif
+endif
diff --git a/makefiles/info-global.inc.mk b/makefiles/info-global.inc.mk
new file mode 100644
index 0000000000000000000000000000000000000000..f250771a96fe6368deaa4398d5bb174fb632f6c2
--- /dev/null
+++ b/makefiles/info-global.inc.mk
@@ -0,0 +1,82 @@
+.PHONY: info-buildsizes info-buildsizes-diff info-features-missing \
+        info-boards-features-missing
+
+USEMODULE_GLOBAL := $(USEMODULE)
+USEPKG_GLOBAL := $(USEPKG)
+FEATURES_REQUIRED_GLOBAL := $(FEATURES_REQUIRED)
+FEATURES_OPTIONAL_GLOBAL := $(FEATURES_OPTIONAL)
+DISABLE_MODULE_GLOBAL := $(DISABLE_MODULE_GLOBAL)
+
+define board_missing_features
+  BOARD             := ${1}
+  USEMODULE         := $(USEMODULE_GLOBAL)
+  USEPKG            := $(USEPKG_GLOBAL)
+  DISABLE_MODULE    := $(DISABLE_MODULE_GLOBAL)
+  FEATURES_REQUIRED := $(FEATURES_REQUIRED_GLOBAL)
+  FEATURES_OPTIONAL := $(FEATURES_OPTIONAL_GLOBAL)
+  FEATURES_MISSING  :=
+  FEATURES_PROVIDED :=
+  include $${RIOTBOARD}/${1}/Makefile.features
+  ifdef BUILDTEST_MCU_GROUP
+    ifneq ($(BUILDTEST_MCU_GROUP), $$(FEATURES_MCU_GROUP))
+      BOARDS_FEATURES_MISSING += "${1} ${BUILDTEST_MCU_GROUP}"
+    BOARDS_WITH_MISSING_FEATURES += ${1}
+    endif
+  endif
+
+  include $(RIOTBASE)/Makefile.dep
+
+  FEATURES_MISSING := $$(filter-out $$(FEATURES_PROVIDED), $$(FEATURES_REQUIRED))
+  ifneq (, $${FEATURES_MISSING})
+    BOARDS_FEATURES_MISSING += "${1} $${FEATURES_MISSING}"
+    ifneq (, $$(filter-out $$(FEATURES_OPTIONAL), $$(FEATURES_MISSING)))
+      BOARDS_WITH_MISSING_FEATURES += ${1}
+    endif
+  endif
+endef
+
+BOARDS ?= $(shell find $(RIOTBOARD)/* -maxdepth 0 -type d \! -name "*-common" -exec basename {} \;)
+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))
+
+info-buildsizes: SHELL=bash
+info-buildsizes:
+	@echo -e "   text\t   data\t    bss\t    dec\tboard"; \
+	for board in ${BOARDS}; do \
+	    echo "$$(BOARD=$${board} $(MAKE) --no-print-directory info-buildsize 2>/dev/null | tail -n-1 | cut -f-4)" "$${board}"; \
+	done;
+
+info-buildsizes-diff: SHELL=bash
+info-buildsizes-diff:
+	@echo -e "text\tdata\tbss\tdec\tBOARD/BINDIRBASE\n"; \
+	for board in ${BOARDS}; do \
+	  for BINDIRBASE in $${OLDBIN} $${NEWBIN}; do \
+	      BOARD=$${board} $(MAKE) info-buildsize --no-print-directory 2>/dev/null | tail -n-1 | cut -f-4; \
+	  done | \
+	  while read -a OLD && read -a NEW; do \
+	    for I in 0 1 2 3; do \
+	      if [[ -n "$${NEW[I]}" && -n "$${OLD[I]}" ]]; then \
+	        DIFF=$$(($${NEW[I]} - $${OLD[I]})); \
+	        if [[ "$${DIFF}" -gt 0 ]]; then $(COLOR_ECHO) -n "${COLOR_RED}"; fi; \
+	        if [[ "$${DIFF}" -lt 0 ]]; then $(COLOR_ECHO) -n "${COLOR_GREEN}"; fi; \
+	      else \
+	        DIFF="${COLOR_RED}ERR"; \
+	      fi; \
+	      echo -ne "$${DIFF}\t${COLOR_RESET}"; \
+	    done; \
+	    echo "$${board}"; \
+	    for I in 0 1 2 3; do echo -ne "$${OLD[I]-${COLOR_RED}ERR${COLOR_RESET}}\t"; done; echo -e "$${OLDBIN}"; \
+	    for I in 0 1 2 3; do echo -ne "$${NEW[I]-${COLOR_RED}ERR${COLOR_RESET}}\t"; done; echo -e "$${NEWBIN}\n"; \
+	  done; \
+	done;
+
+info-boards-supported:
+	@echo $(BOARDS)
+
+info-boards-features-missing:
+	@for f in $(BOARDS_FEATURES_MISSING); do echo $${f}; done | column -t
diff --git a/makefiles/info.inc.mk b/makefiles/info.inc.mk
new file mode 100644
index 0000000000000000000000000000000000000000..997b7112c299dfc1042801258c6ff826983c9f41
--- /dev/null
+++ b/makefiles/info.inc.mk
@@ -0,0 +1,150 @@
+.PHONY: info-objsize info-buildsizes info-build info-boards-supported \
+        info-features-missing info-modules info-cpu
+
+info-objsize:
+	@case "${SORTROW}" in \
+	  text) SORTROW=1 ;; \
+	  data) SORTROW=2 ;; \
+	  bss) SORTROW=3 ;; \
+	  dec) SORTROW=4 ;; \
+	  "") SORTROW=4 ;; \
+	  *) echo "Usage: $(MAKE) info-objsize SORTROW=[text|data|bss|dec]" ; return ;; \
+	esac; \
+	echo -e '   text\t   data\t    bss\t    dec\t    hex\tfilename'; \
+	$(SIZE) -d -B $(BASELIBS) | \
+	  tail -n+2 | \
+	  sed -e 's#$(BINDIR)##' | \
+	  sort -rnk$${SORTROW}
+
+info-buildsize:
+	@$(SIZE) -d -B $(BINDIR)/$(APPLICATION).elf || echo ''
+
+info-build:
+	@echo 'APPLICATION: $(APPLICATION)'
+	@echo ''
+	@echo 'supported boards:'
+	@echo $$($(MAKE) info-boards-supported)
+	@echo ''
+	@echo 'BOARD:   $(BOARD)'
+	@echo 'CPU:     $(CPU)'
+	@echo 'MCU:     $(MCU)'
+	@echo ''
+	@echo 'RIOTBASE:  $(RIOTBASE)'
+	@echo 'RIOTBOARD: $(RIOTBOARD)'
+	@echo 'RIOTCPU:   $(RIOTCPU)'
+	@echo 'RIOTPKG:   $(RIOTPKG)'
+	@echo ''
+	@echo 'DEFAULT_MODULE: $(sort $(filter-out $(DISABLE_MODULE), $(DEFAULT_MODULE)))'
+	@echo 'DISABLE_MODULE: $(sort $(DISABLE_MODULE))'
+	@echo 'USEMODULE:      $(sort $(filter-out $(DEFAULT_MODULE), $(USEMODULE)))'
+	@echo ''
+	@echo 'ELFFILE: $(ELFFILE)'
+	@echo 'HEXFILE: $(HEXFILE)'
+	@echo ''
+	@echo 'FEATURES_REQUIRED (excl. optional features):'
+	@echo '         $(or $(sort $(filter-out $(FEATURES_OPTIONAL), $(FEATURES_REQUIRED))), -none-)'
+	@echo 'FEATURES_OPTIONAL (strictly "nice to have"):'
+	@echo '         $(or $(sort $(FEATURES_OPTIONAL)), -none-)'
+	@echo 'FEATURES_PROVIDED (by the board or USEMODULE'"'"'d drivers):'
+	@echo '         $(or $(sort $(FEATURES_PROVIDED)), -none-)'
+	@echo 'FEATURES_MISSING (incl. optional features):'
+	@echo '         $(or $(sort $(filter-out $(FEATURES_PROVIDED), $(FEATURES_REQUIRED))), -none-)'
+	@echo 'FEATURES_MISSING (only non-optional features):'
+	@echo '         $(or $(sort $(filter-out $(FEATURES_OPTIONAL) $(FEATURES_PROVIDED), $(FEATURES_REQUIRED))), -none-)'
+	@echo ''
+	@echo 'FEATURES_CONFLICT:     $(FEATURES_CONFLICT)'
+	@echo 'FEATURES_CONFLICT_MSG: $(FEATURES_CONFLICT_MSG)'
+	@echo ''
+	@echo 'CC:      $(CC)'
+	@echo -e 'CFLAGS:$(patsubst %, \n\t%, $(CFLAGS))'
+	@echo ''
+	@echo 'CXX:     $(CXX)'
+	@echo -e 'CXXUWFLAGS:$(patsubst %, \n\t%, $(CXXUWFLAGS))'
+	@echo -e 'CXXEXFLAGS:$(patsubst %, \n\t%, $(CXXEXFLAGS))'
+	@echo ''
+	@echo 'LINK:    $(LINK)'
+	@echo -e 'LINKFLAGS:$(patsubst %, \n\t%, $(LINKFLAGS))'
+	@echo ''
+	@echo 'OBJCOPY: $(OBJCOPY)'
+	@echo 'OFLAGS:  $(OFLAGS)'
+	@echo ''
+	@echo 'FLASHER: $(FLASHER)'
+	@echo 'FFLAGS:  $(FFLAGS)'
+	@echo ''
+	@echo 'TERMPROG:  $(TERMPROG)'
+	@echo 'TERMFLAGS: $(TERMFLAGS)'
+	@echo 'PORT:      $(PORT)'
+	@echo ''
+	@echo 'DEBUGGER:       $(DEBUGGER)'
+	@echo 'DEBUGGER_FLAGS: $(DEBUGGER_FLAGS)'
+	@echo
+	@echo 'DOWNLOAD_TO_FILE:   $(DOWNLOAD_TO_FILE)'
+	@echo 'DOWNLOAD_TO_STDOUT: $(DOWNLOAD_TO_STDOUT)'
+	@echo 'UNZIP_HERE:         $(UNZIP_HERE)'
+	@echo ''
+	@echo 'DEBUGSERVER:       $(DEBUGSERVER)'
+	@echo 'DEBUGSERVER_FLAGS: $(DEBUGSERVER_FLAGS)'
+	@echo ''
+	@echo 'RESET:       $(RESET)'
+	@echo 'RESET_FLAGS: $(RESET_FLAGS)'
+	@echo ''
+	@echo -e 'MAKEFILE_LIST:$(patsubst %, \n\t%, $(abspath $(MAKEFILE_LIST)))'
+
+ifneq (, $(filter buildtest info-concurrency, $(MAKECMDGOALS)))
+  ifeq (, $(strip $(NPROC)))
+    # Linux (utility program)
+    NPROC := $(shell nproc 2>/dev/null)
+
+    ifeq (, $(strip $(NPROC)))
+      # Linux (generic)
+      NPROC := $(shell grep -c ^processor /proc/cpuinfo 2>/dev/null)
+    endif
+    ifeq (, $(strip $(NPROC)))
+      # BSD (at least FreeBSD and Mac OSX)
+      NPROC := $(shell sysctl -n hw.ncpu 2>/dev/null)
+    endif
+    ifeq (, $(strip $(NPROC)))
+      # Fallback
+      NPROC := 1
+    endif
+
+    NPROC := $(shell echo $$(($(NPROC) + 1)))
+
+    ifneq (, $(NPROC_MAX))
+      NPROC := $(shell if [ ${NPROC} -gt $(NPROC_MAX) ]; then echo $(NPROC_MAX); else echo ${NPROC}; fi)
+    endif
+    ifneq (, $(NPROC_MIN))
+      NPROC := $(shell if [ ${NPROC} -lt $(NPROC_MIN) ]; then echo $(NPROC_MIN); else echo ${NPROC}; fi)
+    endif
+  endif
+endif
+
+info-concurrency:
+	@echo "$(NPROC)"
+
+info-files: QUIET := 0
+info-files:
+	@( \
+	  echo "$(abspath $(shell echo "$(MAKEFILE_LIST)"))" | tr ' ' '\n'; \
+	  CSRC="$$($(MAKE) USEPKG="" -Bn | grep -o -e "[^ ]\+\.[csS]$$" -e "[^ ]\+\.[csS][ \']" | grep -v -e "^\s*-D")"; \
+	  echo "$$CSRC"; \
+	  echo "$(RIOTBASE)/Makefile.base"; \
+	  echo "$$CSRC" | xargs dirname -- | sort | uniq | xargs -I{} find {} -name "Makefile*"; \
+	  echo "$$CSRC" | xargs $(CC) $(CFLAGS) $(INCLUDES) -MM 2> /dev/null | grep -o "[^ ]\+\.h"; \
+	  if [ -n "$$SRCXX" ]; then \
+	    CPPSRC="$$($(MAKE) -Bn USEPKG="" | grep -o -e "[^ ]\+\.cpp" | grep -v -e "^\s*-D")"; \
+	    echo "$$CPPSRC"; \
+	    echo "$$CPPSRC" | xargs dirname -- | sort | uniq | xargs -I{} find {} -name "Makefile*"; \
+	    echo "$$CPPSRC" | xargs $(CXX) $(CXXFLAGS) $(INCLUDES) -MM 2> /dev/null | grep -o "[^ ]\+\.h"; \
+	  fi; \
+	  $(foreach pkg,$(USEPKG),find $(RIOTPKG)/$(pkg) -type f;) \
+	) | sort | uniq | sed 's#$(RIOTBASE)/##'
+
+info-modules:
+	@for i in $(sort $(USEMODULE)); do echo $$i; done
+
+info-cpu:
+	@echo $(CPU)
+
+info-features-missing:
+	@echo $(filter-out $(FEATURES_PROVIDED), $(FEATURES_REQUIRED))