1DOWNLOAD_SCRIPT := $(MAKEFILE_DIR)/download_and_extract.sh
2
3# Reverses a space-separated list of words.
4reverse = $(if $(1),$(call reverse,$(wordlist 2,$(words $(1)),$(1)))) $(firstword $(1))
5
6# Get macros only (i.e. the ones starting with -D) from two lists and remove duplicates
7getmacros = $(patsubst -D%,%,$(filter -D%,$(sort $(filter -D%, $(1)) $(filter -D%, $(2)))))
8
9# Look for platform or target-specific implementation files to replace reference
10# implementations with, given a tag. These are expected to occur in subfolders
11# of a directory where a reference implementation exists, and have the same
12# interface and header file. For example,
13# tensorflow/lite/micro/examples/micro_speech/audio_provider.cc
14# defines a module for supplying audio data, but since no platform or OS can be
15# presumed, it just always returns zeroes for its samples. The MacOS-specific
16# tensorflow/lite/micro/examples/micro_speech/osx/audio_provider.cc
17# has an implementation that relies on CoreAudio, and there are equivalent
18# versions for other operating systems.
19# The specific implementation yielded by the first tag in the list that produces
20# a match is returned, else the reference version if none of the tags produce a
21# match.
22# All lists of source files are put through this substitution process with the
23# tags of their target OS and architecture, so that implementations can be added
24# by simply placing them in the file tree, with no changes to the build files
25# needed.
26# One confusing thing about this implementation is that we're using wildcard to
27# act as a 'does file exist?' function, rather than expanding an expression.
28# Wildcard will return an empty string if given a plain file path with no actual
29# wildcards, if the file doesn't exist, so taking the first word of the list
30# between that and the reference path will pick the specialized one if it's
31# available.
32# Another fix is that originally if neither file existed(either the original or
33# a specialized version) this would return an empty string.Because this is
34# sometimes called on third party library files before they've been downloaded,
35# this caused mysterious errors, so an initial if conditional was added so that
36# specializations are only looked for if the original file exists.
37substitute_specialized_implementation = \
38  $(if $(wildcard $(1)),$(firstword $(wildcard $(dir $(1))$(2)/$(notdir $(1))) $(wildcard $(1))),$(1))
39substitute_specialized_implementations = \
40  $(foreach source,$(1),$(call substitute_specialized_implementation,$(source),$(2)))
41
42# Tests and project generation targets use this entrypoint for to get the
43# specialized sources. It should be avoided for any new functionality.
44# The only argument is a list of file paths.
45specialize = $(call substitute_specialized_implementations,$(1),$(TARGET))
46
47# TODO(b/143904317): It would be better to have the dependency be
48# THIRD_PARTY_TARGETS instead of third_party_downloads. However, that does not
49# quite work for the generate_project functions.
50#
51# Creates a set of rules to build a standalone makefile project for an
52# executable, including all of the source and header files required in a
53# separate folder and a simple makefile.
54# Arguments are:
55# 1 - Project type (make, mbed, etc).
56# 2 - Project file template name.
57# 3 - Name of executable.
58# 4 - List of C/C++ source files needed to build the target.
59# 5 - List of C/C++ header files needed to build the target.
60# 6 - Linker flags required.
61# 7 - C++ compilation flags needed.
62# 8 - C compilation flags needed.
63# 9 - Target Toolchian root directory
64# 10 - Target Toolchain prefix
65# Calling eval on the output will create a <Name>_makefile target that you
66# can invoke to create the standalone project.
67define generate_project
68$(PRJDIR)$(3)/$(1)/%: % third_party_downloads
69	@mkdir -p $$(dir $$@)
70	@cp $$< $$@
71
72$(PRJDIR)$(3)/cmake/boards/%: tensorflow/lite/micro/examples/$(3)/zephyr_riscv/boards/%
73	@mkdir -p $$(dir $$@)
74	@cp $$< $$@
75
76$(PRJDIR)$(3)/cmake/%: tensorflow/lite/micro/examples/$(3)/zephyr_riscv/%
77	@mkdir -p $$(dir $$@)
78	@cp $$< $$@
79
80$(PRJDIR)$(3)/$(1)/third_party/%: tensorflow/lite/micro/tools/make/downloads/% third_party_downloads
81	@mkdir -p $$(dir $$@)
82	@cp $$< $$@
83
84$(PRJDIR)$(3)/$(1)/%: tensorflow/lite/micro/tools/make/templates/%.tpl
85	@mkdir -p $$(dir $$@)
86	@sed -E 's#\%\{SRCS\}\%#$(4)#g' $$< | \
87	sed -E 's#\%\{EXECUTABLE\}\%#$(3)#g' | \
88	sed -E 's#\%\{LINKER_FLAGS\}\%#$(6)#g' | \
89	sed -E 's#\%\{CXX_FLAGS\}\%#$(7)#g' | \
90	sed -E 's#\%\{CC_FLAGS\}\%#$(8)#g' | \
91	sed -E 's#\%\{TARGET_TOOLCHAIN_ROOT\}\%#$(9)#g' | \
92	sed -E 's#\%\{TARGET_TOOLCHAIN_PREFIX\}\%#$(10)#g' > $$@
93
94$(PRJDIR)$(3)/$(1)/keil_project.uvprojx: tensorflow/lite/micro/tools/make/templates/keil_project.uvprojx.tpl
95	@mkdir -p $$(dir $$@)
96	@python tensorflow/lite/micro/tools/make/generate_keil_project.py \
97        --input_template=$$< --output_file=$$@ --executable=$(3) \
98        --srcs="$(4)" --hdrs="$(5)" --include_paths="$$(PROJECT_INCLUDES)"
99
100$(PRJDIR)$(3)/$(1)/.vscode/tasks.json : tensorflow/lite/micro/tools/make/templates/tasks.json.$(1).tpl
101	@mkdir -p $$(dir $$@)
102	@cp $$< $$@
103
104generate_$(3)_$(1)_project: $(addprefix $(PRJDIR)$(3)/$(1)/, $(4) $(5) $(2))
105ifeq (mbed, $(1))
106	$(eval macrolist := $(call getmacros, $7, $8))
107	$(eval jsonfilename := $(PRJDIR)$(3)/$(1)/mbed_app)
108	@awk 'FNR==NR{ if (/}/) p=NR; next} 1; FNR==(p-1){ n=split("$(macrolist)",a," "); print("    ,\"macros\": [");for (i=1; i <= n; i++){ printf("        \"%s\"", a[i]); if(i<n){printf(",\n")}}printf("\n    ]\n")}' \
109        $(jsonfilename).json $(jsonfilename).json > $(jsonfilename).tmp && mv $(jsonfilename).tmp $(jsonfilename).json
110endif
111
112list_$(3)_$(1)_files:
113	@echo $(4) $(5)
114
115ALL_PROJECT_TARGETS += generate_$(3)_$(1)_project
116endef
117
118# Creates a set of rules to build a standalone makefile project for the ARC platform
119# including all of the source and header files required in a
120# separate folder and a simple makefile.
121# Arguments are:
122# 1 - Project type (make, mbed, etc).
123# 2 - Project file template name.
124# 3 - Name of executable.
125# 4 - List of C/C++ source files needed to build the target.
126# 5 - List of C/C++ header files needed to build the target.
127# 6 - Linker flags required.
128# 7 - C++ compilation flags needed.
129# 8 - C compilation flags needed.
130
131# Calling eval on the output will create a <Name>_makefile target that you
132# can invoke to create the standalone project.
133define generate_arc_project
134
135ifeq ($(TARGET_ARCH), arc)
136
137$(PRJDIR)$(3)/$(1)/Makefile: tensorflow/lite/micro/tools/make/templates/arc/arc_app_makefile.tpl
138	@mkdir -p $$(dir $$@)
139	@sed -E 's#\%\{SRCS\}\%#$(4)#g' $$< | \
140	sed -E 's#\%\{CC\}\%#$(CC_TOOL)#g' | \
141	sed -E 's#\%\{CXX\}\%#$(CXX_TOOL)#g' | \
142	sed -E 's#\%\{LD\}\%#$(LD_TOOL)#g' | \
143	sed -E 's#\%\{EXECUTABLE\}\%#$(3).elf#g' | \
144	sed -E 's#\%\{LINKER_FLAGS\}\%#$(6)#g' | \
145	sed -E 's#\%\{CXX_FLAGS\}\%#$(7)#g' | \
146	sed -E 's#\%\{CC_FLAGS\}\%#$(8)#g' | \
147	sed -E 's#\%\{EXTRA_APP_SETTINGS\}\%#$(ARC_EXTRA_APP_SETTINGS)#g' | \
148	sed -E 's#\%\{EXTRA_APP_RULES\}\%#$(ARC_EXTRA_APP_RULES)#g' | \
149	sed -E 's#\%\{BIN_DEPEND\}\%#$(ARC_BIN_DEPEND)#g' | \
150	sed -E 's#\%\{BIN_RULE\}\%#$(ARC_BIN_RULE)#g' | \
151	sed -E 's#\%\{EXTRA_RM_TARGETS\}\%#$(ARC_EXTRA_RM_TARGETS)#g' | \
152	sed -E 's#\%\{APP_RUN_CMD\}\%#$(ARC_APP_RUN_CMD)#g' | \
153	sed -E 's#\%\{APP_DEBUG_CMD\}\%#$(ARC_APP_DEBUG_CMD)#g' | \
154	sed -E 's#\%\{EXTRA_EXECUTE_RULES\}\%#$(ARC_EXTRA_EXECUTE_RULES)#g' > $$@
155
156$(PRJDIR)$(3)/$(1)/%: tensorflow/lite/micro/tools/make/templates/arc/%.tpl
157	@cp $$< $$@
158
159$(foreach var,$(ARC_TARGET_COPY_FILES), $(eval $(call path_changing_copy_file,\
160    $(PRJDIR)$(3)/$(1)/$(word 1, $(subst !, ,$(var))),\
161    $(word 2, $(subst !, ,$(var))))))
162
163endif
164endef
165
166
167define generate_ceva_bx1_project
168ifeq ($(TARGET), ceva)
169ifeq ($(TARGET_ARCH), CEVA_BX1)
170
171$(PRJDIR)$(3)/$(1)/Makefile: tensorflow/lite/micro/tools/make/templates/ceva/ceva_app_makefile_v18.0.5.tpl
172	@mkdir -p $$(dir $$@)
173	@sed -E 's#\%\{SRCS\}\%#$(4)#g' $$< | \
174	sed -E 's#\%\{CC\}\%#$(CC_TOOL)#g' | \
175	sed -E 's#\%\{CXX\}\%#$(CXX_TOOL)#g' | \
176	sed -E 's#\%\{LD\}\%#$(LD_TOOL)#g' | \
177	sed -E 's#\%\{EXECUTABLE\}\%#$(3).elf#g' | \
178	sed -E 's#\%\{LD_FLAGS\}\%#$(6)#g' | \
179	sed -E 's#\%\{CXX_FLAGS\}\%#$(7)#g' | \
180	sed -E 's#\%\{CC_FLAGS\}\%#$(8)#g' > $$@
181
182$(PRJDIR)$(3)/$(1)/%: tensorflow/lite/micro/tools/make/templates/ceva/%.tpl
183	@cp $$< $$@
184
185$(foreach var,$(CEVA_TARGET_FILES_DIRS),$(eval $(call path_changing_copy_file,$(PRJDIR)$(3)/$(1),$(var))))
186
187endif
188endif
189endef
190
191define generate_ceva_sp500_project
192ifeq ($(TARGET), ceva)
193ifeq ($(TARGET_ARCH), CEVA_SP500)
194
195$(PRJDIR)$(3)/$(1)/Makefile: tensorflow/lite/micro/tools/make/templates/ceva_SP500/ceva_app_makefile.tpl
196	@mkdir -p $$(dir $$@)
197	@sed -E 's#\%\{SRCS\}\%#$(4)#g' $$< | \
198	sed -E 's#\%\{CC\}\%#$(CC_TOOL)#g' | \
199	sed -E 's#\%\{CXX\}\%#$(CXX_TOOL)#g' | \
200	sed -E 's#\%\{LD\}\%#$(LD_TOOL)#g' | \
201	sed -E 's#\%\{EXECUTABLE\}\%#$(3).elf#g' | \
202	sed -E 's#\%\{LD_FLAGS\}\%#$(6)#g' | \
203	sed -E 's#\%\{CXX_FLAGS\}\%#$(7)#g' | \
204	sed -E 's#\%\{CC_FLAGS\}\%#$(8)#g' | \
205	sed -E 's#\%\{EXTRA_APP_SETTINGS\}\%#$(ARC_EXTRA_APP_SETTINGS)#g' | \
206	sed -E 's#\%\{EXTRA_APP_RULES\}\%#$(ARC_EXTRA_APP_RULES)#g' | \
207	sed -E 's#\%\{BIN_DEPEND\}\%#$(ARC_BIN_DEPEND)#g' | \
208	sed -E 's#\%\{BIN_RULE\}\%#$(ARC_BIN_RULE)#g' | \
209	sed -E 's#\%\{EXTRA_RM_TARGETS\}\%#$(ARC_EXTRA_RM_TARGETS)#g' | \
210	sed -E 's#\%\{APP_RUN_CMD\}\%#$(ARC_APP_RUN_CMD)#g' | \
211	sed -E 's#\%\{APP_DEBUG_CMD\}\%#$(ARC_APP_DEBUG_CMD)#g' | \
212	sed -E 's#\%\{EXTRA_EXECUTE_RULES\}\%#$(ARC_EXTRA_EXECUTE_RULES)#g' > $$@
213
214$(PRJDIR)$(3)/$(1)/%: tensorflow/lite/micro/tools/make/templates/ceva_SP500/%.tpl
215	@cp $$< $$@
216
217$(foreach var,$(CEVA_TARGET_FILES_DIRS),$(eval $(call path_changing_copy_file,$(PRJDIR)$(3)/$(1),$(var))))
218
219endif
220endif
221endef
222
223
224
225
226
227# Creates a set of rules to build a standalone Arduino project for an
228# executable, including all of the source and header files required in a
229# separate folder and a simple makefile.
230# Arguments are:
231# 1 - Project file template names.
232# 2 - Name of executable.
233# 3 - List of C/C++ source files needed to build the target.
234# 4 - List of C/C++ header files needed to build the target.
235# 5 - Linker flags required.
236# 6 - C++ compilation flags needed.
237# 7 - C compilation flags needed.
238# Calling eval on the output will create a <Name>_makefile target that you
239# can invoke to create the standalone project.
240define generate_arduino_project
241
242$(PRJDIR)$(2)/arduino/examples/%.c: tensorflow/lite/micro/examples/%.c
243	@mkdir -p $$(dir $$@)
244	@python tensorflow/lite/micro/tools/make/transform_source.py \
245        --platform=arduino \
246        --is_example_source \
247        --source_path="$$<" \
248        --third_party_headers="$(4)" < $$< > $$@
249
250$(PRJDIR)$(2)/arduino/examples/%.cpp: tensorflow/lite/micro/examples/%.cc
251	@mkdir -p $$(dir $$@)
252	@python tensorflow/lite/micro/tools/make/transform_source.py \
253        --platform=arduino \
254        --is_example_source \
255        --source_path="$$<" \
256        --third_party_headers="$(4)" < $$< > $$@
257
258$(PRJDIR)$(2)/arduino/examples/%.h: tensorflow/lite/micro/examples/%.h
259	@mkdir -p $$(dir $$@)
260	@python tensorflow/lite/micro/tools/make/transform_source.py \
261        --platform=arduino \
262        --is_example_source \
263        --source_path="$$<" \
264        --third_party_headers="$(4)" < $$< > $$@
265
266$(PRJDIR)$(2)/arduino/examples/%/main.ino: tensorflow/lite/micro/examples/%/main_functions.cc
267	@mkdir -p $$(dir $$@)
268	@python tensorflow/lite/micro/tools/make/transform_source.py \
269        --platform=arduino \
270        --is_example_ino \
271        --source_path="$$<" \
272        --third_party_headers="$(4)" < $$< > $$@
273
274$(PRJDIR)$(2)/arduino/src/%.cpp: %.cc
275	@mkdir -p $$(dir $$@)
276	@python tensorflow/lite/micro/tools/make/transform_source.py \
277        --platform=arduino \
278        --third_party_headers="$(4)" < $$< > $$@
279
280$(PRJDIR)$(2)/arduino/src/%.h: %.h third_party_downloads
281	@mkdir -p $$(dir $$@)
282	@python tensorflow/lite/micro/tools/make/transform_source.py \
283        --platform=arduino \
284        --third_party_headers="$(4)" < $$< > $$@
285
286$(PRJDIR)$(2)/arduino/LICENSE: LICENSE
287	@mkdir -p $$(dir $$@)
288	@cp $$< $$@
289
290$(PRJDIR)$(2)/arduino/src/%: % third_party_downloads
291	@mkdir -p $$(dir $$@)
292	@python tensorflow/lite/micro/tools/make/transform_source.py \
293        --platform=arduino \
294        --third_party_headers="$(4)" < $$< > $$@
295
296$(PRJDIR)$(2)/arduino/src/third_party/%: tensorflow/lite/micro/tools/make/downloads/% third_party_downloads
297	@mkdir -p $$(dir $$@)
298	@python tensorflow/lite/micro/tools/make/transform_source.py \
299        --platform=arduino \
300        --third_party_headers="$(4)" < $$< > $$@
301
302$(PRJDIR)$(2)/arduino/src/third_party/%.cpp: tensorflow/lite/micro/tools/make/downloads/%.cc third_party_downloads
303	@mkdir -p $$(dir $$@)
304	@python tensorflow/lite/micro/tools/make/transform_source.py \
305        --platform=arduino \
306        --third_party_headers="$(4)" < $$< > $$@
307
308$(PRJDIR)$(2)/arduino/src/third_party/flatbuffers/include/flatbuffers/base.h: tensorflow/lite/micro/tools/make/downloads/flatbuffers/include/flatbuffers/base.h third_party_downloads
309	@mkdir -p $$(dir $$@)
310	@python tensorflow/lite/micro/tools/make/transform_source.py \
311        --platform=arduino \
312        --third_party_headers="$(4)" < $$< | \
313        sed -E 's/utility\.h/utility/g' > $$@
314
315$(PRJDIR)$(2)/arduino/src/third_party/kissfft/kiss_fft.h: tensorflow/lite/micro/tools/make/downloads/kissfft/kiss_fft.h third_party_downloads
316	@mkdir -p $$(dir $$@)
317	@python tensorflow/lite/micro/tools/make/transform_source.py \
318        --platform=arduino \
319        --third_party_headers="$(4)" < $$< | \
320        sed -E 's@#include <string.h>@//#include <string.h> /* Patched by helper_functions.inc for Arduino compatibility */@g' > $$@
321
322$(PRJDIR)$(2)/arduino/%: tensorflow/lite/micro/tools/make/templates/%
323	@mkdir -p $$(dir $$@)
324	@sed -E 's#\%\{SRCS\}\%#$(3)#g' $$< | \
325	sed -E 's#\%\{EXECUTABLE\}\%#$(2)#g' | \
326	sed -E 's#\%\{LINKER_FLAGS\}\%#$(5)#g' | \
327	sed -E 's#\%\{CXX_FLAGS\}\%#$(6)#g' | \
328	sed -E 's#\%\{CC_FLAGS\}\%#$(7)#g' > $$@
329
330$(PRJDIR)$(2)/arduino/examples/$(2)/$(2).ino: tensorflow/lite/micro/tools/make/templates/arduino_example.ino
331	@mkdir -p $$(dir $$@)
332	@cp $$< $$@
333
334$(PRJDIR)$(2)/arduino/src/TensorFlowLite.h: tensorflow/lite/micro/tools/make/templates/TensorFlowLite.h
335	@mkdir -p $$(dir $$@)
336	@cp $$< $$@
337
338# This would be cleaner if we broke up the list of dependencies into variables,
339# but these get hard to define with the evaluation approach used to define make
340# functions.
341generate_$(2)_arduino_project: \
342$(addprefix $(PRJDIR)$(2)/arduino/,         \
343$(patsubst tensorflow/%,src/tensorflow/%,\
344$(patsubst examples/%/main_functions.cpp,examples/%/main.ino,\
345$(patsubst examples/%_test.cpp,examples/%_test.ino,\
346$(patsubst tensorflow/lite/micro/examples/%,examples/%,\
347$(patsubst third_party/%,src/third_party/%,\
348$(patsubst %.cc,%.cpp,$(3))))))))                                     \
349$(addprefix $(PRJDIR)$(2)/arduino/, \
350$(patsubst tensorflow/%,src/tensorflow/%,\
351$(patsubst tensorflow/lite/micro/examples/%,examples/%,\
352$(patsubst third_party/%,src/third_party/%,$(4))))) \
353$(addprefix $(PRJDIR)$(2)/arduino/,$(1)) \
354$(PRJDIR)$(2)/arduino/src/TensorFlowLite.h
355
356generate_$(2)_arduino_library_zip: generate_$(2)_arduino_project
357	cp -r $(PRJDIR)$(2)/arduino $(PRJDIR)$(2)/tensorflow_lite
358	python tensorflow/lite/micro/tools/make/fix_arduino_subfolders.py $(PRJDIR)$(2)/tensorflow_lite
359	@cd $(PRJDIR)$(2) && zip -q -r tensorflow_lite.zip tensorflow_lite
360
361ALL_PROJECT_TARGETS += $(if $(findstring _test,$(2)),,generate_$(2)_arduino_library_zip)
362
363    ARDUINO_LIBRARY_ZIPS += $(if $(findstring _mock,$(2)),,$(if $(findstring _test,$(2)),,$(PRJDIR)$(2)/tensorflow_lite.zip))
364
365endef
366
367# Creates a set of rules to build a standalone ESP-IDF project for an
368# executable, including all of the source and header files required in a
369# separate folder.
370# Arguments are:
371# 1 - Project file template names.
372# 2 - Name of executable.
373# 3 - List of C/C++ source files needed to build the TF Micro component.
374# 4 - List of C/C++ header files needed to build the TF Micro component.
375# 5 - List of C/C++ source files needed to build this particular project.
376# 6 - List of C/C++ header files needed to build this particular project.
377# 7 - Linker flags required.
378# 8 - C++ compilation flags needed.
379# 9 - C compilation flags needed.
380# 10 - List of includes.
381define generate_esp_project
382$(PRJDIR)$(2)/esp-idf/LICENSE: LICENSE
383	@mkdir -p $$(dir $$@)
384	@cp $$< $$@
385
386$(PRJDIR)$(2)/esp-idf/%: tensorflow/lite/micro/examples/$(2)/esp/%
387	@mkdir -p $$(dir $$@)
388	@cp $$< $$@
389
390$(PRJDIR)$(2)/esp-idf/main/%.cc: tensorflow/lite/micro/examples/$(2)/%.cc
391	@mkdir -p $$(dir $$@)
392	@python tensorflow/lite/micro/tools/make/transform_source.py \
393        --platform=esp \
394        --is_example_source \
395        --source_path="$$<" \
396        < $$< > $$@
397
398$(PRJDIR)$(2)/esp-idf/main/%.h: tensorflow/lite/micro/examples/$(2)/%.h
399	@mkdir -p $$(dir $$@)
400	@python tensorflow/lite/micro/tools/make/transform_source.py \
401        --platform=esp \
402        --is_example_source \
403        --source_path="$$<" \
404        < $$< > $$@
405
406$(PRJDIR)$(2)/esp-idf/main/%: tensorflow/lite/micro/examples/$(2)/%
407	@mkdir -p $$(dir $$@)
408	@cp $$< $$@
409
410$(PRJDIR)$(2)/esp-idf/components/tfmicro/%: % third_party_downloads
411	@mkdir -p $$(dir $$@)
412	@cp $$< $$@
413
414$(PRJDIR)$(2)/esp-idf/components/tfmicro/third_party/%: tensorflow/lite/micro/tools/make/downloads/% third_party_downloads
415	@mkdir -p $$(dir $$@)
416	@cp $$< $$@
417
418$(PRJDIR)$(2)/esp-idf/sdkconfig.defaults: tensorflow/lite/micro/examples/$(2)/esp/sdkconfig.defaults
419	@mkdir -p $$(dir $$@)
420	@cp $$< $$@
421
422$(PRJDIR)$(2)/esp-idf/%: tensorflow/lite/micro/tools/make/templates/esp/%.tpl
423# Split the sources into 2 components:
424# - Main component contains only the example's sources, relative from its dir.
425# - TFL Micro component contains everything but the example sources.
426  $(eval MAIN_SRCS := $(filter tensorflow/lite/micro/examples/%,$(5)))
427  $(eval MAIN_SRCS_RELATIVE := $(patsubst tensorflow/lite/micro/examples/$(2)/%,%,$(MAIN_SRCS)))
428  $(eval TFLM_SRCS := $(filter-out tensorflow/lite/micro/examples/%,$(5)) $(3))
429
430	@mkdir -p $$(dir $$@)
431	@sed -E 's#\%\{COMPONENT_SRCS\}\%#$(TFLM_SRCS)#g' $$< | \
432	sed -E 's#\%\{MAIN_SRCS\}\%#$(MAIN_SRCS_RELATIVE)#g' | \
433	sed -E 's#\%\{EXECUTABLE\}\%#$(2)#g' | \
434	sed -E 's#\%\{COMPONENT_INCLUDES\}\%#$(10)#g' | \
435	sed -E 's#\%\{LINKER_FLAGS\}\%#$(7)#g' | \
436	sed -E 's#\%\{CXX_FLAGS\}\%#$(8)#g' | \
437	sed -E 's#\%\{CC_FLAGS\}\%#$(9)#g' > $$@
438
439generate_$(2)_esp_project: \
440$(addprefix $(PRJDIR)$(2)/esp-idf/,\
441$(patsubst tensorflow/%,components/tfmicro/tensorflow/%,\
442$(patsubst third_party/%,components/tfmicro/third_party/%,\
443$(patsubst tensorflow/lite/micro/examples/$(2)/%,main/%,$(3) $(4) $(5) $(6))))) \
444$(addprefix $(PRJDIR)$(2)/esp-idf/,$(1))
445
446ALL_PROJECT_TARGETS += generate_$(2)_esp_project
447endef
448
449# Specialized version of generate_project for TF Lite Micro test targets that
450# automatically includes standard library files, so you just need to pass the
451# test name and any extra source files required.
452# Arguments are:
453# 1 - Name of test.
454# 2 - C/C++ source files implementing the test.
455# 3 - C/C++ header files needed for the test.
456# Calling eval on the output will create targets that you can invoke to
457# generate the standalone project.
458define generate_microlite_projects
459$(call generate_project,make,$(MAKE_PROJECT_FILES) $($(1)_MAKE_PROJECT_FILES),$(1),$(MICROLITE_CC_SRCS) $(THIRD_PARTY_CC_SRCS) $(MICROLITE_CC_KERNEL_SRCS) $(2),$(MICROLITE_CC_HDRS) $(THIRD_PARTY_CC_HDRS) $(MICROLITE_TEST_HDRS) $(3),$(LDFLAGS) $(MICROLITE_LIBS),$(CXXFLAGS) $(GENERATED_PROJECT_INCLUDES), $(CCFLAGS) $(GENERATED_PROJECT_INCLUDES),$(TARGET_TOOLCHAIN_ROOT),$(TARGET_TOOLCHAIN_PREFIX))
460$(call generate_arc_project,make,$(MAKE_PROJECT_FILES) $($(1)_MAKE_PROJECT_FILES),$(1),$(MICROLITE_CC_SRCS) $(THIRD_PARTY_CC_SRCS) $(MICROLITE_CC_KERNEL_SRCS) $(2),$(MICROLITE_CC_HDRS) $(THIRD_PARTY_CC_HDRS) $(MICROLITE_TEST_HDRS) $(3),$(LDFLAGS) $(GENERATED_PROJECT_LIBS),$(CXXFLAGS) $(GENERATED_PROJECT_INCLUDES), $(CCFLAGS) $(GENERATED_PROJECT_INCLUDES))
461$(call generate_ceva_bx1_project,make,$(MAKE_PROJECT_FILES) $($(1)_MAKE_PROJECT_FILES),$(1),$(MICROLITE_CC_SRCS) $(THIRD_PARTY_CC_SRCS) $(MICROLITE_CC_KERNEL_SRCS) $(2),$(MICROLITE_CC_HDRS) $(THIRD_PARTY_CC_HDRS) $(MICROLITE_TEST_HDRS) $(3),$(LDFLAGS) $(GENERATED_PROJECT_LIBS),$(CXXFLAGS) $(GENERATED_PROJECT_INCLUDES), $(CCFLAGS) $(GENERATED_PROJECT_INCLUDES))
462$(call generate_ceva_sp500_project,make,$(MAKE_PROJECT_FILES) $($(1)_MAKE_PROJECT_FILES),$(1),$(MICROLITE_CC_SRCS) $(THIRD_PARTY_CC_SRCS) $(MICROLITE_CC_KERNEL_SRCS) $(2),$(MICROLITE_CC_HDRS) $(THIRD_PARTY_CC_HDRS) $(MICROLITE_TEST_HDRS) $(3),$(LDFLAGS) $(GENERATED_PROJECT_LIBS),$(CXXFLAGS) $(GENERATED_PROJECT_INCLUDES), $(CCFLAGS) $(GENERATED_PROJECT_INCLUDES))
463$(call generate_project,mbed,$(MBED_PROJECT_FILES) $($(1)_MBED_PROJECT_FILES),$(1),$(MICROLITE_CC_SRCS) $(THIRD_PARTY_CC_SRCS) $(MICROLITE_CC_KERNEL_SRCS) $(2),$(MICROLITE_CC_HDRS) $(THIRD_PARTY_CC_HDRS) $(MICROLITE_TEST_HDRS) $(3),$(MICROLITE_LIBS),$(CXXFLAGS),$(CCFLAGS),$(TARGET_TOOLCHAIN_ROOT),$(TARGET_TOOLCHAIN_PREFIX))
464$(call generate_project,keil,$(KEIL_PROJECT_FILES) $($(1)_KEIL_PROJECT_FILES),$(1),$(MICROLITE_CC_SRCS) $(THIRD_PARTY_CC_SRCS) $(MICROLITE_CC_KERNEL_SRCS) $(2),$(MICROLITE_CC_HDRS) $(THIRD_PARTY_CC_HDRS) $(MICROLITE_TEST_HDRS) $(3),$(MICROLITE_LIBS),$(CXXFLAGS),$(CCFLAGS),$(TARGET_TOOLCHAIN_ROOT),$(TARGET_TOOLCHAIN_PREFIX))
465ifeq (,$(findstring _benchmark,$(1)))
466  $(call generate_arduino_project,$(ARDUINO_PROJECT_FILES) $($(1)_ARDUINO_PROJECT_FILES),$(1),$(MICROLITE_CC_SRCS) $(THIRD_PARTY_CC_SRCS) $(MICROLITE_CC_KERNEL_SRCS) $(2),$(MICROLITE_CC_HDRS) $(THIRD_PARTY_CC_HDRS) $(MICROLITE_TEST_HDRS) $(3),$(MICROLITE_LIBS),$(CXXFLAGS),$(CCFLAGS))
467endif
468$(call generate_esp_project,$(ESP_PROJECT_FILES) $($(1)_ESP_PROJECT_FILES),$(1),$(MICROLITE_CC_SRCS) $(THIRD_PARTY_CC_SRCS) $(MICROLITE_CC_KERNEL_SRCS),$(MICROLITE_CC_HDRS) $(THIRD_PARTY_CC_HDRS) $(MICROLITE_TEST_HDRS),$(2),$(3),$(MICROLITE_LIBS),$(CXXFLAGS),$(CCFLAGS),$(PROJECT_INCLUDES))
469endef
470
471# Handles the details of generating a binary target, including specializing
472# for the current platform, and generating project file targets.
473#
474# Note that while the function is called microlite_test, it is used for both
475# test and non-test binaries.
476
477# Files that end with _test are added as test targets (i.e. can be executed with
478# make test_<target>. ALl others can be executed with make run_<target>
479#
480# Arguments are:
481# 1 - Name of target.
482# 2 - C/C++ source files
483# 3 - C/C++ header files
484# 4 - if "exclude", then the non-test target will be excluded from
485#     MICROLITE_BUILD_TARGETS. This exception is needed because not all the
486#     microlite_test targets (e.g. the examples) are buildable on all platforms.
487# Calling eval on the output will create the targets that you need.
488define microlite_test
489ifeq (,$(findstring _test, $(1)))
490	$(eval $(call generate_project_third_party_parsing))
491endif
492
493$(1)_LOCAL_SRCS := $(2)
494$(1)_LOCAL_SRCS := $$(call specialize,$$($(1)_LOCAL_SRCS))
495ALL_SRCS += $$($(1)_LOCAL_SRCS)
496$(1)_LOCAL_HDRS := $(3)
497$(1)_LOCAL_OBJS := $$(addprefix $$(CORE_OBJDIR), \
498$$(patsubst %.S,%.o,$$(patsubst %.cc,%.o,$$(patsubst %.c,%.o,$$($(1)_LOCAL_SRCS)))))
499$(1)_BINARY := $$(BINDIR)$(1)
500$$($(1)_BINARY): $$($(1)_LOCAL_OBJS) $$(MICROLITE_LIB_PATH)
501	@mkdir -p $$(dir $$@)
502	$$(CXX) $$(CXXFLAGS) $$(INCLUDES) \
503	-o $$($(1)_BINARY) $$($(1)_LOCAL_OBJS) \
504	$$(MICROLITE_LIB_PATH) $$(LDFLAGS) $$(MICROLITE_LIBS)
505$(1): $$($(1)_BINARY)
506$(1)_bin: $$($(1)_BINARY).bin
507
508ifneq (,$(findstring _test,$(1)))
509  MICROLITE_TEST_TARGETS += test_$(1)
510  MICROLITE_BUILD_TARGETS += $$($(1)_BINARY)
511
512test_$(1): $$($(1)_BINARY)
513	$$(TEST_SCRIPT) $$($(1)_BINARY) $$(TEST_PASS_STRING) $$(TARGET)
514
515else
516  ifeq ($(findstring exclude,$(4)),)
517    MICROLITE_BUILD_TARGETS += $$($(1)_BINARY)
518  endif
519
520run_$(1): $$($(1)_BINARY)
521	$$(TEST_SCRIPT) $$($(1)_BINARY) non_test_binary $$(TARGET)
522endif
523
524$(eval $(call generate_microlite_projects,$(1),$(call specialize,$(2)),$(3)))
525endef
526
527# Adds a dependency for a third-party library that needs to be downloaded from
528# an external source.
529# Arguments are:
530# 1 - URL to download archive file from (can be .zip, .tgz, or .bz).
531# 2 - MD5 sum of archive, to check integrity. Use md5sum tool to generate.
532# 3 - Folder name to unpack library into, inside tf/l/x/m/t/downloads root.
533# 4 - Optional patching action, must match clause in download_and_extract.sh.
534# 5 - Optional patching action parameter
535# These arguments are packed into a single '!' separated string, so no element
536# can contain a '!'.
537define add_third_party_download
538THIRD_PARTY_DOWNLOADS += $(1)!$(2)!tensorflow/lite/micro/tools/make/downloads/$(3)!$(4)!$(5)
539endef
540
541# Unpacks an entry in a list of strings created by add_third_party_download, and
542# defines a dependency rule to download the library. The download_and_extract.sh
543# script is used to handle to downloading and unpacking.
544# 1 - Information about the library, separated by '!'s.
545define create_download_rule
546$(word 3, $(subst !, ,$(1))):
547	$(DOWNLOAD_SCRIPT) $(subst !, ,$(1))
548THIRD_PARTY_TARGETS += $(word 3, $(subst !, ,$(1)))
549endef
550
551# Recursively find all files of given pattern
552# Arguments are:
553# 1 - Starting path
554# 2 - File pattern, e.g: *.h
555recursive_find = $(wildcard $(1)$(2)) $(foreach dir,$(wildcard $(1)*),$(call recursive_find,$(dir)/,$(2)))
556
557
558# Modifies the Makefile to include all third party Srcs so that generate
559# projects will create a Makefile that can be immediatley compiled without
560# modification
561define generate_project_third_party_parsing
562
563ifeq ($$(PARSE_THIRD_PARTY), true)
564# Get generated src includes with update path to third party
565THIRD_PARTY_CC_SRCS += $$(filter $$(MAKEFILE_DIR)/downloads/%, $$(MICROLITE_CC_SRCS))
566MICROLITE_CC_SRCS := $$(filter-out $$(THIRD_PARTY_CC_SRCS), $$(MICROLITE_CC_SRCS))
567THIRD_PARTY_CC_SRCS :=  $$(sort $$(patsubst  $$(MAKEFILE_DIR)/downloads/%, third_party/%,  $$(THIRD_PARTY_CC_SRCS)))
568
569# Get generated project includes from the includes with update path to third_party
570GENERATED_PROJECT_INCLUDES += $$(filter -I$$(MAKEFILE_DIR)/downloads/%, $$(INCLUDES))
571GENERATED_PROJECT_INCLUDES := $$(patsubst  -I$$(MAKEFILE_DIR)/downloads/%, -Ithird_party/%,  $$(GENERATED_PROJECT_INCLUDES))
572GENERATED_PROJECT_INCLUDES += $$(filter -isystem$$(MAKEFILE_DIR)/downloads/%, $$(INCLUDES))
573GENERATED_PROJECT_INCLUDES := $$(sort $$(patsubst  -isystem$$(MAKEFILE_DIR)/downloads/%, -isystemthird_party/%,  $$(GENERATED_PROJECT_INCLUDES)))
574
575# We dont copy the libraries, we just want to make sure we link to them correctly.
576MICROLITE_LIBS :=  $$(sort $$(patsubst  $$(MAKEFILE_DIR)/downloads/%, $$(TENSORFLOW_ROOT)$$(MAKEFILE_DIR)/downloads/%, $$(MICROLITE_LIBS)))
577LDFLAGS :=   $$(sort $$(patsubst  $$(MAKEFILE_DIR)/downloads/%, $$(TENSORFLOW_ROOT)$$(MAKEFILE_DIR)/downloads/%, $$(LDFLAGS)))
578
579# Copy all third party headers that are mentioned in includes
580THIRD_PARTY_CC_HDRS += $$(filter $$(MAKEFILE_DIR)/downloads/%, $$(MICROLITE_CC_HDRS))
581MICROLITE_CC_HDRS:= $$(sort $$(filter-out $$(THIRD_PARTY_CC_HDRS), $$(MICROLITE_CC_HDRS)))
582THIRD_PARTY_CC_HDRS :=  $$(sort $$(patsubst  $$(MAKEFILE_DIR)/downloads/%, third_party/%,  $$(THIRD_PARTY_CC_HDRS)))
583
584# Copy all third party headers that are mentioned in includes
585INCLUDE_HDRS := $$(wildcard $$(addsuffix /*.h,$$(filter $$(MAKEFILE_DIR)/downloads/%, $$(patsubst -I%,%,$$(INCLUDES)))))
586INCLUDE_HDRS += $$(wildcard $$(addsuffix /*.h,$$(filter $$(MAKEFILE_DIR)/downloads/%,  $$(patsubst -isystem%,%,$$(INCLUDES)))))
587INCLUDE_HDRS :=  $$(sort $$(INCLUDE_HDRS))
588THIRD_PARTY_CC_HDRS += $ $$(sort $(patsubst  $$(MAKEFILE_DIR)/downloads/%, third_party/%,  $$(INCLUDE_HDRS)))
589endif
590
591endef
592