1 2# Reverses a space-separated list of words. 3reverse = $(if $(1),$(call reverse,$(wordlist 2,$(words $(1)),$(1)))) $(firstword $(1)) 4 5# Get macros only (i.e. the ones starting with -D) from two lists and remove duplicates 6getmacros = $(patsubst -D%,%,$(filter -D%,$(sort $(filter -D%, $(1)) $(filter -D%, $(2))))) 7 8# Look for platform or target-specific implementation files to replace reference 9# implementations with, given a tag. These are expected to occur in subfolders 10# of a directory where a reference implementation exists, and have the same 11# interface and header file. For example, 12# tensorflow/lite/micro/examples/micro_speech/audio_provider.cc 13# defines a module for supplying audio data, but since no platform or OS can be 14# presumed, it just always returns zeroes for its samples. The MacOS-specific 15# tensorflow/lite/micro/examples/micro_speech/osx/audio_provider.cc 16# has an implementation that relies on CoreAudio, and there are equivalent 17# versions for other operating systems. 18# The specific implementation yielded by the first tag in the list that produces 19# a match is returned, else the reference version if none of the tags produce a 20# match. 21# All lists of source files are put through this substitution process with the 22# tags of their target OS and architecture, so that implementations can be added 23# by simply placing them in the file tree, with no changes to the build files 24# needed. 25# One confusing thing about this implementation is that we're using wildcard to 26# act as a 'does file exist?' function, rather than expanding an expression. 27# Wildcard will return an empty string if given a plain file path with no actual 28# wildcards, if the file doesn't exist, so taking the first word of the list 29# between that and the reference path will pick the specialized one if it's 30# available. 31# Another fix is that originally if neither file existed(either the original or 32# a specialized version) this would return an empty string.Because this is 33# sometimes called on third party library files before they've been downloaded, 34# this caused mysterious errors, so an initial if conditional was added so that 35# specializations are only looked for if the original file exists. 36substitute_specialized_implementation = \ 37 $(if $(wildcard $(1)),$(firstword $(wildcard $(dir $(1))$(2)/$(notdir $(1))) $(wildcard $(1))),$(1)) 38substitute_specialized_implementations = \ 39 $(foreach source,$(1),$(call substitute_specialized_implementation,$(source),$(2))) 40# Here we're first looking for specialized implementations in ref_dir/$(TAG1) 41# and then ref_dir/$(TAG2), etc, before falling back to ref_dir's 42# implementation. 43# The argument to this function should be a list of space-separated file paths, 44# with any wildcards already expanded. 45define specialize_on_tags 46$(if $(2),$(call substitute_specialized_implementations,$(call specialize_on_tags,$(1),$(wordlist 2,$(words $(2)),$(2))),$(firstword $(2))),$(1)) 47endef 48# The entry point that most targets should use to find implementation-specific 49# versions of their source files. The only argument is a list of file paths. 50specialize = $(call specialize_on_tags,$(1),$(strip $(call reverse,$(ALL_TAGS)))) 51 52# TODO(b/143904317): It would be better to have the dependency be 53# THIRD_PARTY_TARGETS instead of third_party_downloads. However, that does not 54# quite work for the generate_project functions. 55# 56# Creates a set of rules to build a standalone makefile project for an 57# executable, including all of the source and header files required in a 58# separate folder and a simple makefile. 59# Arguments are: 60# 1 - Project type (make, mbed, etc). 61# 2 - Project file template name. 62# 3 - Name of executable. 63# 4 - List of C/C++ source files needed to build the target. 64# 5 - List of C/C++ header files needed to build the target. 65# 6 - Linker flags required. 66# 7 - C++ compilation flags needed. 67# 8 - C compilation flags needed. 68# Calling eval on the output will create a <Name>_makefile target that you 69# can invoke to create the standalone project. 70define generate_project 71$(PRJDIR)$(3)/$(1)/%: % third_party_downloads 72 @mkdir -p $$(dir $$@) 73 @cp $$< $$@ 74 75$(PRJDIR)$(3)/$(1)/third_party/%: tensorflow/lite/micro/tools/make/downloads/% third_party_downloads 76 @mkdir -p $$(dir $$@) 77 @cp $$< $$@ 78 79$(PRJDIR)$(3)/$(1)/%: tensorflow/lite/micro/tools/make/templates/%.tpl 80 @mkdir -p $$(dir $$@) 81 @sed -E 's#\%\{SRCS\}\%#$(4)#g' $$< | \ 82 sed -E 's#\%\{EXECUTABLE\}\%#$(3)#g' | \ 83 sed -E 's#\%\{LINKER_FLAGS\}\%#$(6)#g' | \ 84 sed -E 's#\%\{CXX_FLAGS\}\%#$(7)#g' | \ 85 sed -E 's#\%\{CC_FLAGS\}\%#$(8)#g' > $$@ 86 87$(PRJDIR)$(3)/$(1)/keil_project.uvprojx: tensorflow/lite/micro/tools/make/templates/keil_project.uvprojx.tpl 88 @mkdir -p $$(dir $$@) 89 @python tensorflow/lite/micro/tools/make/generate_keil_project.py \ 90 --input_template=$$< --output_file=$$@ --executable=$(3) \ 91 --srcs="$(4)" --hdrs="$(5)" --include_paths="$$(PROJECT_INCLUDES)" 92 93$(PRJDIR)$(3)/$(1)/.vscode/tasks.json : tensorflow/lite/micro/tools/make/templates/tasks.json.$(1).tpl 94 @mkdir -p $$(dir $$@) 95 @cp $$< $$@ 96 97generate_$(3)_$(1)_project: $(addprefix $(PRJDIR)$(3)/$(1)/, $(4) $(5) $(2)) 98ifeq (mbed, $(1)) 99 $(eval macrolist := $(call getmacros, $7, $8)) 100 $(eval jsonfilename := $(PRJDIR)$(3)/$(1)/mbed_app) 101 @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")}' \ 102 $(jsonfilename).json $(jsonfilename).json > $(jsonfilename).tmp && mv $(jsonfilename).tmp $(jsonfilename).json 103endif 104 105list_$(3)_$(1)_files: 106 @echo $(4) $(5) 107 108ALL_PROJECT_TARGETS += generate_$(3)_$(1)_project 109endef 110 111# Creates a set of rules to build a standalone makefile project for the ARC platform 112# including all of the source and header files required in a 113# separate folder and a simple makefile. 114# Arguments are: 115# 1 - Project type (make, mbed, etc). 116# 2 - Project file template name. 117# 3 - Name of executable. 118# 4 - List of C/C++ source files needed to build the target. 119# 5 - List of C/C++ header files needed to build the target. 120# 6 - Linker flags required. 121# 7 - C++ compilation flags needed. 122# 8 - C compilation flags needed. 123# Calling eval on the output will create a <Name>_makefile target that you 124# can invoke to create the standalone project. 125define generate_arc_project 126 127ifeq ($(TARGET_ARCH), arc) 128$(PRJDIR)$(3)/$(1)/Makefile: tensorflow/lite/micro/tools/make/templates/Makefile.tpl 129 @mkdir -p $$(dir $$@) 130 @sed -E 's#\%\{SRCS\}\%#$(4)#g' $$< | \ 131 sed -E '1 i\CC = ccac\nCXX = ccac\nLD = ccac\n' | \ 132 sed -E 's#\%\{EXECUTABLE\}\%#$(3).elf#g' | \ 133 sed -E 's#\%\{LINKER_FLAGS\}\%#$(6)#g' | \ 134 sed -E 's#\%\{CXX_FLAGS\}\%#$(7)#g' | \ 135 sed -E 's#\%\{CC_FLAGS\}\%#$(8)#g' > $$@ 136 137# Special rule to copy TCF in case the local filesystem file name has been defined 138ifneq ($(TCF_FILE_NAME), ) 139$(PRJDIR)$(3)/$(1)/$(TCF_FILE_NAME): $(TCF_FILE) 140 @cp $$< $$@ 141endif 142endif 143endef 144 145# Creates a set of rules to build a standalone Arduino project for an 146# executable, including all of the source and header files required in a 147# separate folder and a simple makefile. 148# Arguments are: 149# 1 - Project file template names. 150# 2 - Name of executable. 151# 3 - List of C/C++ source files needed to build the target. 152# 4 - List of C/C++ header files needed to build the target. 153# 5 - Linker flags required. 154# 6 - C++ compilation flags needed. 155# 7 - C compilation flags needed. 156# Calling eval on the output will create a <Name>_makefile target that you 157# can invoke to create the standalone project. 158define generate_arduino_project 159 160$(PRJDIR)$(2)/arduino/examples/%.cpp: tensorflow/lite/micro/examples/%.cc 161 @mkdir -p $$(dir $$@) 162 @python tensorflow/lite/micro/tools/make/transform_source.py \ 163 --platform=arduino \ 164 --is_example_source \ 165 --source_path="$$<" \ 166 --third_party_headers="$(4)" < $$< > $$@ 167 168$(PRJDIR)$(2)/arduino/examples/%.h: tensorflow/lite/micro/examples/%.h 169 @mkdir -p $$(dir $$@) 170 @python tensorflow/lite/micro/tools/make/transform_source.py \ 171 --platform=arduino \ 172 --is_example_source \ 173 --source_path="$$<" \ 174 --third_party_headers="$(4)" < $$< > $$@ 175 176$(PRJDIR)$(2)/arduino/examples/%/main.ino: tensorflow/lite/micro/examples/%/main_functions.cc 177 @mkdir -p $$(dir $$@) 178 @python tensorflow/lite/micro/tools/make/transform_source.py \ 179 --platform=arduino \ 180 --is_example_ino \ 181 --source_path="$$<" \ 182 --third_party_headers="$(4)" < $$< > $$@ 183 184$(PRJDIR)$(2)/arduino/src/%.cpp: %.cc 185 @mkdir -p $$(dir $$@) 186 @python tensorflow/lite/micro/tools/make/transform_source.py \ 187 --platform=arduino \ 188 --third_party_headers="$(4)" < $$< > $$@ 189 190$(PRJDIR)$(2)/arduino/src/%.h: %.h third_party_downloads 191 @mkdir -p $$(dir $$@) 192 @python tensorflow/lite/micro/tools/make/transform_source.py \ 193 --platform=arduino \ 194 --third_party_headers="$(4)" < $$< > $$@ 195 196$(PRJDIR)$(2)/arduino/LICENSE: LICENSE 197 @mkdir -p $$(dir $$@) 198 @cp $$< $$@ 199 200$(PRJDIR)$(2)/arduino/src/%: % third_party_downloads 201 @mkdir -p $$(dir $$@) 202 @python tensorflow/lite/micro/tools/make/transform_source.py \ 203 --platform=arduino \ 204 --third_party_headers="$(4)" < $$< > $$@ 205 206$(PRJDIR)$(2)/arduino/src/third_party/%: tensorflow/lite/micro/tools/make/downloads/% third_party_downloads 207 @mkdir -p $$(dir $$@) 208 @python tensorflow/lite/micro/tools/make/transform_source.py \ 209 --platform=arduino \ 210 --third_party_headers="$(4)" < $$< > $$@ 211 212$(PRJDIR)$(2)/arduino/src/third_party/%.cpp: tensorflow/lite/micro/tools/make/downloads/%.cc third_party_downloads 213 @mkdir -p $$(dir $$@) 214 @python tensorflow/lite/micro/tools/make/transform_source.py \ 215 --platform=arduino \ 216 --third_party_headers="$(4)" < $$< > $$@ 217 218$(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 219 @mkdir -p $$(dir $$@) 220 @python tensorflow/lite/micro/tools/make/transform_source.py \ 221 --platform=arduino \ 222 --third_party_headers="$(4)" < $$< | \ 223 sed -E 's/utility\.h/utility/g' > $$@ 224 225$(PRJDIR)$(2)/arduino/src/third_party/kissfft/kiss_fft.h: tensorflow/lite/micro/tools/make/downloads/kissfft/kiss_fft.h third_party_downloads 226 @mkdir -p $$(dir $$@) 227 @python tensorflow/lite/micro/tools/make/transform_source.py \ 228 --platform=arduino \ 229 --third_party_headers="$(4)" < $$< | \ 230 sed -E 's@#include <string.h>@//#include <string.h> /* Patched by helper_functions.inc for Arduino compatibility */@g' > $$@ 231 232$(PRJDIR)$(2)/arduino/%: tensorflow/lite/micro/tools/make/templates/% 233 @mkdir -p $$(dir $$@) 234 @sed -E 's#\%\{SRCS\}\%#$(3)#g' $$< | \ 235 sed -E 's#\%\{EXECUTABLE\}\%#$(2)#g' | \ 236 sed -E 's#\%\{LINKER_FLAGS\}\%#$(5)#g' | \ 237 sed -E 's#\%\{CXX_FLAGS\}\%#$(6)#g' | \ 238 sed -E 's#\%\{CC_FLAGS\}\%#$(7)#g' > $$@ 239 240$(PRJDIR)$(2)/arduino/examples/$(2)/$(2).ino: tensorflow/lite/micro/tools/make/templates/arduino_example.ino 241 @mkdir -p $$(dir $$@) 242 @cp $$< $$@ 243 244$(PRJDIR)$(2)/arduino/src/TensorFlowLite.h: tensorflow/lite/micro/tools/make/templates/TensorFlowLite.h 245 @mkdir -p $$(dir $$@) 246 @cp $$< $$@ 247 248# This would be cleaner if we broke up the list of dependencies into variables, 249# but these get hard to define with the evaluation approach used to define make 250# functions. 251generate_$(2)_arduino_project: \ 252$(addprefix $(PRJDIR)$(2)/arduino/, \ 253$(patsubst tensorflow/%,src/tensorflow/%,\ 254$(patsubst examples/%/main_functions.cpp,examples/%/main.ino,\ 255$(patsubst examples/%_test.cpp,examples/%_test.ino,\ 256$(patsubst tensorflow/lite/micro/examples/%,examples/%,\ 257$(patsubst third_party/%,src/third_party/%,\ 258$(patsubst %.cc,%.cpp,$(3)))))))) \ 259$(addprefix $(PRJDIR)$(2)/arduino/, \ 260$(patsubst tensorflow/%,src/tensorflow/%,\ 261$(patsubst tensorflow/lite/micro/examples/%,examples/%,\ 262$(patsubst third_party/%,src/third_party/%,$(4))))) \ 263$(addprefix $(PRJDIR)$(2)/arduino/,$(1)) \ 264$(PRJDIR)$(2)/arduino/src/TensorFlowLite.h 265 266generate_$(2)_arduino_library_zip: generate_$(2)_arduino_project 267 cp -r $(PRJDIR)$(2)/arduino $(PRJDIR)$(2)/tensorflow_lite 268 python tensorflow/lite/micro/tools/make/fix_arduino_subfolders.py $(PRJDIR)$(2)/tensorflow_lite 269 @cd $(PRJDIR)$(2) && zip -q -r tensorflow_lite.zip tensorflow_lite 270 271ALL_PROJECT_TARGETS += $(if $(findstring _test,$(2)),,generate_$(2)_arduino_library_zip) 272 273 ARDUINO_LIBRARY_ZIPS += $(if $(findstring _mock,$(2)),,$(if $(findstring _test,$(2)),,$(PRJDIR)$(2)/tensorflow_lite.zip)) 274 275endef 276 277# Creates a set of rules to build a standalone ESP-IDF project for an 278# executable, including all of the source and header files required in a 279# separate folder. 280# Arguments are: 281# 1 - Project file template names. 282# 2 - Name of executable. 283# 3 - List of C/C++ source files needed to build the TF Micro component. 284# 4 - List of C/C++ header files needed to build the TF Micro component. 285# 5 - List of C/C++ source files needed to build this particular project. 286# 6 - List of C/C++ header files needed to build this particular project. 287# 7 - Linker flags required. 288# 8 - C++ compilation flags needed. 289# 9 - C compilation flags needed. 290# 10 - List of includes. 291define generate_esp_project 292$(PRJDIR)$(2)/esp-idf/LICENSE: LICENSE 293 @mkdir -p $$(dir $$@) 294 @cp $$< $$@ 295 296$(PRJDIR)$(2)/esp-idf/main/%.cc: tensorflow/lite/micro/examples/$(2)/%.cc 297 @mkdir -p $$(dir $$@) 298 @python tensorflow/lite/micro/tools/make/transform_source.py \ 299 --platform=esp \ 300 --is_example_source \ 301 --source_path="$$<" \ 302 < $$< > $$@ 303 304$(PRJDIR)$(2)/esp-idf/main/%: tensorflow/lite/micro/examples/$(2)/% 305 @mkdir -p $$(dir $$@) 306 @cp $$< $$@ 307 308$(PRJDIR)$(2)/esp-idf/components/tfmicro/%: % third_party_downloads 309 @mkdir -p $$(dir $$@) 310 @cp $$< $$@ 311 312$(PRJDIR)$(2)/esp-idf/components/tfmicro/third_party/%: tensorflow/lite/micro/tools/make/downloads/% third_party_downloads 313 @mkdir -p $$(dir $$@) 314 @cp $$< $$@ 315 316$(PRJDIR)$(2)/esp-idf/%: tensorflow/lite/micro/tools/make/templates/esp/%.tpl 317 $(eval MAIN_SRCS_RELATIVE := $(patsubst tensorflow/lite/micro/examples/$(2)/%,%,$(5))) 318 319 @mkdir -p $$(dir $$@) 320 @sed -E 's#\%\{COMPONENT_SRCS\}\%#$(3)#g' $$< | \ 321 sed -E 's#\%\{MAIN_SRCS\}\%#$(MAIN_SRCS_RELATIVE)#g' | \ 322 sed -E 's#\%\{EXECUTABLE\}\%#$(2)#g' | \ 323 sed -E 's#\%\{COMPONENT_INCLUDES\}\%#$(10)#g' | \ 324 sed -E 's#\%\{LINKER_FLAGS\}\%#$(7)#g' | \ 325 sed -E 's#\%\{CXX_FLAGS\}\%#$(8)#g' | \ 326 sed -E 's#\%\{CC_FLAGS\}\%#$(9)#g' > $$@ 327 328generate_$(2)_esp_project: \ 329$(addprefix $(PRJDIR)$(2)/esp-idf/,\ 330$(patsubst tensorflow/%,components/tfmicro/tensorflow/%,\ 331$(patsubst third_party/%,components/tfmicro/third_party/%,\ 332$(patsubst tensorflow/lite/micro/examples/$(2)/%,main/%,$(3) $(4) $(5) $(6))))) \ 333$(addprefix $(PRJDIR)$(2)/esp-idf/,$(1)) 334 335ALL_PROJECT_TARGETS += generate_$(2)_esp_project 336endef 337 338# Specialized version of generate_project for TF Lite Micro test targets that 339# automatically includes standard library files, so you just need to pass the 340# test name and any extra source files required. 341# Arguments are: 342# 1 - Name of test. 343# 2 - C/C++ source files implementing the test. 344# 3 - C/C++ header files needed for the test. 345# Calling eval on the output will create targets that you can invoke to 346# generate the standalone project. 347define generate_microlite_projects 348$(call generate_project,make,$(MAKE_PROJECT_FILES),$(1),$(MICROLITE_CC_SRCS) $(THIRD_PARTY_CC_SRCS) $(2),$(MICROLITE_CC_HDRS) $(THIRD_PARTY_CC_HDRS) $(MICROLITE_TEST_HDRS) $(3),$(LDFLAGS) $(MICROLITE_LIBS),$(CXXFLAGS) $(GENERATED_PROJECT_INCLUDES), $(CCFLAGS) $(GENERATED_PROJECT_INCLUDES)) 349$(call generate_arc_project,make,$(MAKE_PROJECT_FILES),$(1),$(MICROLITE_CC_SRCS) $(THIRD_PARTY_CC_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)) 350$(call generate_project,mbed,$(MBED_PROJECT_FILES),$(1),$(MICROLITE_CC_SRCS) $(THIRD_PARTY_CC_SRCS) $(2),$(MICROLITE_CC_HDRS) $(THIRD_PARTY_CC_HDRS) $(MICROLITE_TEST_HDRS) $(3),$(MICROLITE_LIBS),$(CXXFLAGS),$(CCFLAGS)) 351$(call generate_project,keil,$(KEIL_PROJECT_FILES),$(1),$(MICROLITE_CC_SRCS) $(THIRD_PARTY_CC_SRCS) $(2),$(MICROLITE_CC_HDRS) $(THIRD_PARTY_CC_HDRS) $(MICROLITE_TEST_HDRS) $(3),$(MICROLITE_LIBS),$(CXXFLAGS),$(CCFLAGS)) 352$(call generate_arduino_project,$(ARDUINO_PROJECT_FILES),$(1),$(MICROLITE_CC_SRCS) $(THIRD_PARTY_CC_SRCS) $(2),$(MICROLITE_CC_HDRS) $(THIRD_PARTY_CC_HDRS) $(MICROLITE_TEST_HDRS) $(3),$(MICROLITE_LIBS),$(CXXFLAGS),$(CCFLAGS)) 353$(call generate_esp_project,$(ESP_PROJECT_FILES),$(1),$(MICROLITE_CC_SRCS) $(THIRD_PARTY_CC_SRCS),$(MICROLITE_CC_HDRS) $(THIRD_PARTY_CC_HDRS) $(MICROLITE_TEST_HDRS),$(2),$(3),$(MICROLITE_LIBS),$(CXXFLAGS),$(CCFLAGS),$(PROJECT_INCLUDES)) 354endef 355 356# Handles the details of generating a binary target, including specializing 357# for the current platform, and generating project file targets. 358# Arguments are: 359# 1 - Name of test. 360# 2 - C/C++ source files implementing the test. 361# 3 - C/C++ header files needed for the test. 362# Calling eval on the output will create the targets that you need. 363define microlite_test 364$(1)_LOCAL_SRCS := $(2) 365$(1)_LOCAL_SRCS := $$(call specialize,$$($(1)_LOCAL_SRCS)) 366ALL_SRCS += $$($(1)_LOCAL_SRCS) 367$(1)_LOCAL_HDRS := $(3) 368$(1)_LOCAL_OBJS := $$(addprefix $$(OBJDIR), \ 369$$(patsubst %.cc,%.o,$$(patsubst %.c,%.o,$$($(1)_LOCAL_SRCS)))) 370$(1)_BINARY := $$(BINDIR)$(1) 371$$($(1)_BINARY): $$($(1)_LOCAL_OBJS) $$(MICROLITE_LIB_PATH) 372 @mkdir -p $$(dir $$@) 373 $$(CXX) $$(CXXFLAGS) $$(INCLUDES) \ 374 -o $$($(1)_BINARY) $$($(1)_LOCAL_OBJS) \ 375 $$(LIBFLAGS) $$(MICROLITE_LIB_PATH) $$(LDFLAGS) $$(MICROLITE_LIBS) 376$(1): $$($(1)_BINARY) 377$(1)_bin: $$($(1)_BINARY).bin 378test_$(1): $$($(1)_BINARY) 379 @test -f $$(TEST_SCRIPT) || (echo 'Unable to find the test script. Is the software emulation available in $$(TARGET)?'; exit 1) 380 $$(TEST_SCRIPT) $$($(1)_BINARY) '~~~ALL TESTS PASSED~~~' 381ifneq (,$(findstring _test,$(1))) 382 MICROLITE_TEST_TARGETS += test_$(1) 383endif 384$(eval $(call generate_microlite_projects,$(1),$(call specialize,$(2)),$(3))) 385endef 386 387# Adds a dependency for a third-party library that needs to be downloaded from 388# an external source. 389# Arguments are: 390# 1 - URL to download archive file from (can be .zip, .tgz, or .bz). 391# 2 - MD5 sum of archive, to check integrity. Use md5sum tool to generate. 392# 3 - Folder name to unpack library into, inside tf/l/x/m/t/downloads root. 393# 4 - Optional patching action, must match clause in download_and_extract.sh. 394# 5 - Optional patching action parameter 395# These arguments are packed into a single '!' separated string, so no element 396# can contain a '!'. 397define add_third_party_download 398THIRD_PARTY_DOWNLOADS += $(1)!$(2)!tensorflow/lite/micro/tools/make/downloads/$(3)!$(4)!$(5) 399endef 400 401# Unpacks an entry in a list of strings created by add_third_party_download, and 402# defines a dependency rule to download the library. The download_and_extract.sh 403# script is used to handle to downloading and unpacking. 404# 1 - Information about the library, separated by '!'s. 405define create_download_rule 406$(word 3, $(subst !, ,$(1))): 407 tensorflow/lite/micro/tools/make/download_and_extract.sh $(subst !, ,$(1)) 408THIRD_PARTY_TARGETS += $(word 3, $(subst !, ,$(1))) 409endef 410 411# Recursively find all files of given pattern 412# Arguments are: 413# 1 - Starting path 414# 2 - File pattern, e.g: *.h 415recursive_find = $(wildcard $(1)$(2)) $(foreach dir,$(wildcard $(1)*),$(call recursive_find,$(dir)/,$(2))) 416