Skip to content

Commit b01fbfc

Browse files
committed
Fixes builds for cpp examples.
- Upgrade to latest libedgetpu with matching tensorflow library - Use bazel and share WORKSPACE for both examples - Added docker with cross compile supports
1 parent eced31a commit b01fbfc

File tree

18 files changed

+342
-204
lines changed

18 files changed

+342
-204
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
*.idea

cpp/examples/.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
.bazelrc
2+
/bazel-*
3+
/out
4+
5+
** Editors **
6+
*.swp
7+
*.idea

cpp/examples/Makefile

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# Copyright 2022 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
SHELL := /bin/bash
15+
MAKEFILE_DIR := $(realpath $(dir $(lastword $(MAKEFILE_LIST))))
16+
OS := $(shell uname -s)
17+
18+
# Allowed CPU values: k8, armv7a, aarch64
19+
ifeq ($(OS),Linux)
20+
CPU ?= k8
21+
else
22+
$(error $(OS) is not supported)
23+
endif
24+
ifeq ($(filter $(CPU),k8 armv7a aarch64),)
25+
$(error CPU must be k8, armv7a, aarch64)
26+
endif
27+
28+
# Allowed COMPILATION_MODE values: opt, dbg
29+
COMPILATION_MODE ?= opt
30+
ifeq ($(filter $(COMPILATION_MODE),opt dbg),)
31+
$(error COMPILATION_MODE must be opt or dbg)
32+
endif
33+
34+
BAZEL_OUT_DIR := $(MAKEFILE_DIR)/bazel-out/$(CPU)-$(COMPILATION_MODE)/bin
35+
BAZEL_BUILD_FLAGS := --crosstool_top=@crosstool//:toolchains \
36+
--compiler=gcc \
37+
--compilation_mode=$(COMPILATION_MODE) \
38+
--copt=-DNPY_NO_DEPRECATED_API=NPY_1_7_API_VERSION \
39+
--copt=-std=c++14 \
40+
--verbose_failures \
41+
--cpu=$(CPU) \
42+
--experimental_repo_remote_exec
43+
44+
ifeq ($(COMPILATION_MODE), opt)
45+
BAZEL_BUILD_FLAGS += --linkopt=-Wl,--strip-all
46+
else ifeq ($(COMPILATION_MODE), dbg)
47+
# for now, disable arm_neon in dbg.
48+
# see: https://github.com/tensorflow/tensorflow/issues/33360
49+
BAZEL_BUILD_FLAGS += --cxxopt -DTF_LITE_DISABLE_X86_NEON
50+
endif
51+
52+
ifeq ($(CPU),k8)
53+
BAZEL_BUILD_FLAGS += --copt=-includeglibc_compat.h
54+
else ifeq ($(CPU),aarch64)
55+
BAZEL_BUILD_FLAGS += --copt=-ffp-contract=off
56+
else ifeq ($(CPU),armv7a)
57+
BAZEL_BUILD_FLAGS += --copt=-ffp-contract=off
58+
endif
59+
60+
61+
DEMO_OUT_DIR := $(MAKEFILE_DIR)/out/$(CPU)/
62+
63+
.PHONY: all lstpu classify clean
64+
65+
66+
examples:
67+
bazel build $(BAZEL_BUILD_FLAGS) //classification:classify
68+
bazel build $(BAZEL_BUILD_FLAGS) //lstpu:lstpu
69+
mkdir -p $(DEMO_OUT_DIR)
70+
cp -f $(BAZEL_OUT_DIR)/classification/classify \
71+
$(DEMO_OUT_DIR)
72+
cp -f $(BAZEL_OUT_DIR)/lstpu/lstpu \
73+
$(DEMO_OUT_DIR)
74+
rm -rf $(MAKEFILE_DIR)/bazel-*
75+
76+
clean:
77+
rm -rf $(MAKEFILE_DIR)/out
78+
79+
DOCKER_WORKSPACE=$(MAKEFILE_DIR)
80+
DOCKER_CPUS=k8 armv7a aarch64 armv6
81+
DOCKER_TAG_BASE=tflite-coral-examples
82+
include $(MAKEFILE_DIR)/docker/docker.mk

cpp/examples/README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Simple C++ code example
2+
3+
These examples show how to build a simple C++ program that uses the EdgeTPU
4+
runtime library. This subdirectory contains 2 different examples:
5+
6+
- lstpu:
7+
- lists available Edge TPU devices (It does not perform inference).
8+
- classification:
9+
- classify a bmp image using a classification model.
10+
11+
## Compile the examples
12+
```bash
13+
$ make DOCKER_TARGET=examples DOCKER_CPUS=k8 docker-build
14+
```

cpp/examples/WORKSPACE

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# Copyright 2020 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
workspace(name = "tflite_examples")
15+
16+
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
17+
18+
TENSORFLOW_COMMIT = "48c3bae94a8b324525b45f157d638dfd4e8c3be1"
19+
TENSORFLOW_SHA256 = "363420a67b4cfa271cd21e5c8fac0d7d91b18b02180671c3f943c887122499d8"
20+
21+
# These values come from the Tensorflow workspace. If the TF commit is updated,
22+
# these should be updated to match.
23+
IO_BAZEL_RULES_CLOSURE_COMMIT = "308b05b2419edb5c8ee0471b67a40403df940149"
24+
IO_BAZEL_RULES_CLOSURE_SHA256 = "5b00383d08dd71f28503736db0500b6fb4dda47489ff5fc6bed42557c07c6ba9"
25+
26+
CORAL_CROSSTOOL_COMMIT = "142e930ac6bf1295ff3ba7ba2b5b6324dfb42839"
27+
CORAL_CROSSTOOL_SHA256 = "088ef98b19a45d7224be13636487e3af57b1564880b67df7be8b3b7eee4a1bfc"
28+
29+
# Configure libedgetpu and downstream libraries (TF and Crosstool).
30+
http_archive(
31+
name = "libedgetpu",
32+
sha256 = "d76d18c5a96758dd620057028cdd4e129bd885480087a5c7334070bba3797e58",
33+
strip_prefix = "libedgetpu-14eee1a076aa1af7ec1ae3c752be79ae2604a708",
34+
urls = [
35+
"https://github.com/google-coral/libedgetpu/archive/14eee1a076aa1af7ec1ae3c752be79ae2604a708.tar.gz"
36+
],
37+
)
38+
39+
load("@libedgetpu//:workspace.bzl", "libedgetpu_dependencies")
40+
libedgetpu_dependencies(TENSORFLOW_COMMIT, TENSORFLOW_SHA256,
41+
IO_BAZEL_RULES_CLOSURE_COMMIT,IO_BAZEL_RULES_CLOSURE_SHA256,
42+
CORAL_CROSSTOOL_COMMIT,CORAL_CROSSTOOL_SHA256)
43+
44+
45+
load("@org_tensorflow//tensorflow:workspace.bzl", "tf_workspace")
46+
tf_workspace(tf_repo_name = "org_tensorflow")
47+
48+
load("@coral_crosstool//:configure.bzl", "cc_crosstool")
49+
cc_crosstool(name = "crosstool", additional_system_include_directories=["//docker/include"])

cpp/examples/classification/BUILD

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Copyright 2019 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
cc_binary(
15+
name = "classify",
16+
srcs = ["classify.cc"],
17+
deps = [
18+
"@libedgetpu//tflite/public:oss_edgetpu_direct_all",
19+
"@org_tensorflow//tensorflow/lite:builtin_op_data",
20+
"@org_tensorflow//tensorflow/lite:framework",
21+
"@org_tensorflow//tensorflow/lite/kernels:builtin_ops",
22+
],
23+
)

cpp/examples/classification/Makefile

Lines changed: 0 additions & 46 deletions
This file was deleted.

cpp/examples/classification/classify.cc

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@
88
#include <utility>
99
#include <vector>
1010

11-
#include "edgetpu_c.h"
11+
#include "tensorflow/lite/builtin_op_data.h"
1212
#include "tensorflow/lite/interpreter.h"
1313
#include "tensorflow/lite/kernels/register.h"
1414
#include "tensorflow/lite/model.h"
15+
#include "tflite/public/edgetpu.h"
1516

1617
namespace {
1718
constexpr size_t kBmpFileHeaderSize = 14;
@@ -130,17 +131,6 @@ int main(int argc, char* argv[]) {
130131
const std::string image_file = argv[3];
131132
const float threshold = std::stof(argv[4]);
132133

133-
// Find TPU device.
134-
size_t num_devices;
135-
std::unique_ptr<edgetpu_device, decltype(&edgetpu_free_devices)> devices(
136-
edgetpu_list_devices(&num_devices), &edgetpu_free_devices);
137-
138-
if (num_devices == 0) {
139-
std::cerr << "No connected TPU found" << std::endl;
140-
return 1;
141-
}
142-
const auto& device = devices.get()[0];
143-
144134
// Load labels.
145135
auto labels = ReadLabels(label_file);
146136
if (labels.empty()) {
@@ -164,17 +154,19 @@ int main(int argc, char* argv[]) {
164154
return 1;
165155
}
166156

167-
// Create interpreter.
157+
// Get edgetpu context.
158+
auto edgetpu_context = edgetpu::EdgeTpuManager::GetSingleton()->OpenDevice();
168159
tflite::ops::builtin::BuiltinOpResolver resolver;
160+
resolver.AddCustom(edgetpu::kCustomOp, edgetpu::RegisterCustomOp());
161+
162+
// Create interpreter.
169163
std::unique_ptr<tflite::Interpreter> interpreter;
170164
if (tflite::InterpreterBuilder(*model, resolver)(&interpreter) != kTfLiteOk) {
171165
std::cerr << "Cannot create interpreter" << std::endl;
172-
return 1;
166+
exit(EXIT_FAILURE);
173167
}
174-
175-
auto* delegate =
176-
edgetpu_create_delegate(device.type, device.path, nullptr, 0);
177-
interpreter->ModifyGraphWithDelegate({delegate, edgetpu_free_delegate});
168+
interpreter->SetExternalContext(kTfLiteEdgeTpuContext, edgetpu_context.get());
169+
interpreter->SetNumThreads(1);
178170

179171
// Allocate tensors.
180172
if (interpreter->AllocateTensors() != kTfLiteOk) {

cpp/examples/docker/Dockerfile

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# Copyright 2021 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
ARG IMAGE
16+
FROM ${IMAGE}
17+
18+
COPY update_sources.sh /
19+
RUN /update_sources.sh
20+
21+
RUN dpkg --add-architecture armhf
22+
RUN dpkg --add-architecture arm64
23+
RUN apt-get update && apt-get install -y \
24+
sudo \
25+
debhelper \
26+
build-essential \
27+
crossbuild-essential-armhf \
28+
crossbuild-essential-arm64 \
29+
libusb-1.0-0-dev \
30+
libusb-1.0-0-dev:arm64 \
31+
libusb-1.0-0-dev:armhf \
32+
libglib2.0-dev \
33+
libglib2.0-dev:armhf \
34+
libglib2.0-dev:arm64 \
35+
libgstreamer1.0-dev \
36+
libgstreamer1.0-dev:armhf \
37+
libgstreamer1.0-dev:arm64 \
38+
libgstreamer-plugins-base1.0-dev \
39+
libgstreamer-plugins-base1.0-dev:armhf \
40+
libgstreamer-plugins-base1.0-dev:arm64 \
41+
libgtk-3-dev \
42+
libgtk-3-dev:arm64 \
43+
libgtk-3-dev:armhf \
44+
python \
45+
python3-all \
46+
python3-six \
47+
zlib1g-dev \
48+
zlib1g-dev:armhf \
49+
zlib1g-dev:arm64 \
50+
pkg-config \
51+
zip \
52+
unzip \
53+
curl \
54+
wget \
55+
git \
56+
subversion \
57+
vim \
58+
python3-numpy
59+
60+
ARG BAZEL_VERSION=2.1.0
61+
RUN wget -O /bazel https://github.com/bazelbuild/bazel/releases/download/${BAZEL_VERSION}/bazel-${BAZEL_VERSION}-installer-linux-x86_64.sh && \
62+
bash /bazel && \
63+
rm -f /bazel
64+
65+
RUN svn export https://github.com/google-coral/edgetpu/trunk/libedgetpu /libedgetpu
66+

cpp/examples/docker/docker.mk

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
DOCKER_MK_DIR := $(realpath $(dir $(lastword $(MAKEFILE_LIST))))
2+
3+
# Docker
4+
DOCKER_CPUS ?= k8 armv7a armv6 aarch64
5+
DOCKER_TARGETS ?=
6+
DOCKER_IMAGE ?= debian:buster
7+
DOCKER_TAG_BASE ?= "bazel-cross"
8+
DOCKER_TAG := "$(DOCKER_TAG_BASE)-$(subst :,-,$(DOCKER_IMAGE))"
9+
DOCKER_SHELL_COMMAND ?=
10+
11+
ifndef DOCKER_WORKSPACE
12+
$(error DOCKER_WORKSPACE is not defined)
13+
endif
14+
15+
WORKSPACE := /workspace
16+
MAKE_COMMAND := \
17+
for cpu in $(DOCKER_CPUS); do \
18+
make CPU=\$${cpu} COMPILATION_MODE=$(COMPILATION_MODE) -C /workspace $(DOCKER_TARGETS) || exit 1; \
19+
done
20+
21+
define run_command
22+
chmod a+w /; \
23+
groupadd --gid $(shell id -g) $(shell id -g -n); \
24+
useradd -m -e '' -s /bin/bash --gid $(shell id -g) --uid $(shell id -u) $(shell id -u -n); \
25+
echo '$(shell id -u -n) ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers; \
26+
su $(shell id -u -n) $(if $(1),-c '$(1)',)
27+
endef
28+
29+
docker-image:
30+
docker build $(DOCKER_IMAGE_OPTIONS) -t $(DOCKER_TAG) \
31+
--build-arg IMAGE=$(DOCKER_IMAGE) $(DOCKER_MK_DIR)
32+
33+
docker-shell: docker-image
34+
docker run --rm -i --tty -v $(DOCKER_WORKSPACE):$(WORKSPACE) --workdir $(WORKSPACE) \
35+
$(DOCKER_TAG) /bin/bash -c "$(call run_command,$(DOCKER_SHELL_COMMAND))"
36+
37+
docker-build: docker-image
38+
docker run --rm -i $(shell tty -s && echo --tty) -v $(DOCKER_WORKSPACE):$(WORKSPACE) \
39+
$(DOCKER_TAG) /bin/bash -c "$(call run_command,$(MAKE_COMMAND))"

cpp/examples/docker/include/BUILD

Whitespace-only changes.

0 commit comments

Comments
 (0)