diff --git a/.gitee/PULL_REQUEST_TEMPLATE.zh-CN.md b/.gitee/PULL_REQUEST_TEMPLATE.zh-CN.md deleted file mode 100644 index 5beec68522eea90e5aec8292edd802ff02cbbb6b..0000000000000000000000000000000000000000 --- a/.gitee/PULL_REQUEST_TEMPLATE.zh-CN.md +++ /dev/null @@ -1,8 +0,0 @@ -##### 修改原因:(目的、解决的问题等) -##### 修改内容:(整体或分文件描述修改内容) -##### 测试场景:(新增或改动可能影响的功能,对测试情况做简要说明。测试截图请贴在PR评论区) -##### 以下内容非必须,如无内容请删除 -##### 相关PR:(若有需列明) -##### 兼容性说明:(是否无法兼容已发布的版本) -##### API/接口变更:(若修改了现有的API/函数定义,需要做出说明) -##### 其他: diff --git a/.gitignore b/.gitignore index 85813e1cbc84ce2999ad60cb6b67fb14fbb375d5..76660e4d71b3451c984a1e996c8d15bd3ec666bf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,4 @@ -.vscode/* -!.vscode/settings.json -!.vscode/tasks.json -!.vscode/launch.json -!.vscode/extensions.json -*.code-workspace - -# Local History for Visual Studio Code -.history/ +/workdir/ +/.config +/.vscode +.config* diff --git a/Config.uk b/Config.uk new file mode 100644 index 0000000000000000000000000000000000000000..c4449619474fcc929a5ebcf99b33485c84b0b181 --- /dev/null +++ b/Config.uk @@ -0,0 +1,13 @@ +config LIBPYTHON3_START_CUSTOM + bool "Python start arguments" + select LIBPYTHON3 + default y + help + Custom settings Python command parameters + +if LIBPYTHON3_START_CUSTOM + config LIBPYTHON3_CUSTOM_PARAMETER + string "set python command parameters" + default "detect.py --input_image table.jpg --output_image output.jpg" +endif + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..8956879254bf0d023a2a7cf5cc4737e6b6e2c70a --- /dev/null +++ b/Makefile @@ -0,0 +1,18 @@ +UK_ROOT ?= $(PWD)/workdir/tenon +UK_LIBS ?= $(PWD)/workdir/libs +UK_BUILD ?= $(PWD)/workdir/build +UK_ROOTFS ?= $(PWD)/$(path) + +all: + @$(MAKE) -C $(UK_ROOT) A=$(PWD) O=$(UK_BUILD) L=$(UK_LIBS) + +$(MAKECMDGOALS): + @$(MAKE) -C $(UK_ROOT) A=$(PWD) O=$(UK_BUILD) L=$(UK_LIBS) $(MAKECMDGOALS) + +clean-rootfs: + @find $(UK_ROOTFS)/lib -name '*.so' -o -name '*.dll' -o -name '*.dylib' | xargs rm -f + @find $(UK_ROOTFS)/lib -name '__pycache__' -o -name '*.pyc' -o -name '*.pyo' | xargs rm -rf + @find $(UK_ROOTFS)/lib -name 'test' -o -name 'tests' | xargs rm -rf + @find $(UK_ROOTFS)/lib -name '*.dist-info' | xargs rm -rf + +.PHONY: clean_rootfs all initrd-img diff --git a/Makefile.uk b/Makefile.uk new file mode 100644 index 0000000000000000000000000000000000000000..5f4a28506ca5d837f6ec40fb001ff2e07ee87f83 --- /dev/null +++ b/Makefile.uk @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright 2024 The TenonOS Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +$(eval $(call addlib,appobjectdetection)) + +APPOBJECTDETECTION_SRCS-y += $(APPOBJECTDETECTION_BASE)/main.c \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000000000000000000000000000000000000..cf106eb45f780801a3fe111afc9b44ab708ab301 --- /dev/null +++ b/README.md @@ -0,0 +1,261 @@ +# app-object-detection + +## 介绍 + +TensorFlow Lite 是 TensorFlow 移动和嵌入式设备轻量级解决方案,为Tenon移植后,提供运行物体识别模型的能力,对输入图片中的物体进行识别。 + +本项目为移动和嵌入式设备提供机器学习应用的运行环境,并包含完整的 Python 标准库。用户可以运行自定义的 Python 脚本或定制的机器学习任务。项目还提供了一个图像识别任务作为示例。 + +## 支持架构 + +- AArch64 +- 运行平台:qemu、树莓派、rk3568 + +## 运行项目示例 + +编译环境配置 + +```powershell +sudo apt-get install build-essential libncurses-dev bison flex gcc-aarch64-linux-gnu g++-aarch64-linux-gnu +``` + +下载应用 + +```powershell +git clone git@gitee.com:tenonos/app-object-detection.git +cd app-object-detection +``` + +本项目提供默认启动命令来运行图像识别示例应用。除此之外,可以不使用默认启动命令,而是在交互式的python解释器中运行示例应用 + +### 配置启动命令运行图像识别应用 + +在应用构建平台的默认配置之后,默认勾选启动参数,运行默认启动参数为: + +```powershell +detect.py --input_image table.jpg --output_image output.jpg +``` + +- detect.py:对象识别代码 +- --input_image table.jpg:待识别的图片,table.jpg已经打包在rootfs文件夹下 +- --output_image xx.jpg:输出识别后的图片 + +以下是在不同的平台(qemu、树莓派、ok3568)上的具体构建过程,使用默认启动命令运行图像识别示例应用: + +#### qemu + +1. 拉取依赖微库 + + ```powershell + sh scripts/setup.sh + ``` + +2. 配置应用镜像 + + ```powershell + UK_DEFCONFIG=$(pwd)/defconfigs/qemu-arm64 make defconfig + ``` + +3. 编译python环境,待检测图片放在打包的文件夹中 + + ```powershell + make python-rootfs path=rootfs && make clean-rootfs path=rootfs + cd rootfs + sudo find . | cpio -H newc -o > ../initrd.cpio + cd .. + ``` + +4. 编译镜像: + + ```powershell + make + ``` + +5. 运行 + + ```powershell + # 使用initrd.cpio + sudo qemu-system-aarch64 -cpu cortex-a53 \ + -fsdev local,id=myid,path="$(pwd)/rootfs",security_model=none \ + -kernel workdir/build/app-object-detection_qemu-arm64 -nographic -machine virt \ + --append "vfs.rootdev=test" \ + -m 2048 -initrd initrd.cpio + ``` + +#### 树莓派 + +1. 拉取依赖微库 + + ```powershell + sh scripts/setup.sh + ``` + +2. 拉取树莓派板级支持包,配置树莓派 + + ```powershell + git clone git@gitee.com:tenonos/plat-raspi.git workdir/tenon/plat/raspi + vim workdir/tenon/plat/Makefile.uk + ``` + + 在最后一行添加: + + ```shell + $(eval $(call import_lib,$(UK_PLAT_BASE)/raspi)) + ``` + +3. 配置应用镜像 + + ```powershell + UK_DEFCONFIG=$(pwd)/defconfigs/raspi-arm64 make defconfig + ``` + +4. 编译python环境,待检测图片放在打包的文件夹中 + + ```powershell + make python-rootfs path=rootfs && make clean-rootfs path=rootfs + cd rootfs + sudo find . | cpio -H newc -o > ../initrd.cpio + cd .. + ``` + +5. 编译镜像 + + ```powershell + make + ``` + +6. 将编译好的内核镜像./workdir/build/kernel8.img通过bsp库打包,将解压打包后的文件以及编译后的initrd.cpio放入树莓派SD卡内。 + + ```powershell + # 进入bsp库根目录,打包树莓派镜像 + bash ./build.sh -b=raspberry-pi-3b+ pack + ``` + +7. 修改树莓派的config.txt文件,选择使用initrd.cpio作为启动文件系统: + + ```txt + # 取消掉这一行的注释 + initramfs initrd.cpio 0x1f800000 + ``` + +8. 上电,启动树莓派,运行对象识别应用 + +#### rk3568 + +1. 拉取依赖微库 + + ```powershell + sh scripts/setup.sh + ``` + +2. 拉取rk3568板级支持包,配置ok3568 + + ```powershell + git clone git@gitee.com:tenonos/plat-rk3568.git workdir/tenon/plat/rk3568 + vim workdir/tenon/plat/Makefile.uk + ``` + + 在最后一行添加rk3568微库: + + ```shell + $(eval $(call import_lib,$(UK_PLAT_BASE)/rk3568)) + ``` + +3. 配置应用镜像 + + ```powershell + UK_DEFCONFIG=$(pwd)/defconfigs/rk3568-arm64 make defconfig + ``` + +4. 编译python环境,待检测图片放在打包的文件夹中 + + ```powershell + make python-rootfs path=rootfs && make clean-rootfs path=rootfs + cd rootfs + sudo find . | cpio -H newc -o > ../initrd.cpio + cd .. + ``` + +5. 编译 + + ```powershell + make + ``` + +6. 打包 + + 通过第五步构建出workdir/build/kernel.img镜像之后,通过[BoardSupportPackage](https://gitee.com/tenonos/board-support-package.git)将其按照ok3568的打包逻辑打包为boot.img和uboot.img,进入bsp目录: + + ```powershell + bash ./build.sh -b=ok3568 pack + ``` + +### 运行成功示例 + +图像识别应用运行成功输出: + +![运行成功示例](./img/result.png) + +### python交互式启动 + +图像识别示例应用也可以不使用默认启动命令运行,可自定义启动参数,启动一个交互式的python解释器,在python解释器中运行。 + +在平台构建的第三步:“配置应用镜像”后,取消勾选启动参数: + +```powershell +make menuconfig +# Application Options -> LIBPYTHON3_START_CUSTOM +# 勾选则使用启动参数运行图像识别应用 +# 取消勾选则启动一个交互式的python解释器 +``` + +在交互式的python解释器中运行AI对象识别代码: + +![在交互式的python解释器中运行AI对象识别代码](./img/interactive_2.png) + +### 清理 + +清除构建后产物 + +```powershell +make distclean +``` + +## 扩展能力 + +本项目为移动和嵌入式设备提供机器学习应用的运行环境,并包含完整的 Python 标准库。用户可以运行自定义的 Python 脚本或定制的机器学习任务。 + +### 使用交互式Python解释器 + +使用[Python交互式启动方式](#python交互式启动),在平台上启动python解释器,可以运行一些简单的脚本: + +![使用交互式Python解释器运行简单脚本](./img/interactive_1.png) + +### 运行自定义Python脚本或机器学习任务 + +本项目所需的Python环境以及TensorFlow Lite等依赖微库安装在 *rootfs/* 文件夹下,并通过打包为initrd.cpio供Tenon内核使用,图像识别任务的模型以及运行代码也在 *rootfs/* 下: + +```sh +.rootfs +├── bin +├── detect.py ———— 图像识别应用代码 +├── efficientdet_lite0.tflite ———— 图像识别模型 +├── include +├── lib ———— Python环境 +├── lib64 -> lib +├── pyvenv.cfg +├── table.jpg +└── utils.py +``` + +用户可将自定义的 Python 脚本或机器学习任务代码以及模型放入 *rootfs/* 文件夹下,并打包为initrd.cpio文件供内核使用: + +```bash + cd rootfs + sudo find . | cpio -H newc -o > ../initrd.cpio +``` + +不过请注意: + +1. ok3568使用的是Embeded InitRD文件系统,initrd.cpio会在编译过程中被打包到内核镜像kernel.img中,因此如果重新打包了initrd.cpio文件,则需要再次构建ok3568镜像。 +2. 在使用 Python 自定义脚本或其他机器学习任务之前,请确认程序运行的所需要的相应微库/python库是否被安装。 diff --git a/defconfigs/qemu-arm64 b/defconfigs/qemu-arm64 new file mode 100644 index 0000000000000000000000000000000000000000..39f5077a0f5b2f44c905f1b9908cc829ae3ad2ab --- /dev/null +++ b/defconfigs/qemu-arm64 @@ -0,0 +1,11 @@ +CONFIG_ARCH_ARM_64=y +CONFIG_MCPU_ARM64_CORTEX_A53=y +# CONFIG_ARM64_ERRATUM_858921 is not set +CONFIG_STACK_SIZE_PAGE_ORDER=10 +CONFIG_PLAT_KVM=y +# CONFIG_ENFORCE_W_XOR_X is not set +CONFIG_LIBVFSCORE_ROOTFS_INITRD=y +# CONFIG_LIBPYTHON3_MAIN_FUNCTION is not set +CONFIG_LIBPYTHON_TFLITE_SUPPORT=y +CONFIG_LIBPYTHON_OPENCV=y +CONFIG_OPTIMIZE_DEADELIM=y diff --git a/defconfigs/raspi-arm64 b/defconfigs/raspi-arm64 new file mode 100644 index 0000000000000000000000000000000000000000..daf1510751031a661dbfe894a3e4c28c76ee9c4c --- /dev/null +++ b/defconfigs/raspi-arm64 @@ -0,0 +1,11 @@ +CONFIG_ARCH_ARM_64=y +CONFIG_MCPU_ARM64_CORTEX_A53=y +# CONFIG_ARM64_ERRATUM_858921 is not set +CONFIG_STACK_SIZE_PAGE_ORDER=10 +CONFIG_PLAT_RASPI=y +# CONFIG_ENFORCE_W_XOR_X is not set +CONFIG_LIBVFSCORE_ROOTFS_INITRD=y +# CONFIG_LIBPYTHON3_MAIN_FUNCTION is not set +CONFIG_LIBPYTHON_TFLITE_SUPPORT=y +CONFIG_LIBPYTHON_OPENCV=y +CONFIG_OPTIMIZE_DEADELIM=y diff --git a/defconfigs/rk3568-arm64 b/defconfigs/rk3568-arm64 new file mode 100644 index 0000000000000000000000000000000000000000..1b1a073ad91cfd10283503c3e515e2de7837f707 --- /dev/null +++ b/defconfigs/rk3568-arm64 @@ -0,0 +1,11 @@ +CONFIG_ARCH_ARM_64=y +CONFIG_MCPU_ARM64_CORTEX_A55=y +# CONFIG_ARM64_ERRATUM_858921 is not set +CONFIG_STACK_SIZE_PAGE_ORDER=10 +CONFIG_PLAT_RK3568=y +# CONFIG_ENFORCE_W_XOR_X is not set +CONFIG_LIBVFSCORE_ROOTFS_EINITRD=y +# CONFIG_LIBPYTHON3_MAIN_FUNCTION is not set +CONFIG_LIBPYTHON_TFLITE_SUPPORT=y +CONFIG_LIBPYTHON_OPENCV=y +CONFIG_OPTIMIZE_DEADELIM=y diff --git a/img/interactive_1.png b/img/interactive_1.png new file mode 100644 index 0000000000000000000000000000000000000000..bc28c8eeb8cc9eecf224dc59e10ee0b22f45842c Binary files /dev/null and b/img/interactive_1.png differ diff --git a/img/interactive_2.png b/img/interactive_2.png new file mode 100644 index 0000000000000000000000000000000000000000..f2ea47efeef291ec2f696bfb02355b6ba447a1a0 Binary files /dev/null and b/img/interactive_2.png differ diff --git a/img/result.png b/img/result.png new file mode 100644 index 0000000000000000000000000000000000000000..a607317d0ad75ed2471ac46780850f67472131b6 Binary files /dev/null and b/img/result.png differ diff --git a/main.c b/main.c new file mode 100644 index 0000000000000000000000000000000000000000..e7b09c6a32754bde0a27115eb179074da78e335d --- /dev/null +++ b/main.c @@ -0,0 +1,45 @@ +#include +#include +#include +#include +#include + +#define MAX_ARGUMENTS 100 + +int main(int argc, char *argv[]) +{ + char *arguments[MAX_ARGUMENTS]; + int i = 0; + int rc = 0; + + arguments[i] = (char *)malloc((strlen(argv[0]) + 1) * sizeof(char)); + strcpy(arguments[i], argv[0]); + i++; + +#if CONFIG_LIBPYTHON3_START_CUSTOM + char split[2] = " "; + char custom_parameters[1000]; + + strcpy(custom_parameters, CONFIG_LIBPYTHON3_CUSTOM_PARAMETER); + + char *argument = strtok(custom_parameters, split); + while (argument != NULL) { + arguments[i] = + (char *)malloc((strlen(argument) + 1) * sizeof(char)); + if (arguments[i] == NULL) + uk_pr_crit("Failed to allocate memory\n"); + strcpy(arguments[i], argument); + i++; + + argument = strtok(NULL, split); + } +#endif + + rc = Py_BytesMain(i, arguments); + + for (int j = 0; j < i; j++) { + free(arguments[j]); + } + + return rc; +} diff --git a/rootfs/detect.py b/rootfs/detect.py new file mode 100644 index 0000000000000000000000000000000000000000..1998c94e8779e4ea04d8c9fcd9ce86f53d8c4f4e --- /dev/null +++ b/rootfs/detect.py @@ -0,0 +1,86 @@ +# Copyright 2021 The TensorFlow Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Main script to run the object detection routine.""" + +import argparse +import sys +import time + +import cv2 +from tflite_support.task import core +from tflite_support.task import processor +from tflite_support.task import vision +import utils + + +def run(model: str, input_image: str, output_image: str) -> None: + # Visualization parameters + row_size = 20 # pixels + left_margin = 24 # pixels + text_color = (0, 0, 255) # red + font_size = 1 + font_thickness = 1 + + # Initialize the object detection model + base_options = core.BaseOptions(file_name=model) + detection_options = processor.DetectionOptions( + max_results=3, score_threshold=0.3) + options = vision.ObjectDetectorOptions( + base_options=base_options, detection_options=detection_options) + detector = vision.ObjectDetector.create_from_options(options) + + image = cv2.imread(input_image) + + # Convert the image from BGR to RGB as required by the TFLite model. + rgb_image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) + + # Create a TensorImage object from the RGB image. + input_tensor = vision.TensorImage.create_from_array(rgb_image) + + # Run object detection estimation using the model. + detection_result = detector.detect(input_tensor) + + # Draw keypoints and edges on input image + image = utils.visualize(image, detection_result) + text_location = (left_margin, row_size) + cv2.putText(image, 'obj_detection', text_location, cv2.FONT_HERSHEY_PLAIN, + font_size, text_color, font_thickness) + cv2.imwrite(output_image, image) + + +def main(): + parser = argparse.ArgumentParser( + formatter_class=argparse.ArgumentDefaultsHelpFormatter) + parser.add_argument( + '--model', + help='Path of the object detection model.', + required=False, + default='efficientdet_lite0.tflite') + parser.add_argument( + '--input_image', + help='Name of the input image.', + required=False, + default='table.jpg') + parser.add_argument( + '--output_image', + help='Name of the output image.', + required=False, + default='result.jpg') + args = parser.parse_args() + + run(args.model, args.input_image, args.output_image) + + +if __name__ == '__main__': + main() diff --git a/rootfs/efficientdet_lite0.tflite b/rootfs/efficientdet_lite0.tflite new file mode 100644 index 0000000000000000000000000000000000000000..57bea4a32b2b7f42f784162afaea95fcd87c0708 Binary files /dev/null and b/rootfs/efficientdet_lite0.tflite differ diff --git a/rootfs/table.jpg b/rootfs/table.jpg new file mode 100644 index 0000000000000000000000000000000000000000..82213777e29f6f039c62904976b4ca71434fccfe Binary files /dev/null and b/rootfs/table.jpg differ diff --git a/rootfs/utils.py b/rootfs/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..5785b6e98430df4113d7afe1d584a6d662abcd67 --- /dev/null +++ b/rootfs/utils.py @@ -0,0 +1,58 @@ +# Copyright 2021 The TensorFlow Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Utility functions to display the pose detection results.""" + +import cv2 +import numpy as np +from tflite_support.task import processor + +_MARGIN = 10 # pixels +_ROW_SIZE = 10 # pixels +_FONT_SIZE = 1 +_FONT_THICKNESS = 1 +_TEXT_COLOR = (0, 0, 255) # red + + +def visualize( + image: np.ndarray, + detection_result: processor.DetectionResult, +) -> np.ndarray: + """Draws bounding boxes on the input image and return it. + + Args: + image: The input RGB image. + detection_result: The list of all "Detection" entities to be visualize. + + Returns: + Image with bounding boxes. + """ + for detection in detection_result.detections: + # Draw bounding_box + bbox = detection.bounding_box + start_point = bbox.origin_x, bbox.origin_y + end_point = bbox.origin_x + bbox.width, bbox.origin_y + bbox.height + cv2.rectangle(image, start_point, end_point, _TEXT_COLOR, 3) + + # Draw label and score + category = detection.categories[0] + category_name = category.category_name + probability = round(category.score, 2) + result_text = category_name + ' (' + str(probability) + ')' + print(category_name + ' (' + str(probability) + ')') + text_location = (_MARGIN + bbox.origin_x, + _MARGIN + _ROW_SIZE + bbox.origin_y) + cv2.putText(image, result_text, text_location, cv2.FONT_HERSHEY_PLAIN, + _FONT_SIZE, _TEXT_COLOR, _FONT_THICKNESS) + + return image diff --git a/scripts/build.sh b/scripts/build.sh new file mode 100755 index 0000000000000000000000000000000000000000..71dc4d5db12ece5cec3af5cc3613853117b9e221 --- /dev/null +++ b/scripts/build.sh @@ -0,0 +1,27 @@ +#!/bin/sh + +# SPDX-License-Identifier: Apache-2.0 +# Copyright 2024 The TenonOS Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +if [ -n "$1" ]; then + CONFIG_PATH=$1 +else + CONFIG_PATH=$(pwd)/defconfigs/qemu-arm64 +fi + +UK_DEFCONFIG=$CONFIG_PATH make defconfig +make prepare +make -j $(nproc) diff --git a/scripts/setup.sh b/scripts/setup.sh new file mode 100755 index 0000000000000000000000000000000000000000..faba65a35cfcfdc4f6609ad8efc668e9eb2dc3a7 --- /dev/null +++ b/scripts/setup.sh @@ -0,0 +1,53 @@ +#!/bin/bash + +# SPDX-License-Identifier: Apache-2.0 +# Copyright 2024 The TenonOS Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +test ! -d "workdir" && echo "Cloning repositories ..." || true +test ! -d "workdir/tenon" && git clone git@gitee.com:tenonos/tenon.git workdir/tenon -b master || true +test ! -d "workdir/libs/compiler-rt" && git clone git@gitee.com:tenonos-mirror/lib-compiler-rt.git -b master workdir/libs/compiler-rt || true +test ! -d "workdir/libs/cxx" && git clone git@gitee.com:tenonos-mirror/lib-libcxx.git -b master workdir/libs/cxx || true +test ! -d "workdir/libs/cxxabi" && git clone git@gitee.com:tenonos-mirror/lib-libcxxabi.git -b master workdir/libs/cxxabi || true +test ! -d "workdir/libs/eigen" && git clone git@gitee.com:tenonos-mirror/lib-eigen.git -b master workdir/libs/eigen || true +test ! -d "workdir/libs/farmhash" && git clone git@gitee.com:tenonos-mirror/lib-farmhash.git -b master workdir/libs/farmhash || true +test ! -d "workdir/libs/fft2d" && git clone git@gitee.com:tenonos-mirror/lib-fft2d.git -b master workdir/libs/fft2d || true +test ! -d "workdir/libs/flatbuffers" && git clone git@gitee.com:tenonos-mirror/lib-flatbuffers.git -b master workdir/libs/flatbuffers || true +test ! -d "workdir/libs/gemmlowp" && git clone git@gitee.com:tenonos-mirror/lib-gemmlowp.git -b master workdir/libs/gemmlowp || true +test ! -d "workdir/libs/unwind" && git clone git@gitee.com:tenonos-mirror/lib-libunwind.git -b master workdir/libs/unwind || true +test ! -d "workdir/libs/arm-intrinsics" && git clone git@gitee.com:tenonos-mirror/lib-arm-intrinsics.git -b master workdir/libs/arm-intrinsics || true +test ! -d "workdir/libs/zlib" && git clone git@gitee.com:tenonos-mirror/lib-zlib.git -b master workdir/libs/zlib || true +test ! -d "workdir/libs/musl" && git clone git@gitee.com:tenonos-mirror/lib-musl.git -b master workdir/libs/musl || true +test ! -d "workdir/libs/libffi" && git clone git@gitee.com:tenonos-mirror/lib-libffi.git -b master workdir/libs/libffi || true +test ! -d "workdir/libs/python3" && git clone git@gitee.com:tenonos-mirror/lib-python3.git -b master workdir/libs/python3 || true +test ! -d "workdir/libs/python-numpy" && git clone git@gitee.com:tenonos-mirror/lib-python-numpy.git -b master workdir/libs/python-numpy || true +test ! -d "workdir/libs/tflite" && git clone git@gitee.com:tenonos-mirror/lib-tflite.git -b master workdir/libs/tflite || true +test ! -d "workdir/libs/lwip" && git clone git@gitee.com:tenonos-mirror/lib-lwip.git -b master workdir/libs/lwip || true +test ! -d "workdir/libs/pthreadpool" && git clone git@gitee.com:tenonos-mirror/lib-pthreadpool.git -b master workdir/libs/pthreadpool || true +test ! -d "workdir/libs/pthread-embedded" && git clone git@gitee.com:tenonos-mirror/lib-pthread-embedded.git -b master workdir/libs/pthread-embedded || true +test ! -d "workdir/libs/libfxdiv" && git clone git@gitee.com:tenonos-mirror/lib-libfxdiv.git -b master workdir/libs/libfxdiv || true +test ! -d "workdir/libs/glog" && git clone git@gitee.com:tenonos/lib-glog.git -b master workdir/libs/glog || true +test ! -d "workdir/libs/leveldb" && git clone git@gitee.com:tenonos/lib-leveldb.git -b master workdir/libs/leveldb || true +test ! -d "workdir/libs/yuv" && git clone git@gitee.com:tenonos/lib-yuv.git -b master workdir/libs/yuv || true +test ! -d "workdir/libs/protobuf" && git clone git@gitee.com:tenonos/lib-protobuf.git -b master workdir/libs/protobuf || true +test ! -d "workdir/libs/pybind11_abseil" && git clone git@gitee.com:tenonos/lib-pybind11_abseil.git -b master workdir/libs/pybind11_abseil || true +test ! -d "workdir/libs/pybind11_protobuf" && git clone git@gitee.com:tenonos/lib-pybind11_protobuf.git -b master workdir/libs/pybind11_protobuf || true +test ! -d "workdir/libs/re2" && git clone git@gitee.com:tenonos/lib-re2.git -b master workdir/libs/re2 || true +test ! -d "workdir/libs/ruy" && git clone git@gitee.com:tenonos/lib-ruy.git -b master workdir/libs/ruy || true +test ! -d "workdir/libs/stb" && git clone git@gitee.com:tenonos/lib-stb.git -b master -b master workdir/libs/stb || true +test ! -d "workdir/libs/tflite-support" && git clone git@gitee.com:tenonos/lib-tflite-support.git -b master workdir/libs/tflite-support || true +test ! -d "workdir/libs/absl" && git clone git@gitee.com:tenonos/lib-absl.git -b master workdir/libs/absl || true +test ! -d "workdir/libs/opencv" && git clone git@gitee.com:tenonos/lib-opencv.git -b master workdir/libs/opencv || true +test ! -d "workdir/libs/pybind11" && git clone git@gitee.com:tenonos/lib-pybind11.git -b master workdir/libs/pybind11 || true +