diff --git a/Makefile.docker b/Makefile.docker index 1ee2657a9728cf6c9c44e3c1601bd7655a7b2997..464e1dff2f4a9ff1b546cde78c47c3a563f53501 100644 --- a/Makefile.docker +++ b/Makefile.docker @@ -5,44 +5,57 @@ export DOCKER_FLAGS ?= --rm export DOCKER_MAKECMDGOALS_POSSIBLE = \ all \ buildtest \ + scan-build \ + scan-build-analyze \ # export DOCKER_MAKECMDGOALS = $(filter $(MAKECMDGOALS),$(DOCKER_MAKECMDGOALS_POSSIBLE)) +# Docker creates the files .dockerinit and .dockerenv in the root directory of +# the container, we check for the files to determine if we are inside a container. +ifneq (,$(wildcard /.dockerinit /.dockerenv)) + export INSIDE_DOCKER := 1 +else + export INSIDE_DOCKER := 0 +endif + # Default target for building inside a Docker container if nothing was given export DOCKER_MAKECMDGOALS ?= all # List of all exported environment variables that shall be passed on to the # Docker container, they will only be passed if they are set from the # environment, not if they are only default Makefile values. export DOCKER_ENV_VARS = \ - BINDIRBASE \ - BOARD \ - QUIET \ - RIOT_VERSION \ APPDIR \ + AR \ + ARFLAGS \ + AS \ + ASFLAGS \ BINDIR \ + BINDIRBASE \ + BOARD \ BUILDRELPATH \ - ELFFILE \ - HEXFILE \ - LINKFLAGPREFIX \ - CPPMIX \ - PREFIX \ + BUILDTEST_MCU_GROUP \ + BUILDTEST_VERBOSE \ CC \ - CXX \ CFLAGS \ - CXXUWFLAGS \ + CPPMIX \ + CXX \ CXXEXFLAGS \ - AR \ - ARFLAGS \ - AS \ - ASFLAGS \ + CXXUWFLAGS \ + ELFFILE \ + HEXFILE \ LINK \ + LINKFLAGPREFIX \ LINKFLAGS \ OBJCOPY \ OFLAGS \ + PREFIX \ + QUIET \ + RIOT_VERSION \ + SCANBUILD_ARGS \ + SCANBUILD_OUTPUTDIR \ SIZE \ + TOOLCHAIN \ UNDEF \ - BUILDTEST_MCU_GROUP \ - BUILDTEST_VERBOSE \ # # Find which variables were set using the command line or the environment and @@ -51,9 +64,9 @@ export DOCKER_ENV_VARS = \ # of the environment variables will be overwritten by Makefile.include and their # origin is changed to "file" DOCKER_ENVIRONMENT_CMDLINE := $(foreach varname,$(DOCKER_ENV_VARS), \ - $(if $(filter environment command,$(origin $(varname))), \ - -e '$(varname)=$($(varname))', \ - )) + $(if $(filter environment command,$(origin $(varname))), \ + -e '$(varname)=$(subst ','\'',$($(varname)))', \ + )) DOCKER_ENVIRONMENT_CMDLINE := $(strip $(DOCKER_ENVIRONMENT_CMDLINE)) # This will execute `make $(DOCKER_MAKECMDGOALS)` inside a Docker container. @@ -70,6 +83,7 @@ DOCKER_ENVIRONMENT_CMDLINE := $(strip $(DOCKER_ENVIRONMENT_CMDLINE)) -v '$(RIOTCPU):$(DOCKER_BUILD_ROOT)/riotcpu' \ -v '$(RIOTBOARD):$(DOCKER_BUILD_ROOT)/riotboard' \ -v '$(RIOTPROJECT):$(DOCKER_BUILD_ROOT)/riotproject' \ + -v /etc/localtime:/etc/localtime:ro \ -e 'RIOTBASE=$(DOCKER_BUILD_ROOT)/riotbase' \ -e 'RIOTCPU=$(DOCKER_BUILD_ROOT)/riotcpu' \ -e 'RIOTBOARD=$(DOCKER_BUILD_ROOT)/riotboard' \ diff --git a/Makefile.include b/Makefile.include index 8b253f64c811ef26822681ed702778240b352259..dcf05902b9ca36a060b8d6d9da26db80b808f66b 100644 --- a/Makefile.include +++ b/Makefile.include @@ -18,6 +18,9 @@ RIOTPROJECT := $(abspath $(RIOTPROJECT)) # using abspath, strip etc. include $(RIOTBASE)/Makefile.docker +# Static code analysis tools provided by LLVM +include $(RIOTBASE)/Makefile.scan-build + # Path to the current directory relative to the git root BUILDRELPATH ?= $(shell git rev-parse --show-prefix) @@ -54,6 +57,12 @@ ifeq (, ${JENKINS_URL}) endif endif +ifeq ($(OS),Darwin) + OPEN := open +else + OPEN := xdg-open +endif + ifeq ($(QUIET),1) AD=@ MAKEFLAGS += --no-print-directory diff --git a/Makefile.scan-build b/Makefile.scan-build new file mode 100644 index 0000000000000000000000000000000000000000..5137d05a2ca90c672537e9243d69d93901ea9803 --- /dev/null +++ b/Makefile.scan-build @@ -0,0 +1,91 @@ +SCANBUILD_ENV_VARS := \ + APPDIR \ + AR \ + ARFLAGS \ + AS \ + ASFLAGS \ + BINDIR \ + BINDIRBASE \ + BOARD \ + BUILDRELPATH \ + CC \ + CFLAGS \ + CPPMIX \ + CXX \ + CXXEXFLAGS \ + CXXUWFLAGS \ + ELFFILE \ + HEXFILE \ + HOME \ + LINK \ + LINKFLAGPREFIX \ + LINKFLAGS \ + OBJCOPY \ + OFLAGS \ + PATH \ + PREFIX \ + QUIET \ + RIOT_VERSION \ + SIZE \ + TOOLCHAIN \ + UNDEF \ + USER \ + # + +SCANBUILD_ARGS ?= \ + -analyze-headers \ + --use-cc=$(CC) \ + --use-c++=$(CXX) \ + -analyzer-config stable-report-filename=true \ + # + +export SCANBUILD_OUTPUTDIR = $(CURDIR)/scan-build/ + +# Find all variables given on the command line and recreate the command. +CMDVARS := $(strip $(foreach varname, $(SCANBUILD_ENV_VARS), \ + $(if $(filter command, $(origin $(varname))), \ + '$(varname)=$(subst ','\'',$($(varname)))', \ + ))) +ENVVARS := $(strip $(foreach varname, $(SCANBUILD_ENV_VARS), \ + $(if $(filter environment, $(origin $(varname))), \ + '$(varname)=$(subst ','\'',$($(varname)))', \ + ))) + +.PHONY: scan-build scan-build-analyze scan-build-view +scan-build: scan-build-view scan-build-analyze +scan-build-view: scan-build-analyze +ifeq ($(BUILD_IN_DOCKER),1) +scan-build-analyze: ..in-docker-container +else # BUILD_IN_DOCKER +scan-build-analyze: clean + @$(COLOR_ECHO) '$(COLOR_GREEN)Performing Clang static code analysis using toolchain "$(TOOLCHAIN)".$(COLOR_RESET)' +# ccc-analyzer needs to be told the proper -target setting for best results, +# otherwise false error reports about unknown register names etc will be produced. +# These kinds of errors can be safely ignored as long as they only come from LLVM + @if [ "$${TOOLCHAIN}" != "llvm" -a "$${BOARD}" != "native" ]; then \ + $(COLOR_ECHO) '$(COLOR_YELLOW)Recommend using TOOLCHAIN=llvm for best results.$(COLOR_RESET)'; \ + $(COLOR_ECHO) '$(COLOR_YELLOW)Ignore any "error: unknown register name '\''rX'\'' in asm" messages.$(COLOR_RESET)'; \ + fi + $(AD)mkdir -p '$(SCANBUILD_OUTPUTDIR)' + $(AD)env -i $(ENVVARS) \ + scan-build -o '$(SCANBUILD_OUTPUTDIR)' $(SCANBUILD_ARGS) \ + make -C $(CURDIR) all $(strip $(CMDVARS)); +endif # BUILD_IN_DOCKER + +ifeq (1,$(INSIDE_DOCKER)) +scan-build-view: + @ +else + @echo "Showing most recent report in your web browser..." + @REPORT_FILE="$$(find '$(SCANBUILD_OUTPUTDIR)' -maxdepth 2 -mindepth 2 \ + -type f -name 'index.html' 2>/dev/null | sort | tail -n 1)"; \ + if [ -n "$${REPORT_FILE}" ]; then \ + echo "$(OPEN) $${REPORT_FILE}"; \ + $(OPEN) "$${REPORT_FILE}"; \ + else \ + echo "No report found"; \ + fi +endif + +# Reset the default goal. +.DEFAULT_GOAL :=