]> git.donarmstrong.com Git - qmk_firmware.git/blob - Makefile
Add color output
[qmk_firmware.git] / Makefile
1 ifndef VERBOSE
2 .SILENT:
3 endif
4
5 STARTING_MAKEFILE := $(firstword $(MAKEFILE_LIST))
6 ROOT_MAKEFILE := $(lastword $(MAKEFILE_LIST))
7 ROOT_DIR := $(dir $(ROOT_MAKEFILE))
8 ifeq ($(ROOT_DIR),)
9     ROOT_DIR := .
10 endif
11 ABS_STARTING_MAKEFILE := $(abspath $(STARTING_MAKEFILE))
12 ABS_ROOT_MAKEFILE := $(abspath $(ROOT_MAKEFILE))
13 ABS_STARTING_DIR := $(dir $(ABS_STARTING_MAKEFILE))
14 ABS_ROOT_DIR := $(dir $(ABS_ROOT_MAKEFILE))
15 STARTING_DIR := $(subst $(ABS_ROOT_DIR),,$(ABS_STARTING_DIR))
16
17 PATH_ELEMENTS := $(subst /, ,$(STARTING_DIR))
18
19 MAKEFILE_INCLUDED=yes
20
21 define NEXT_PATH_ELEMENT
22     $$(eval CURRENT_PATH_ELEMENT := $$(firstword  $$(PATH_ELEMENTS)))
23     $$(eval PATH_ELEMENTS := $$(wordlist  2,9999,$$(PATH_ELEMENTS)))
24 endef
25
26 $(eval $(call NEXT_PATH_ELEMENT))
27
28 ifeq ($(CURRENT_PATH_ELEMENT),keyboards)
29     $(eval $(call NEXT_PATH_ELEMENT))
30     KEYBOARD := $(CURRENT_PATH_ELEMENT)
31     $(eval $(call NEXT_PATH_ELEMENT))
32     ifeq ($(CURRENT_PATH_ELEMENT),keymaps)
33         $(eval $(call NEXT_PATH_ELEMENT))
34         KEYMAP := $(CURRENT_PATH_ELEMENT)
35     else ifneq ($(CURRENT_PATH_ELEMENT),)
36         SUBPROJECT := $(CURRENT_PATH_ELEMENT)
37         $(eval $(call NEXT_PATH_ELEMENT))
38         ifeq ($(CURRENT_PATH_ELEMENT),keymaps)
39             $(eval $(call NEXT_PATH_ELEMENT))
40             KEYMAP := $(CURRENT_PATH_ELEMENT)
41         endif
42     endif
43 endif
44
45 # Only consider folders with makefiles, to prevent errors in case there are extra folders
46 KEYBOARDS := $(notdir $(patsubst %/Makefile,%,$(wildcard $(ROOT_DIR)/keyboards/*/Makefile)))
47
48 #Compability with the old make variables
49 ifdef keyboard
50     KEYBOARD := $(keyboard)
51 endif
52 ifdef sub
53     SUBPROJECT := $(sub)
54 endif
55 ifdef subproject
56     SUBPROJECT := $(subproject)
57 endif
58 ifdef keymap
59     KEYMAP := $(keymap)
60 endif
61
62 $(info Keyboard: $(KEYBOARD))
63 $(info Keymap: $(KEYMAP))
64 $(info Subproject: $(SUBPROJECT))
65 $(info Keyboards: $(KEYBOARDS))
66
67 .DEFAULT_GOAL := all
68 ifneq ($(KEYMAP),)
69     ifeq ($(SUBPROJECT),)
70         .DEFAULT_GOAL := $(KEYBOARD)-$(KEYMAP)
71     else
72         .DEFAULT_GOAL := $(KEYBOARD)-$(SUBPROJECT)-$(KEYMAP)
73     endif
74 else ifneq ($(SUBPROJECT),)
75     .DEFAULT_GOAL := $(KEYBOARD)-$(SUBPROJECT)-allkm
76 else ifneq ($(KEYBOARD),)
77     .DEFAULT_GOAL := $(KEYBOARD)-allsp-allkm
78 endif
79
80
81 # Compare the start of the RULE_VARIABLE with the first argument($1)
82 # If the rules equals $1 or starts with $1-, RULE_FOUND is set to true
83 #     and $1 is removed from the RULE variable
84 # Otherwise the RULE_FOUND variable is set to false
85 # The function is a bit tricky, since there's no built in $(startswith) function
86 define COMPARE_AND_REMOVE_FROM_RULE_HELPER
87     ifeq ($1,$$(RULE))
88         RULE:=
89         RULE_FOUND := true
90     else
91         STARTDASH_REMOVED=$$(subst START$1-,,START$$(RULE))
92         ifneq ($$(STARTDASH_REMOVED),START$$(RULE))
93             RULE_FOUND := true
94             RULE := $$(STARTDASH_REMOVED)
95         else
96             RULE_FOUND := false
97         endif
98     endif
99 endef
100
101 COMPARE_AND_REMOVE_FROM_RULE = $(eval $(call COMPARE_AND_REMOVE_FROM_RULE_HELPER,$1))$(RULE_FOUND)
102
103
104 # Recursively try to find a match
105 # $1 The list to be checked
106 # If a match is found, then RULE_FOUND is set to true
107 # and MATCHED_ITEM to the item that was matched
108 define TRY_TO_MATCH_RULE_FROM_LIST_HELPER
109     ifneq ($1,)
110         ifeq ($$(call COMPARE_AND_REMOVE_FROM_RULE,$$(firstword $1)),true)
111             MATCHED_ITEM := $$(firstword $1)
112         else 
113             $$(eval $$(call TRY_TO_MATCH_RULE_FROM_LIST_HELPER,$$(wordlist 2,9999,$1)))
114         endif
115     endif
116 endef
117
118 TRY_TO_MATCH_RULE_FROM_LIST = $(eval $(call TRY_TO_MATCH_RULE_FROM_LIST_HELPER,$1))$(RULE_FOUND)
119
120 define ALL_IN_LIST_LOOP
121     OLD_RULE$1 := $$(RULE)
122     $$(eval $$(call $1,$$(ITEM$1)))
123     RULE := $$(OLD_RULE$1)
124 endef
125
126 define PARSE_ALL_IN_LIST
127     $$(foreach ITEM$1,$2,$$(eval $$(call ALL_IN_LIST_LOOP,$1)))
128 endef
129
130 define PARSE_RULE
131     RULE := $1
132     COMMANDS :=
133     ifeq ($$(call COMPARE_AND_REMOVE_FROM_RULE,allkb),true)
134         $$(eval $$(call PARSE_ALL_KEYBOARDS))
135     else ifeq ($$(call TRY_TO_MATCH_RULE_FROM_LIST,$$(KEYBOARDS)),true)
136         $$(eval $$(call PARSE_KEYBOARD,$$(MATCHED_ITEM)))
137     else ifneq ($$(KEYBOARD),)
138         $$(eval $$(call PARSE_KEYBOARD,$$(KEYBOARD)))
139     else
140         $$(info make: *** No rule to make target '$1'. Stop.)
141                 exit 1
142     endif
143 endef
144
145 # $1 = Keyboard
146 define PARSE_KEYBOARD
147     CURRENT_KB := $1
148     # A subproject is any keyboard subfolder with a makefile
149     SUBPROJECTS := $$(notdir $$(patsubst %/Makefile,%,$$(wildcard $(ROOT_DIR)/keyboards/$$(CURRENT_KB)/*/Makefile)))
150     ifeq ($$(call COMPARE_AND_REMOVE_FROM_RULE,allsp),true)
151         $$(eval $$(call PARSE_ALL_SUBPROJECTS))
152     else ifeq ($$(call COMPARE_AND_REMOVE_FROM_RULE,defaultsp),true)
153         $$(eval $$(call PARSE_SUBPROJECT,defaultsp))
154     else ifeq ($$(call TRY_TO_MATCH_RULE_FROM_LIST,$$(SUBPROJECTS)),true)
155         $$(eval $$(call PARSE_SUBPROJECT,$$(MATCHED_ITEM)))
156     else ifneq ($$(SUBPROJECT),)
157         $$(eval $$(call PARSE_SUBPROJECT,$$(SUBPROJECT)))
158     else 
159         # If there's no matching subproject, we assume it's the default
160         # This will allow you to leave the subproject part of the target out
161         $$(eval $$(call PARSE_SUBPROJECT,defaultsp))
162     endif
163 endef
164
165 define PARSE_ALL_KEYBOARDS
166     $$(eval $$(call PARSE_ALL_IN_LIST,PARSE_KEYBOARD,$(KEYBOARDS)))
167 endef
168
169 # $1 Subproject
170 define PARSE_SUBPROJECT
171     ifeq ($1,defaultsp)
172         SUBPROJECT_DEFAULT=
173         $$(eval include $(ROOT_DIR)/keyboards/$$(CURRENT_KB)/Makefile)
174         CURRENT_SP := $$(SUBPROJECT_DEFAULT)
175     else
176         CURRENT_SP := $1
177     endif
178     # If current subproject is empty (the default was not defined), and we have a list of subproject
179     # then make all
180     ifeq ($$(CURRENT_SP),)
181         ifneq ($$(SUBPROJECTS),)
182             CURRENT_SP := allsp
183          endif
184     endif
185     ifneq ($$(CURRENT_SP),allsp) 
186         KEYMAPS := $$(notdir $$(patsubst %/.,%,$$(wildcard $(ROOT_DIR)/keyboards/$$(CURRENT_KB)/keymaps/*/.)))
187         ifneq ($$(CURRENT_SP),)
188             SP_KEYMAPS := $$(notdir $$(patsubst %/.,%,$$(wildcard $(ROOT_DIR)/keyboards/$$(CURRENT_KB)/$$(CURRENT_SP)/keymaps/*/.)))
189             KEYMAPS := $$(sort $$(KEYMAPS) $$(SP_KEYMAPS))
190         endif
191         ifeq ($$(RULE),)
192             $$(eval $$(call PARSE_ALL_KEYMAPS))
193         else ifeq ($$(call COMPARE_AND_REMOVE_FROM_RULE,allkm),true)
194             $$(eval $$(call PARSE_ALL_KEYMAPS))
195         else ifeq ($$(call TRY_TO_MATCH_RULE_FROM_LIST,$$(KEYMAPS)),true)
196             $$(eval $$(call PARSE_KEYMAP,$$(MATCHED_ITEM)))
197         else ifneq ($$(KEYMAP),)
198             $$(eval $$(call PARSE_KEYMAP,$$(KEYMAP)))
199         else
200             ifeq ($$(CURRENT_SP),)
201                 $$(info make: *** No rule to make target '$$(CURRENT_KB)-$$(RULE)'. Stop.)
202             else
203                 $$(info make: *** No rule to make target '$$(CURRENT_KB)-$$(CURRENT_SP)-$$(RULE)'. Stop.)
204             endif
205                         exit 1
206         endif
207     else
208         $$(eval $$(call PARSE_ALL_IN_LIST,PARSE_SUBPROJECT,$(SUBPROJECTS)))
209     endif
210 endef
211
212 define PARSE_ALL_SUBPROJECTS
213     ifeq ($$(SUBPROJECTS),)
214         $$(eval $$(call PARSE_SUBPROJECT,defaultsp))
215     else
216         $$(eval $$(call PARSE_ALL_IN_LIST,PARSE_SUBPROJECT,$$(SUBPROJECTS)))
217     endif
218 endef
219
220 # $1 Keymap
221 define PARSE_KEYMAP
222     CURRENT_KM = $1
223     COMMAND := COMMAND_KEYBOARD_$$(CURRENT_KB)_SUBPROJECT_$(CURRENT_SP)_KEYMAP_$$(CURRENT_KM)
224     COMMANDS += $$(COMMAND)
225     ifeq ($$(CURRENT_SP),)
226         KB_SP := $(CURRENT_KB)
227     else
228         KB_SP := $(CURRENT_KB)/$$(CURRENT_SP)
229     endif
230     KB_SP := $(BOLD)$$(KB_SP)$(NO_COLOR)
231     COMMAND_$$(COMMAND) := \
232     printf "Compiling $$(KB_SP) with $(BOLD)$$(CURRENT_KM)$(NO_COLOR)" | \
233     $(AWK) '{ printf "%-118s", $$$$0;}'; \
234     LOG=$$$$(echo "$$(MAKE) -c $(ROOT_DIR) -f build_keyboard.mk VERBOSE=$(VERBOSE) COLOR=$(COLOR) SILENT=true" 2>&1) ; \
235     if [ $$$$? -gt 0 ]; \
236         then $$(PRINT_ERROR_PLAIN); \
237     elif [ "$$$$LOG" != "" ] ; \
238         then $$(PRINT_WARNING_PLAIN); \
239     else \
240         $$(PRINT_OK); \
241     fi;
242 endef
243
244 define PARSE_ALL_KEYMAPS
245     $$(eval $$(call PARSE_ALL_IN_LIST,PARSE_KEYMAP,$$(KEYMAPS)))
246 endef
247
248 include $(ROOT_DIR)/message.mk
249
250 #RUN_COMMAND = echo "Running": $(COMMAND_$(COMMAND));
251 RUN_COMMAND = \
252 $(COMMAND_$(COMMAND))
253 #LOG=$$(echo $(COMMAND) VERBOSE=$(VERBOSE) COLOR=$(COLOR) SILENT=true 2>&1) ; if [ $$? -gt 0 ]; then $(PRINT_ERROR_PLAIN); elif [ "$$LOG" != "" ] ; then $(PRINT_WARNING_PLAIN); else $(PRINT_OK); fi; \
254
255 # Allow specifying just the subproject, in the keyboard directory, which will compile all keymaps
256 SUBPROJECTS := $(notdir $(patsubst %/Makefile,%,$(wildcard ./*/Makefile)))
257 .PHONY: $(SUBPROJECTS)
258 $(SUBPROJECTS): %: %-allkm 
259
260 .PHONY: %
261 %:
262         $(eval $(call PARSE_RULE,$@))
263         $(foreach COMMAND,$(COMMANDS),$(RUN_COMMAND))
264
265 .PHONY: all
266 all: all-keyboards 
267
268 .PHONY: all-keyboards
269 all-keyboards: allkb-allsp-allkm
270
271 .PHONY: all-keyboards-defaults
272 all-keyboards-defaults: allkb-allsp-default
273