]> git.donarmstrong.com Git - qmk_firmware.git/blobdiff - Makefile
More common settings for unit tests and keyboards
[qmk_firmware.git] / Makefile
index d70ac9a3b8f70355ccdbc9f49497bfb6e52fa2c3..5f5c46860cf16030ec3fe5bdc060b671976339ac 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -28,6 +28,7 @@ ABS_ROOT_MAKEFILE := $(abspath $(ROOT_MAKEFILE))
 ABS_STARTING_DIR := $(dir $(ABS_STARTING_MAKEFILE))
 ABS_ROOT_DIR := $(dir $(ABS_ROOT_MAKEFILE))
 STARTING_DIR := $(subst $(ABS_ROOT_DIR),,$(ABS_STARTING_DIR))
+TEST_DIR := $(ROOT_DIR)/.build/test
 
 MAKEFILE_INCLUDED=yes
 
@@ -152,16 +153,55 @@ COMPARE_AND_REMOVE_FROM_RULE = $(eval $(call COMPARE_AND_REMOVE_FROM_RULE_HELPER
 # $1 The list to be checked
 # If a match is found, then RULE_FOUND is set to true
 # and MATCHED_ITEM to the item that was matched
-define TRY_TO_MATCH_RULE_FROM_LIST_HELPER
+define TRY_TO_MATCH_RULE_FROM_LIST_HELPER3
     ifneq ($1,)
         ifeq ($$(call COMPARE_AND_REMOVE_FROM_RULE,$$(firstword $1)),true)
             MATCHED_ITEM := $$(firstword $1)
         else 
-            $$(eval $$(call TRY_TO_MATCH_RULE_FROM_LIST_HELPER,$$(wordlist 2,9999,$1)))
+            $$(eval $$(call TRY_TO_MATCH_RULE_FROM_LIST_HELPER3,$$(wordlist 2,9999,$1)))
         endif
     endif
 endef
 
+# A recursive helper function for finding the longest match
+# $1 The list to be checed
+# It works by always removing the currently matched item from the list 
+# and call itself recursively, until a match is found
+define TRY_TO_MATCH_RULE_FROM_LIST_HELPER2
+    # Stop the recursion when the list is empty 
+    ifneq ($1,)
+        RULE_BEFORE := $$(RULE)
+        $$(eval $$(call TRY_TO_MATCH_RULE_FROM_LIST_HELPER3,$1))
+        # If a match is found in the current list, otherwise just return what we had before
+        ifeq ($$(RULE_FOUND),true)
+            # Save the best match so far and call itself recursivel
+            BEST_MATCH := $$(MATCHED_ITEM)
+            BEST_MATCH_RULE := $$(RULE)
+            RULE_FOUND := false
+            RULE := $$(RULE_BEFORE)
+            $$(eval $$(call TRY_TO_MATCH_RULE_FROM_LIST_HELPER2,$$(filter-out $$(MATCHED_ITEM),$1)))
+        endif
+     endif
+endef
+
+
+# Recursively try to find the longest match for the start of the rule to be checked
+# $1 The list to be checked
+# If a match is found, then RULE_FOUND is set to true
+# and MATCHED_ITEM to the item that was matched
+define TRY_TO_MATCH_RULE_FROM_LIST_HELPER
+    BEST_MATCH :=
+    $$(eval $$(call TRY_TO_MATCH_RULE_FROM_LIST_HELPER2,$1))
+    ifneq ($$(BEST_MATCH),)
+        RULE_FOUND := true
+        RULE := $$(BEST_MATCH_RULE)
+        MATCHED_ITEM := $$(BEST_MATCH)
+    else
+        RULE_FOUND := false
+        MATCHED_ITEM :=
+    endif
+endef
+
 # Make it easier to call TRY_TO_MATCH_RULE_FROM_LIST
 TRY_TO_MATCH_RULE_FROM_LIST = $(eval $(call TRY_TO_MATCH_RULE_FROM_LIST_HELPER,$1))$(RULE_FOUND)
 
@@ -185,6 +225,8 @@ define PARSE_RULE
     # PARSE_ALL_KEYBOARDS
     ifeq ($$(call COMPARE_AND_REMOVE_FROM_RULE,allkb),true)
         $$(eval $$(call PARSE_ALL_KEYBOARDS))
+    else ifeq ($$(call COMPARE_AND_REMOVE_FROM_RULE,test),true)
+        $$(eval $$(call PARSE_TEST))
     # If the rule starts with the name of a known keyboard, then continue
     # the parsing from PARSE_KEYBOARD
     else ifeq ($$(call TRY_TO_MATCH_RULE_FROM_LIST,$$(KEYBOARDS)),true)
@@ -223,7 +265,7 @@ define PARSE_KEYBOARD
        # If there's no matching subproject, we assume it's the default
        # This will allow you to leave the subproject part of the target out
     else 
-        $$(eval $$(call PARSE_SUBPROJECT,defaultsp))
+        $$(eval $$(call PARSE_SUBPROJECT,))
     endif
 endef
 
@@ -239,12 +281,14 @@ endef
 define PARSE_SUBPROJECT
     # If we want to compile the default subproject, then we need to 
     # include the correct makefile to determine the actual name of it
-    ifeq ($1,defaultsp)
+    CURRENT_SP := $1
+    ifeq ($$(CURRENT_SP),)
+        CURRENT_SP := defaultsp
+    endif
+    ifeq ($$(CURRENT_SP),defaultsp)
         SUBPROJECT_DEFAULT=
         $$(eval include $(ROOT_DIR)/keyboards/$$(CURRENT_KB)/Makefile)
         CURRENT_SP := $$(SUBPROJECT_DEFAULT)
-    else
-        CURRENT_SP := $1
     endif
     # If current subproject is empty (the default was not defined), and we have a list of subproject
     # then make all of them
@@ -275,16 +319,16 @@ define PARSE_SUBPROJECT
         # Otherwise try to match the keymap from the current folder, or arguments to the make command
         else ifneq ($$(KEYMAP),)
             $$(eval $$(call PARSE_KEYMAP,$$(KEYMAP)))
+        # No matching keymap found, so we assume that the rest of the rule is the target
+        # If we haven't been able to parse out a subproject, then make all of them
+        # This is consistent with running make without any arguments from the keyboard
+        # folder
+        else ifeq ($1,)
+            $$(eval $$(call PARSE_ALL_SUBPROJECTS))
+        # Otherwise, make all keymaps, again this is consistent with how it works without
+        # any arguments
         else
-            # Otherwise something is wrong with the target
-            # Try to give as much information as possible of what it it was trying to do
-            ifeq ($$(CURRENT_SP),)
-                $$(info make: *** No rule to make target '$$(CURRENT_KB)-$$(RULE)'. Stop.)
-            else
-                $$(info make: *** No rule to make target '$$(CURRENT_KB)-$$(CURRENT_SP)-$$(RULE)'. Stop.)
-            endif
-            # Notice the tab instead of spaces below!
-                       exit 1
+            $$(eval $$(call PARSE_ALL_KEYMAPS))
         endif
     else
         # As earlier mentione,d when allsb is specified, we call our self recursively
@@ -315,7 +359,6 @@ define PARSE_KEYMAP
     MAKE_TARGET := $$(patsubst -%,%,$$(RULE))
     # We need to generate an unique indentifer to append to the COMMANDS list
     COMMAND := COMMAND_KEYBOARD_$$(CURRENT_KB)_SUBPROJECT_$(CURRENT_SP)_KEYMAP_$$(CURRENT_KM)
-    COMMANDS += $$(COMMAND)
     # If we are compiling a keyboard without a subproject, we want to display just the name
     # of the keyboard, otherwise keyboard/subproject
     ifeq ($$(CURRENT_SP),)
@@ -327,13 +370,18 @@ define PARSE_KEYMAP
     KB_SP := $(BOLD)$$(KB_SP)$(NO_COLOR)
     # Specify the variables that we are passing forward to submake
     MAKE_VARS := KEYBOARD=$$(CURRENT_KB) SUBPROJECT=$$(CURRENT_SP) KEYMAP=$$(CURRENT_KM)
-    MAKE_VARS += VERBOSE=$(VERBOSE) COLOR=$(COLOR)
     # And the first part of the make command
     MAKE_CMD := $$(MAKE) -r -R -C $(ROOT_DIR) -f build_keyboard.mk $$(MAKE_TARGET)
     # The message to display
     MAKE_MSG := $$(MSG_MAKE_KB)
     # We run the command differently, depending on if we want more output or not
     # The true version for silent output and the false version otherwise
+    $$(eval $$(call BUILD))
+endef
+
+define BUILD
+    MAKE_VARS += VERBOSE=$(VERBOSE) COLOR=$(COLOR)
+    COMMANDS += $$(COMMAND)
     COMMAND_true_$$(COMMAND) := \
         printf "$$(MAKE_MSG)" | \
         $$(MAKE_MSG_FORMAT); \
@@ -347,7 +395,10 @@ define PARSE_KEYMAP
         fi;
     COMMAND_false_$$(COMMAND) := \
         printf "$$(MAKE_MSG)\n\n"; \
-        $$(MAKE_CMD) $$(MAKE_VARS) SILENT=false;
+        $$(MAKE_CMD) $$(MAKE_VARS) SILENT=false; \
+        if [ $$$$? -gt 0 ]; \
+            then error_occured=1; \
+        fi;
 endef
 
 # Just parse all the keymaps for a specifc keyboard
@@ -355,6 +406,27 @@ define PARSE_ALL_KEYMAPS
     $$(eval $$(call PARSE_ALL_IN_LIST,PARSE_KEYMAP,$$(KEYMAPS)))
 endef
 
+define BUILD_TEST
+    TEST_NAME := $1
+    MAKE_TARGET := $2
+    COMMAND := $1
+    MAKE_CMD := $$(MAKE) -r -R -C $(ROOT_DIR) -f build_test.mk $$(MAKE_TARGET)
+    MAKE_VARS := TEST=$$(TEST_NAME)
+    MAKE_MSG := $$(MSG_MAKE_TEST)
+    $$(eval $$(call BUILD))
+    TEST_EXECUTABLE := $$(TEST_DIR)/$$(TEST_NAME).elf
+    TESTS += $$(TEST_EXECUTABLE)
+endef
+
+define PARSE_TEST
+    TESTS :=
+    TEST_NAME := $$(firstword $$(subst -, ,$$(RULE)))
+    TEST_TARGET := $$(subst $$(TEST_NAME),,$$(subst $$(TEST_NAME)-,,$$(RULE)))
+    MATCHED_TESTS := $$(foreach TEST,$$(TEST_LIST),$$(if $$(findstring $$(TEST_NAME),$$(TEST)),$$(TEST),))
+    $$(foreach TEST,$$(MATCHED_TESTS),$$(eval $$(call BUILD_TEST,$$(TEST),$$(TEST_TARGET))))
+endef
+
+
 # Set the silent mode depending on if we are trying to compile multiple keyboards or not
 # By default it's on in that case, but it can be overriden by specifying silent=false 
 # from the command line
@@ -399,8 +471,8 @@ $(SUBPROJECTS): %: %-allkm
        # But we return the error code at the end, to trigger travis failures
        +error_occured=0; \
        $(foreach COMMAND,$(COMMANDS),$(RUN_COMMAND)) \
-       if [ $$error_occured -gt 0 ]; then printf "$(MSG_ERRORS)" & exit $$error_occured; fi
-       
+       if [ $$error_occured -gt 0 ]; then printf "$(MSG_ERRORS)" & exit $$error_occured; fi;\
+       $(foreach TEST,$(TESTS),$(TEST);)
 
 # All should compile everything
 .PHONY: all
@@ -418,4 +490,6 @@ all-keyboards-defaults: allkb-allsp-default
 GIT_VERSION := $(shell git describe --abbrev=6 --dirty --always --tags 2>/dev/null || date +"%Y-%m-%d-%H:%M:%S")
 BUILD_DATE := $(shell date +"%Y-%m-%d-%H:%M:%S")
 $(shell echo '#define QMK_VERSION "$(GIT_VERSION)"' > $(ROOT_DIR)/quantum/version.h)
-$(shell echo '#define QMK_BUILDDATE "$(BUILD_DATE)"' >> $(ROOT_DIR)/quantum/version.h)
\ No newline at end of file
+$(shell echo '#define QMK_BUILDDATE "$(BUILD_DATE)"' >> $(ROOT_DIR)/quantum/version.h)
+
+include $(ROOT_DIR)/testlist.mk
\ No newline at end of file