Skip to content

Commit

Permalink
RSDK-6865 android ML and streaming libraries (viamrobotics#3889)
Browse files Browse the repository at this point in the history
Co-authored-by: Eric Daniels <[email protected]>
  • Loading branch information
abe-winter and edaniels authored May 3, 2024
1 parent 2e97f5e commit 04de2fd
Show file tree
Hide file tree
Showing 31 changed files with 319 additions and 38 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/droid.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ env:

jobs:
droid-build:
# temporarily disabled while we port the new android build
if: ${{ false }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,7 @@ etc/FFmpeg

# qemu core dumps
web/cmd/server/*.core

# gomobile / android
*.aar
*.jar
15 changes: 0 additions & 15 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ BIN_OUTPUT_PATH = bin/$(shell uname -s)-$(shell uname -m)

TOOL_BIN = bin/gotools/$(shell uname -s)-$(shell uname -m)

NDK_ROOT ?= etc/android-ndk-r26
BUILD_CHANNEL ?= local

PATH_WITH_TOOLS="`pwd`/$(TOOL_BIN):`pwd`/node_modules/.bin:${PATH}"
Expand Down Expand Up @@ -118,20 +117,6 @@ full-static: build-web
server-static-compressed: server-static
upx --best --lzma $(BIN_OUTPUT_PATH)/viam-server

$(NDK_ROOT):
# download ndk (used by server-android)
cd etc && wget https://dl.google.com/android/repository/android-ndk-r26-linux.zip
cd etc && unzip android-ndk-r26-linux.zip

.PHONY: server-android
server-android:
GOOS=android GOARCH=arm64 CGO_ENABLED=1 \
CC=$(shell realpath $(NDK_ROOT)/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android30-clang) \
go build -v \
-tags no_cgo \
-o bin/viam-server-$(BUILD_CHANNEL)-android-aarch64 \
./web/cmd/server

clean-all:
git clean -fxd

Expand Down
54 changes: 54 additions & 0 deletions android.make
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
$(NDK_ROOT):
# todo: remove this once we are building .aar in CI
# download ndk (used by server-android)
cd etc && wget https://dl.google.com/android/repository/android-ndk-r26-linux.zip
cd etc && unzip android-ndk-r26-linux.zip

.PHONY: server-android
server-android:
GOOS=android GOARCH=arm64 CGO_ENABLED=1 \
CC=$(shell realpath $(NDK_ROOT)/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android30-clang) \
go build -v \
-tags no_cgo \
-o bin/viam-server-$(BUILD_CHANNEL)-android-aarch64 \
./web/cmd/server

UNAME = $(shell uname)
ifeq ($(UNAME),Linux)
PLATFORM_NDK_ROOT ?= $(HOME)/Android/Sdk/ndk/26.1.10909125
else
PLATFORM_NDK_ROOT ?= $(HOME)/Android/Sdk/ndk/26.1.10909125
endif
DROID_CC ?= $(PLATFORM_NDK_ROOT)/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android28-clang
DROID_PREFIX = $(PWD)/etc/android/prefix

etc/android/prefix/%:
TARGET_ARCH=$* etc/android/build-x264.sh

.SECONDARY: etc/android/prefix/aarch64 etc/android/prefix/x86_64

droid-rdk.%.aar: etc/android/prefix/aarch64 etc/android/prefix/x86_64
# creates a per-platform android library that can be imported by native code
# we clear CGO_LDFLAGS so this doesn't try (and fail) to link to linuxbrew where present
$(eval JNI_ARCH := $(if $(filter arm64,$*),arm64-v8a,x86_64))
$(eval CPU_ARCH := $(if $(filter arm64,$*),aarch64,x86_64))
CGO_LDFLAGS= PKG_CONFIG_PATH=$(DROID_PREFIX)/$(CPU_ARCH)/lib/pkgconfig \
gomobile bind -v -target android/$* -androidapi 28 -tags no_cgo \
-o $@ ./web/cmd/droid
rm -rf droidtmp/jni/$(JNI_ARCH)
mkdir -p droidtmp/jni/$(JNI_ARCH)
cp -d etc/android/prefix/$(CPU_ARCH)/lib/*.so* droidtmp/jni/$(JNI_ARCH)
cd droidtmp && zip --symlinks -r ../$@ jni/$(JNI_ARCH)
cd ./services/mlmodel/tflitecpu/android/ && zip --symlinks -r ../../../../$@ jni/$(JNI_ARCH)

droid-rdk.aar: droid-rdk.amd64.aar droid-rdk.arm64.aar
# multi-platform AAR -- twice the size, but portable
rm -rf droidtmp
cp droid-rdk.arm64.aar $@.tmp
unzip droid-rdk.amd64.aar -d droidtmp
cd droidtmp && zip --symlinks -r ../$@.tmp jni
mv $@.tmp $@

clean-droid:
# note: this doesn't clean x264 checkout
rm -rvf droid-rdk*.aar droid-rdk*.jar etc/android/prefix droidtmp
2 changes: 2 additions & 0 deletions etc/android/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
prefix/
x264/
3 changes: 3 additions & 0 deletions etc/android/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## unversion-soname

The unversion-soname patch in this folder changes the soname of x264 from `.so.VERSION_NUMBER` format to strict `.so`. We do this because the android toolchain removes the version-suffixed version of the SO, but our go build links against the soname it observes.
38 changes: 38 additions & 0 deletions etc/android/build-tflite.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#!/bin/bash -e

if [[ -z "${ANDROID_NDK}" ]]; then
echo "Must provide ANDROID_NDK in environment" 1>&2
exit 1
fi

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
ROOT_DIR="${DIR}/../../"
source ${ANDROID_NDK}/build/tools/ndk_bin_common.sh
NDK_TOOLCHAIN=${ANDROID_NDK}/toolchains/llvm/prebuilt/${HOST_TAG}

# ripped from private sysops repo
cd ~ && mkdir -p tensorflow/build_arm64-v8a tensorflow/build_x86_64 && cd tensorflow
curl -L https://github.com/tensorflow/tensorflow/archive/refs/tags/v2.12.0.tar.gz | tar -xz
patch -p1 -d tensorflow-2.12.0 < ${DIR}/tflite.patch
function build() {
local arch=$1
pushd ~/tensorflow/build_$arch
cmake -DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK}/build/cmake/android.toolchain.cmake \
-DANDROID_ABI=$arch ../tensorflow-2.12.0/tensorflow/lite/c
cmake --build . -j
${NDK_TOOLCHAIN}/bin/llvm-strip --strip-unneeded libtensorflowlite_c.so
local dest=${ROOT_DIR}/services/mlmodel/tflitecpu/android/jni/$arch
mkdir -p $dest
cp libtensorflowlite_c.so $dest
popd
}
for arch in arm64-v8a x86_64; do
build $arch
done
if [ $KEEP_TFLITE_SRC != "1" ]; then
echo "cleaning up source and build"
rm -rf ~/tensorflow/
else
echo "cleaning up build, keeping source"
rm -rf ~/tensorflow/build_*
fi
66 changes: 66 additions & 0 deletions etc/android/build-x264.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#!/usr/bin/env bash
# build a static x264 distro for android

set -euxo pipefail

if [ $(uname) = Linux ]; then
: "${NDK_ROOT:=$HOME/Android/Sdk/ndk/26.1.10909125}"
HOST_OS=linux
else
: "${NDK_ROOT:=$HOME/Library/Android/sdk/ndk/26.1.10909125}"
HOST_OS=darwin
fi

API_LEVEL=28
: "${TARGET_ARCH:=aarch64}"
TOOLCHAIN=$NDK_ROOT/toolchains/llvm/prebuilt/$HOST_OS-x86_64
export CC=$TOOLCHAIN/bin/$TARGET_ARCH-linux-android$API_LEVEL-clang
EXTRAS=
if [ $TARGET_ARCH = aarch64 ]; then
EXTRAS="--extra-cflags=-march=armv8-a"
fi
# CXX=$TOOLCHAIN/bin/$CC_ARCH-linux-android$API_LEVEL-clang++
# AR=$TOOLCHAIN/bin/llvm-ar
# LD=$CC
# RANLIB=$TOOLCHAIN/bin/llvm-ranlib
# STRIP=$TOOLCHAIN/bin/llvm-strip
# NM=$TOOLCHAIN/bin/llvm-nm
SYSROOT=$TOOLCHAIN/sysroot
DIRNAME=$(realpath $(dirname $0))
PREFIX=$DIRNAME/prefix/$TARGET_ARCH
X264_ROOT=$DIRNAME/x264

if [ ! -e $X264_ROOT ]; then
echo checking out x264
git clone https://code.videolan.org/videolan/x264.git -b stable $X264_ROOT
else
echo using existing x264
fi

cd $X264_ROOT
# note: patchelf can also change the soname
if git apply --check ../unversion-soname.patch; then
git apply ../unversion-soname.patch
elif git apply --reverse --check ../unversion-soname.patch; then
echo "not applying patch, already applied"
else
# note: we patch the soname because android build resolves the libx264.so -> libx264.so.164 symlink
# if allowed, this will build successfully and then fail on startup.
echo "soname patch could not be applied, bailing"
exit 1
fi
./configure \
--prefix=$PREFIX \
--host=$TARGET_ARCH-linux-android \
--cross-prefix=$TOOLCHAIN/bin/llvm- \
--sysroot=$SYSROOT \
$EXTRAS \
--enable-shared \
--disable-avs \
--disable-swscale \
--disable-lavf \
--disable-ffms \
--disable-gpac \
--disable-lsmash \
&& make \
&& make install
35 changes: 35 additions & 0 deletions etc/android/tflite.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
--- a/tensorflow/lite/core/interpreter.cc
+++ b/tensorflow/lite/core/interpreter.cc
@@ -445,8 +445,10 @@
}

TfLiteStatus Interpreter::ReportTelemetrySettings(const char* setting_name) {
+#ifdef TF_LITE_TENSORFLOW_PROFILER
telemetry::TelemetryReportSettings(context_, setting_name,
telemetry_data_.get());
+#endif //TFLITE_TENSORFLOW_PROFILER
return kTfLiteOk;
}

--- a/tensorflow/lite/core/subgraph.cc
+++ b/tensorflow/lite/core/subgraph.cc
@@ -1382,7 +1382,9 @@

TfLiteStatus Subgraph::Invoke() {
auto status = InvokeImpl();
+#ifdef TF_LITE_TENSORFLOW_PROFILER
telemetry::TelemetryReportEvent(&context_, "Invoke", status);
+#endif //TFLITE_TENSORFLOW_PROFILER
return status;
}
TfLiteStatus Subgraph::InvokeImpl() {
@@ -1966,7 +1968,9 @@

TfLiteStatus Subgraph::ModifyGraphWithDelegate(TfLiteDelegate* delegate) {
auto status = ModifyGraphWithDelegateImpl(delegate);
+#ifdef TF_LITE_TENSORFLOW_PROFILER
telemetry::TelemetryReportEvent(&context_, "ModifyGraphWithDelegate", status);
+#endif //TFLITE_TENSORFLOW_PROFILER
return status;
}

13 changes: 13 additions & 0 deletions etc/android/unversion-soname.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
diff --git a/configure b/configure
index e242e73c..83b6ec82 100755
--- a/configure
+++ b/configure
@@ -1591,7 +1591,7 @@ if [ "$shared" = "yes" ]; then
echo "SOFLAGS=-shared -Wl,-h,\$(SONAME) $SOFLAGS" >> config.mak
else
echo "SOSUFFIX=so" >> config.mak
- echo "SONAME=libx264.so.$API" >> config.mak
+ echo "SONAME=libx264.so" >> config.mak
echo "SOFLAGS=-shared -Wl,-soname,\$(SONAME) $SOFLAGS" >> config.mak
fi
echo 'default: lib-shared' >> config.mak
7 changes: 4 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,11 @@ require (
go.viam.com/utils v0.1.74
goji.io v2.0.2+incompatible
golang.org/x/image v0.15.0
golang.org/x/mobile v0.0.0-20240112133503-c713f31d574b
golang.org/x/sys v0.18.0
golang.org/x/term v0.18.0
golang.org/x/time v0.3.0
golang.org/x/tools v0.12.0
golang.org/x/tools v0.17.0
gonum.org/v1/gonum v0.12.0
gonum.org/v1/plot v0.12.0
google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98
Expand Down Expand Up @@ -367,10 +368,10 @@ require (
go4.org/unsafe/assume-no-moving-gc v0.0.0-20230525183740-e7c30c78aeb2 // indirect
golang.org/x/crypto v0.21.0 // indirect
golang.org/x/exp/typeparams v0.0.0-20230224173230-c95f2b4c22f2 // indirect
golang.org/x/mod v0.12.0 // indirect
golang.org/x/mod v0.14.0 // indirect
golang.org/x/net v0.22.0 // indirect
golang.org/x/oauth2 v0.10.0 // indirect
golang.org/x/sync v0.3.0 // indirect
golang.org/x/sync v0.6.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/api v0.126.0 // indirect
Expand Down
14 changes: 8 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1609,6 +1609,8 @@ golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPI
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mobile v0.0.0-20240112133503-c713f31d574b h1:kfWLZgb8iUBHdE9WydD5V5dHIS/F6HjlBZNyJfn2bs4=
golang.org/x/mobile v0.0.0-20240112133503-c713f31d574b/go.mod h1:4efzQnuA1nICq6h4kmZRMGzbPiP06lZvgADUu1VpJCE=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
Expand All @@ -1624,8 +1626,8 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91
golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
Expand Down Expand Up @@ -1721,8 +1723,8 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
Expand Down Expand Up @@ -1977,8 +1979,8 @@ golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k=
golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.12.0 h1:YW6HUoUmYBpwSgyaGaZq1fHjrBjX1rlpZ54T6mu2kss=
golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM=
golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc=
golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
Expand Down
2 changes: 0 additions & 2 deletions gostream/stream.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ import (

"github.com/edaniels/golog"
"github.com/google/uuid"
// register screen drivers.
_ "github.com/pion/mediadevices/pkg/driver/microphone"
"github.com/pion/mediadevices/pkg/prop"
"github.com/pion/mediadevices/pkg/wave"
"github.com/pion/rtp"
Expand Down
8 changes: 8 additions & 0 deletions gostream/stream_cgo.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
//go:build !no_cgo

package gostream

import (
// comment for linter.
_ "github.com/pion/mediadevices/pkg/driver/microphone"
)
10 changes: 10 additions & 0 deletions robot/web/graphviz_nocgo.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
//go:build no_cgo

package web

import "net/http"

// stub for missing graphviz
func (svc *webService) handleVisualizeResourceGraph(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(`<html><body>Resource graph not supported on this build</body></html>`))
}
2 changes: 1 addition & 1 deletion robot/web/stream/stream.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//go:build !no_cgo
//go:build !no_cgo || android

// Package webstream provides controls for streaming from the web server.
package webstream
Expand Down
2 changes: 1 addition & 1 deletion robot/web/web_c.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//go:build !no_cgo
//go:build !no_cgo || android

package web

Expand Down
5 changes: 1 addition & 4 deletions robot/web/web_notc.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//go:build no_cgo
//go:build no_cgo && !android

package web

Expand Down Expand Up @@ -70,6 +70,3 @@ func (svc *webService) initStreamServer(ctx context.Context, options *weboptions

// stub for missing gostream
type options struct{}

// stub for missing graphviz
func (svc *webService) handleVisualizeResourceGraph(w http.ResponseWriter, r *http.Request) {}
2 changes: 1 addition & 1 deletion robot/web/web_options_cgo.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//go:build !no_cgo
//go:build !no_cgo || android

package web

Expand Down
2 changes: 1 addition & 1 deletion services/mlmodel/register/register_tflite.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//go:build !no_tflite && !no_cgo
//go:build !no_tflite && (!no_cgo || android)

// Package register registers all relevant ML model services
package register
Expand Down
Loading

0 comments on commit 04de2fd

Please sign in to comment.