Current section
Files
Jump to
Current section
Files
tflite_beam
Makefile
Makefile
SOURCE_PRIV_DIR = $(shell pwd)/priv
# Mix does not export MIX_APP_PATH when it builds a rebar3 dependency, but it does
# point REBAR_BARE_COMPILER_OUTPUT_DIR at _build/<target>_<env>/lib/tflite_beam.
# Using it keeps the artifacts of each MIX_TARGET apart, instead of having every
# target overwrite the same deps/tflite_beam/priv.
ifndef MIX_APP_PATH
ifdef REBAR_BARE_COMPILER_OUTPUT_DIR
MIX_APP_PATH=$(REBAR_BARE_COMPILER_OUTPUT_DIR)
endif
endif
ifndef MIX_APP_PATH
MIX_APP_PATH=$(shell pwd)/_build/default/lib/tflite_beam
PRIV_DIR=$(SOURCE_PRIV_DIR)
LIBUSB_INSTALL_DIR=$(shell pwd)/libusb
else
PRIV_DIR = $(MIX_APP_PATH)/priv
LIBUSB_INSTALL_DIR = $(MIX_APP_PATH)/libusb
endif
NATIVE_BINDINGS_SO = $(PRIV_DIR)/tflite_beam.so
LIBEDGETPU_RUNTIME_PRIV = $(PRIV_DIR)/libedgetpu
TFLITE_BEAM_CORAL_SUPPORT ?= "true"
TFLITE_BEAM_CORAL_LIBEDGETPU_RUNTIME ?= "native"
TFLITE_BEAM_PREFER_PRECOMPILED ?= "true"
TFLITE_BEAM_CORAL_LIBEDGETPU_URL ?= "native"
SCRIPTS_DIR = $(shell pwd)/scripts
C_SRC = $(shell pwd)/c_src
LIB_SRC = $(shell pwd)/lib
LIBCORAL_SRC = $(shell pwd)/c_src/libcoral
PRECOMPILED_ERL_HELPER = $(shell pwd)/tflite_beam_precompiled.erl
UNICODEDATA = $(shell pwd)/unicodedata
UNICODE_DATA = $(PRIV_DIR)/unicode_data.txt
FLATC_PATH ?= $(shell which flatc)
TFLITE_HOST_TOOLS_DIR = $(patsubst %/,%,$(dir $(FLATC_PATH)))
ifdef CMAKE_TOOLCHAIN_FILE
CMAKE_CONFIGURE_FLAGS=-D CMAKE_TOOLCHAIN_FILE="$(CMAKE_TOOLCHAIN_FILE)"
endif
# Tensorflow
TFLITE_USE_GIT_HEAD ?= false
TFLITE_GIT_REPO ?= "https://github.com/tensorflow/tensorflow.git"
# The runtime comes from LiteRT's tflite subtree. LITERT_VER is therefore the
# version a delegate plugin has to match, and it is what tflite_beam:tflite_version/0
# answers.
LITERT_GIT_REPO ?= "https://github.com/google-ai-edge/LiteRT.git"
LITERT_VER ?= 2.2.0
# TensorFlow is still a build dependency rather than the source of the runtime:
# LiteRT's CMake reaches into it for compiler/mlir/lite, TSL and XLA. The version
# is the one LiteRT pins, and mismatching it silently mixes two schemas.
TFLITE_VER ?= 2.21.0-rc0
TFLITE_VER_V = v$(TFLITE_VER)
ifneq ($(TFLITE_USE_GIT_HEAD), false)
TFLITE_VER_V=$(TFLITE_USE_GIT_BRANCH)
endif
THIRD_PARTY_DIR = $(shell pwd)/3rd_party
TFLITE_BEAM_CACHE_DIR = $(THIRD_PARTY_DIR)/cache
TFLITE_SOURCE_URL = "https://github.com/tensorflow/tensorflow/archive/refs/tags/$(TFLITE_VER_V).zip"
TFLITE_SOURCE_ZIP = $(TFLITE_BEAM_CACHE_DIR)/tensorflow-$(TFLITE_VER_V).zip
UNZIP_TARGET_DIR = $(THIRD_PARTY_DIR)/tensorflow
TENSORFLOW_ROOT_DIR = $(UNZIP_TARGET_DIR)/tensorflow-$(TFLITE_VER)
LITERT_VER_V = v$(LITERT_VER)
LITERT_SOURCE_URL = "https://github.com/google-ai-edge/LiteRT/archive/refs/tags/$(LITERT_VER_V).zip"
LITERT_SOURCE_ZIP = $(TFLITE_BEAM_CACHE_DIR)/litert-$(LITERT_VER_V).zip
LITERT_UNZIP_TARGET_DIR = $(THIRD_PARTY_DIR)/litert
LITERT_ROOT_DIR = $(LITERT_UNZIP_TARGET_DIR)/LiteRT-$(LITERT_VER)
TFLITE_ROOT_DIR = $(LITERT_ROOT_DIR)/tflite
GFLAGS_ROOT_DIR = $(THIRD_PARTY_DIR)/gflags
GLOG_ROOT_DIR = $(THIRD_PARTY_DIR)/glog
TFLITE_CMAKELISTS_TXT = $(TFLITE_ROOT_DIR)/CMakeLists.txt
CMAKE_TFLITE_BUILD_DIR = $(MIX_APP_PATH)/cmake_tflite_$(TFLITE_VER)
# KleidiAI is fetched by XNNPACK for arm64 targets, but gitlab.arm.com blocks
# GitHub runners. Mirror the commit XNNPACK pins (matches this TFLITE_VER) from
# github.com and hand the local copy to XNNPACK via KLEIDIAI_SOURCE_DIR.
KLEIDIAI_COMMIT ?= dce86647385ab2638aa5abebcb652f3e4271970d
KLEIDIAI_SOURCE_URL = https://github.com/ARM-software/kleidiai/archive/$(KLEIDIAI_COMMIT).tar.gz
KLEIDIAI_SOURCE_ARCHIVE = $(TFLITE_BEAM_CACHE_DIR)/kleidiai-$(KLEIDIAI_COMMIT).tar.gz
KLEIDIAI_SOURCE_DIR = $(THIRD_PARTY_DIR)/kleidiai-$(KLEIDIAI_COMMIT)
ifdef TARGET_ARCH
KLEIDIAI_TARGET_ARCH = $(TARGET_ARCH)
else
KLEIDIAI_TARGET_ARCH = $(shell uname -m)
endif
KLEIDIAI_NEEDED = $(filter arm64 aarch64,$(KLEIDIAI_TARGET_ARCH))
LIBUSB_VERSION = 1.0.27
LIBUSB_SOURCE_URL = https://github.com/libusb/libusb/releases/download/v$(LIBUSB_VERSION)/libusb-$(LIBUSB_VERSION).tar.bz2
LIBUSB_SOURCE_ARCHIVE = $(TFLITE_BEAM_CACHE_DIR)/libusb-$(LIBUSB_VERSION).tar.bz2
LIBUSB_SOURCE_DIR = $(THIRD_PARTY_DIR)/libusb-$(LIBUSB_VERSION)
LIBUSB_SHARED_LIBRARY = $(PRIV_DIR)/libedgetpu/libusb-1.0.0.dylib
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S),Darwin)
NPROC = $(shell sysctl -n hw.ncpu)
else
NPROC = $(shell nproc)
endif
ifneq ($(UNAME_S),Darwin)
LIBUSB_SHARED_LIBRARY = $(PRIV_DIR)/libedgetpu/libusb-1.0.so.0.4.0
endif
ifeq ($(TARGET_OS),linux)
LIBUSB_SHARED_LIBRARY = $(PRIV_DIR)/libedgetpu/libusb-1.0.so.0.4.0
endif
TFLITE_BEAM_CORAL_USB_THROTTLE ?= true
TFLITE_BEAM_CORAL_LIBEDGETPU_TRIPLET ?= native
TFLITE_BEAM_CORAL_LIBEDGETPU_UNZIPPED_DIR = $(TFLITE_BEAM_CACHE_DIR)/$(TFLITE_BEAM_CORAL_LIBEDGETPU_RUNTIME)
CMAKE_TFLITE_OPTIONS ?= ""
CMAKE_OPTIONS ?= $(CMAKE_TFLITE_OPTIONS)
CMAKE_OPTIONS += $(CMAKE_CONFIGURE_FLAGS)
ifneq ($(KLEIDIAI_NEEDED),)
CMAKE_OPTIONS += -D KLEIDIAI_SOURCE_DIR="$(KLEIDIAI_SOURCE_DIR)"
endif
# bindings
CMAKE_BINDINGS_BUILD_DIR = $(MIX_APP_PATH)/cmake_tflite_beam
MAKE_BUILD_FLAGS ?= auto
.DEFAULT_GLOBAL := build
build: $(NATIVE_BINDINGS_SO) fix_libusb
# Before running us, Mix links a dependency's source priv into the _build target it
# is compiling for -- as a symlink when that directory is absent, but by copying the
# contents in when it already exists. Either way the artifacts of one target leak
# into another, so a source priv means this target's priv cannot be trusted and is
# rebuilt from scratch. Has to be phony: a symlink makes the directory look like it
# already exists, so a directory target would never run.
.PHONY: prepare_priv_dir
prepare_priv_dir:
@ if [ "$(PRIV_DIR)" != "$(SOURCE_PRIV_DIR)" ]; then \
if [ -e "$(SOURCE_PRIV_DIR)" ]; then \
rm -rf "$(SOURCE_PRIV_DIR)" "$(PRIV_DIR)" ; \
elif [ -L "$(PRIV_DIR)" ]; then \
rm -f "$(PRIV_DIR)" ; \
fi ; \
fi ; \
mkdir -p "$(PRIV_DIR)"
create_cache_dir:
@ mkdir -p "$(TFLITE_BEAM_CACHE_DIR)"
$(TFLITE_SOURCE_ZIP): create_cache_dir
@ if [ "$(TFLITE_BEAM_PREFER_PRECOMPILED)" != "true" ]; then \
if [ "$(TFLITE_USE_GIT_HEAD)" = "false" ] && [ ! -e "$(TFLITE_SOURCE_ZIP)" ]; then \
if [ -e "$(shell which curl)" ]; then \
curl -fSL "$(TFLITE_SOURCE_URL)" -o $(TFLITE_SOURCE_ZIP) ; \
elif [ -e "$(shell which wget)" ]; then \
wget "$(TFLITE_SOURCE_URL)" -O $(TFLITE_SOURCE_ZIP) ; \
else \
echo "cannot find curl or wget, cannot download tensorflow source code" ; \
exit 1 ; \
fi \
fi \
fi
unarchive_source_code: $(TFLITE_SOURCE_ZIP)
@ if [ "$(TFLITE_BEAM_PREFER_PRECOMPILED)" != "true" ]; then \
if [ ! -d "$(TENSORFLOW_ROOT_DIR)" ]; then \
rm -rf "$(TENSORFLOW_ROOT_DIR)" ; \
mkdir -p "$(UNZIP_TARGET_DIR)" ; \
if [ "$(TFLITE_USE_GIT_HEAD)" = "false" ]; then \
unzip -qq -o "$(TFLITE_SOURCE_ZIP)" -d "$(UNZIP_TARGET_DIR)" ; \
else \
git clone --branch=$(TFLITE_USE_GIT_BRANCH) --depth=1 $(TFLITE_GIT_REPO) "$(TENSORFLOW_ROOT_DIR)" ; \
fi \
fi \
fi
$(LITERT_SOURCE_ZIP): create_cache_dir
@ if [ "$(TFLITE_BEAM_PREFER_PRECOMPILED)" != "true" ]; then \
if [ ! -e "$(LITERT_SOURCE_ZIP)" ]; then \
if [ -e "$(shell which curl)" ]; then \
curl -fSL "$(LITERT_SOURCE_URL)" -o $(LITERT_SOURCE_ZIP) ; \
elif [ -e "$(shell which wget)" ]; then \
wget "$(LITERT_SOURCE_URL)" -O $(LITERT_SOURCE_ZIP) ; \
else \
echo "cannot find curl or wget, cannot download LiteRT source code" ; \
exit 1 ; \
fi \
fi \
fi
unarchive_litert_source_code: $(LITERT_SOURCE_ZIP)
@ if [ "$(TFLITE_BEAM_PREFER_PRECOMPILED)" != "true" ]; then \
if [ ! -d "$(LITERT_ROOT_DIR)" ]; then \
rm -rf "$(LITERT_ROOT_DIR)" ; \
mkdir -p "$(LITERT_UNZIP_TARGET_DIR)" ; \
unzip -qq -o "$(LITERT_SOURCE_ZIP)" -d "$(LITERT_UNZIP_TARGET_DIR)" ; \
fi ; \
if [ ! -e "$(TFLITE_CMAKELISTS_TXT)" ]; then \
echo "no CMakeLists.txt at $(TFLITE_CMAKELISTS_TXT); is LITERT_VER=$(LITERT_VER) right?" ; \
exit 1 ; \
fi \
fi
install_libedgetpu_runtime: prepare_priv_dir
@ if [ "$(TFLITE_BEAM_CORAL_SUPPORT)" = "true" ]; then \
bash scripts/copy_libedgetpu_runtime.sh "$(LIBEDGETPU_RUNTIME_PRIV)" "$(TFLITE_BEAM_CORAL_LIBEDGETPU_UNZIPPED_DIR)" "$(TFLITE_BEAM_CORAL_LIBEDGETPU_TRIPLET)" "$(TFLITE_BEAM_CORAL_USB_THROTTLE)" "$(TFLITE_BEAM_CORAL_LIBEDGETPU_URL)" "$(TFLITE_BEAM_CORAL_LIBEDGETPU_RUNTIME)" "$(TFLITE_BEAM_CACHE_DIR)" && \
if [ "$(TFLITE_BEAM_PREFER_PRECOMPILED)" != "true" ]; then \
if [ ! -e "$(LIBCORAL_SRC)/Makefile" ]; then \
rm -rf "$(LIBCORAL_SRC)" && \
git clone --depth 1 https://github.com/cocoa-xu/libcoral.git "$(LIBCORAL_SRC)" ; \
fi && \
cd "$(LIBCORAL_SRC)" && git submodule update --init libedgetpu && cd ../.. && \
python3 "$(shell pwd)/scripts/retarget_includes_to_litert.py" "$(LIBCORAL_SRC)" ; \
fi \
fi
libusb: create_cache_dir prepare_priv_dir
@ if [ "$(TFLITE_BEAM_PREFER_PRECOMPILED)" != "true" ]; then \
if [ "$(TFLITE_BEAM_CORAL_SUPPORT)" = "true" ]; then \
echo "LIBUSB_SHARED_LIBRARY: $(LIBUSB_SHARED_LIBRARY)" ; \
if [ ! -e "$(LIBUSB_SHARED_LIBRARY)" ]; then \
mkdir -p "$(LIBUSB_INSTALL_DIR)" ; \
bash scripts/build_libusb.sh "$(LIBUSB_SOURCE_URL)" "$(LIBUSB_SOURCE_ARCHIVE)" "$(THIRD_PARTY_DIR)" "$(LIBUSB_SOURCE_DIR)" "$(LIBUSB_INSTALL_DIR)" "$(PRIV_DIR)" ; \
fi \
fi \
fi
$(UNICODE_DATA): prepare_priv_dir
@ if [ ! -e "$(UNICODE_DATA)" ]; then \
cp -f "$(UNICODEDATA)/unicode_data.txt" "$(UNICODE_DATA)" ; \
fi
$(NATIVE_BINDINGS_SO): $(UNICODE_DATA) unarchive_source_code unarchive_litert_source_code install_libedgetpu_runtime libusb fetch_kleidiai
@ if [ "$(TFLITE_BEAM_PREFER_PRECOMPILED)" = "true" ]; then \
{ \
cd "$(shell pwd)" && \
mkdir -p "$(MIX_APP_PATH)" && \
erlc -o "$(MIX_APP_PATH)" "$(PRECOMPILED_ERL_HELPER)" && \
TFLITE_BEAM_PRIV_DIR="$(PRIV_DIR)" erl -noshell -pa "$(MIX_APP_PATH)" -s tflite_beam_precompiled install_precompiled_binary_if_available -s init stop ; } || \
{ \
$(TFLITE_BEAM_MAKE) TFLITE_BEAM_PREFER_PRECOMPILED=false ; } ; \
fi && \
if [ ! -e "$(NATIVE_BINDINGS_SO)" ]; then \
echo "CORAL SUPPORT: $(TFLITE_BEAM_CORAL_SUPPORT)" ; \
echo "LIBEDGETPU runtime: $(TFLITE_BEAM_CORAL_LIBEDGETPU_RUNTIME)" ; \
echo "Throttle USB Coral Devices: $(TFLITE_BEAM_CORAL_USB_THROTTLE)" ; \
if [ ! -e "3rd_party/gflags/CMakeLists.txt" ]; then \
rm -rf 3rd_party/gflags && \
git clone --depth 1 https://github.com/gflags/gflags.git 3rd_party/gflags ; \
fi && \
if [ ! -e "3rd_party/glog/CMakeLists.txt" ]; then \
rm -rf 3rd_party/glog && \
git clone --depth 1 https://github.com/google/glog.git 3rd_party/glog ; \
fi && \
mkdir -p $(CMAKE_BINDINGS_BUILD_DIR) && \
python3 "$(shell pwd)/patches/apply_patch.py" "$(TENSORFLOW_ROOT_DIR)" "$(TFLITE_VER)" "$(THIRD_PARTY_DIR)" && \
cd "$(CMAKE_BINDINGS_BUILD_DIR)" && \
cmake -D C_SRC="$(C_SRC)" \
-D PRIV_DIR="$(PRIV_DIR)" \
-D ERTS_INCLUDE_DIR="$(ERTS_INCLUDE_DIR)" \
-D TFLITE_ROOT_DIR="$(TFLITE_ROOT_DIR)" \
-D TENSORFLOW_SOURCE_DIR="$(TENSORFLOW_ROOT_DIR)" \
-D GFLAGS_ROOT_DIR="$(GFLAGS_ROOT_DIR)" \
-D GLOG_ROOT_DIR="$(GLOG_ROOT_DIR)" \
-D TFLITE_BEAM_CORAL_SUPPORT="$(TFLITE_BEAM_CORAL_SUPPORT)" \
-D TFLITE_BEAM_TFLITE_VERSION="$(TFLITE_VER)" \
-D TFLITE_BEAM_LITERT_VERSION="$(LITERT_VER)" \
-D TFLITE_HOST_TOOLS_DIR="$(TFLITE_HOST_TOOLS_DIR)" \
-D LIBUSB_INSTALL_DIR="$(LIBUSB_INSTALL_DIR)" \
-D MIX_APP_PATH="$(MIX_APP_PATH)" \
$(CMAKE_OPTIONS) \
"$(shell pwd)" && \
if [ "$(MAKE_BUILD_FLAGS)" = "auto" ]; then \
make "-j$(NPROC)" ; \
else \
make "$(MAKE_BUILD_FLAGS)" ; \
fi && \
mkdir -p "$(PRIV_DIR)" && \
cp "$(CMAKE_BINDINGS_BUILD_DIR)/tflite_beam.so" "$(NATIVE_BINDINGS_SO)" ; \
fi
fix_libusb:
@ bash scripts/macos_libusb_rpath.sh "$(NATIVE_BINDINGS_SO)"
fetch_kleidiai: create_cache_dir
@ if [ "$(TFLITE_BEAM_PREFER_PRECOMPILED)" != "true" ] && [ -n "$(KLEIDIAI_NEEDED)" ]; then \
if [ ! -e "$(KLEIDIAI_SOURCE_DIR)/CMakeLists.txt" ]; then \
echo "Fetching KleidiAI $(KLEIDIAI_COMMIT) from GitHub mirror" ; \
rm -rf "$(KLEIDIAI_SOURCE_DIR)" ; \
mkdir -p "$(KLEIDIAI_SOURCE_DIR)" ; \
curl -fSL "$(KLEIDIAI_SOURCE_URL)" -o "$(KLEIDIAI_SOURCE_ARCHIVE)" && \
tar -xzf "$(KLEIDIAI_SOURCE_ARCHIVE)" -C "$(KLEIDIAI_SOURCE_DIR)" --strip-components=1 ; \
fi \
fi