Initial Java API for the JAR package. (#292)

* more C++ code fixing and polish for release

* fixing for android build

* build flags for android release

* add missing exporting function

* imint

* first versoin

* more C++ code fixing and polish for release (#275)

* more C++ code fixing and polish for release

* fixing for android build

* build flags for android release

* add missing exporting function

* support build_id on Python package building (#281)

* support buildid in package building

* undo the change on build.sh

* build.sh issue on macos

* Add `$schema` to `cgmanifest.json` (#284)

Co-authored-by: Jamie Magee <jamie.magee@microsoft.com>

* test package with a simple java app

* demo app

* some fixing for windows platform

* refine the example app

* fix the missing symobls issue for Linux build

* fix the package package build issue

* typo

* a missing change

* fix PythonOp

* fix Android test issue

* one more Android change

* replace build flags in ci pipeline

* android AAR package build

* refine the code for android package

Co-authored-by: Jamie Magee <jamie.magee@gmail.com>
Co-authored-by: Jamie Magee <jamie.magee@microsoft.com>
This commit is contained in:
Wenbing Li 2022-10-04 16:22:28 -07:00 коммит произвёл GitHub
Родитель 12392c9863
Коммит 08659eae90
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
41 изменённых файлов: 1139 добавлений и 172 удалений

Просмотреть файл

@ -360,7 +360,7 @@ jobs:
sh ./build.sh \
-DCMAKE_TOOLCHAIN_FILE=$(Build.BinariesDirectory)/emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake \
-DOCOS_ENABLE_SPM_TOKENIZER=ON \
-DOCOS_ENABLE_PYTHON=OFF \
-DOCOS_BUILD_PYTHON=OFF \
-DOCOS_ENABLE_OPENCV=OFF
displayName: build the customop library with onnxruntime
# TODO add unittest for webassembly
@ -425,13 +425,13 @@ jobs:
workingDirectory: $(OnnxruntimeDirectory)
- script: |
adb push out/Darwin/RelWithDebInfo/lib/libortcustomops.so /data/local/tmp
adb push out/Darwin/RelWithDebInfo/lib/libortextensions.so /data/local/tmp
adb push out/Darwin/RelWithDebInfo/data /data/local/tmp
adb push out/Darwin/RelWithDebInfo/bin/operators_test /data/local/tmp
adb push out/Darwin/RelWithDebInfo/bin/ortcustomops_test /data/local/tmp
adb push out/Darwin/RelWithDebInfo/bin/ocos_test /data/local/tmp
adb push out/Darwin/RelWithDebInfo/bin/extensions_test /data/local/tmp
adb push $(OnnxruntimeDirectory)/build/Release/libonnxruntime.so /data/local/tmp
adb shell 'cd /data/local/tmp/ && chmod a+x operators_test'
adb shell 'cd /data/local/tmp/ && chmod a+x ortcustomops_test'
adb shell 'cd /data/local/tmp/ && export LD_LIBRARY_PATH=$(pwd) && ./operators_test' && adb shell 'cd /data/local/tmp/ && export LD_LIBRARY_PATH=$(pwd) && ./ortcustomops_test'
adb shell 'cd /data/local/tmp/ && chmod a+x ocos_test'
adb shell 'cd /data/local/tmp/ && chmod a+x extensions_test'
adb shell 'cd /data/local/tmp/ && export LD_LIBRARY_PATH=$(pwd) && ./ocos_test' && adb shell 'cd /data/local/tmp/ && export LD_LIBRARY_PATH=$(pwd) && ./extensions_test'
displayName: Run Android test
workingDirectory: $(Build.sourcesdirectory)

11
.gitignore поставляемый
Просмотреть файл

@ -5,6 +5,7 @@ build_host_protoc
build_android
build_ios
build_*
.version.txt
.venv/
_subbuild/
.build_debug/*
@ -38,7 +39,15 @@ out/
onnxruntime-*-*-*/
temp_*.onnx
test/data/*.py
# Java specific ignores
java/gradlew
java/gradlew.bat
java/gradle
java/.gradle
java/hs_*.log
*.class
tutorials/demo4j/app/bin/
tutorials/demo4j/app/libs
# Compiled Dynamic libraries
*.so
*.dylib

Просмотреть файл

@ -99,7 +99,7 @@ extends:
- task: SDLNativeRules@3
inputs:
msBuildArchitecture: amd64
setupCommandlines: '"$(vscmake)" $(REPOROOT) -A x64 -B $(REPOROOT)\windows_out -DOCOS_ENABLE_PYTHON=ON -DOCOS_ENABLE_CTEST=OFF -DCMAKE_BUILD_TYPE=Release'
setupCommandlines: '"$(vscmake)" $(REPOROOT) -A x64 -B $(REPOROOT)\windows_out -DOCOS_BUILD_PYTHON=ON -DOCOS_ENABLE_CTEST=OFF -DCMAKE_BUILD_TYPE=Release'
msBuildCommandline: '"$(vsmsbuild)" "$(REPOROOT)\windows_out\onnxruntime_extensions.sln" /p:RunCodeAnalysis=true /p:platform=x64 /p:configuration=Release /p:VisualStudioVersion="16.0" /m /p:PreferredToolArchitecture=x64'
excludedPaths: '$(REPOROOT)\windows_out#$(Build.SourcesDirectory)\cmake#C:\program files (x86)'
displayName: 'Run the PREfast SDL Native Rules for MSBuild'

Просмотреть файл

@ -99,7 +99,7 @@ extends:
- task: SDLNativeRules@3
inputs:
msBuildArchitecture: amd64
setupCommandlines: '"$(vscmake)" $(REPOROOT) -A x64 -B $(REPOROOT)\windows_out -DOCOS_ENABLE_PYTHON=ON -DOCOS_ENABLE_CTEST=OFF -DCMAKE_BUILD_TYPE=Release'
setupCommandlines: '"$(vscmake)" $(REPOROOT) -A x64 -B $(REPOROOT)\windows_out -DOCOS_BUILD_PYTHON=ON -DOCOS_ENABLE_CTEST=OFF -DCMAKE_BUILD_TYPE=Release'
msBuildCommandline: '"$(vsmsbuild)" "$(REPOROOT)\windows_out\onnxruntime_extensions.sln" /p:RunCodeAnalysis=true /p:platform=x64 /p:configuration=Release /p:VisualStudioVersion="16.0" /m /p:PreferredToolArchitecture=x64'
excludedPaths: '$(REPOROOT)\windows_out#$(Build.SourcesDirectory)\cmake#C:\program files (x86)'
displayName: 'Run the PREfast SDL Native Rules for MSBuild'

Просмотреть файл

@ -13,7 +13,10 @@ set(CPACK_PACKAGE_VERSION_MAJOR "0")
set(CPACK_PACKAGE_VERSION_MINOR "5")
set(CPACK_PACKAGE_VERSION_PATCH "0")
set(VERSION ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH})
file(WRITE ${PROJECT_SOURCE_DIR}/.version.txt ${VERSION})
# Needed for Java
set(CMAKE_C_STANDARD 99)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
@ -22,7 +25,7 @@ include(CheckCXXCompilerFlag)
include(CheckLanguage)
option(CC_OPTIMIZE "Allow compiler optimizations, Set to OFF to disable" ON)
option(OCOS_ENABLE_PYTHON "Enable Python component building" OFF)
option(OCOS_ENABLE_PYTHON "Enable Python component building, (deprecated)" OFF)
option(OCOS_ENABLE_CTEST "Enable C++ test" OFF)
option(OCOS_ENABLE_CPP_EXCEPTIONS "Enable C++ Exception" ON)
option(OCOS_ENABLE_TF_STRING "Enable String Operator Set" ON)
@ -38,7 +41,9 @@ option(OCOS_ENABLE_OPENCV "Enable operators depending on opencv" ON)
option(OCOS_ENABLE_OPENCV_CODECS "Enable operators depending on opencv imgcodecs" ON)
option(OCOS_ENABLE_STATIC_LIB "Enable generating static library" OFF)
option(OCOS_ENABLE_SELECTED_OPLIST "Enable including the selected_ops tool file" OFF)
option(OCOS_BUILD_PYTHON "Enable building the Python package" OFF)
option(OCOS_BUILD_JAVA "Enable building the Java package" OFF)
option(OCOS_BUILD_ANDROID "Enable building the Android package" OFF)
function(disable_all_operators)
set(OCOS_ENABLE_RE2_REGEX OFF CACHE INTERNAL "")
@ -69,6 +74,18 @@ if(NOT CC_OPTIMIZE)
endif()
endif()
if (NOT OCOS_BUILD_PYTHON AND OCOS_ENABLE_PYTHON)
message("OCOS_ENABLE_PYTHON IS DEPRECATED, USE OCOS_BUILD_PYTHON INSTEAD")
set(OCOS_BUILD_PYTHON ON CACHE INTERNAL "")
endif()
if (OCOS_BUILD_ANDROID)
if (NOT ANDROID_SDK_ROOT OR NOT CMAKE_ANDROID_NDK)
message("Cannot the find Android SDK/NDK")
endif()
set(OCOS_BUILD_JAVA ON CACHE INTERNAL "")
endif()
# Build the libraries with -fPIC
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
@ -305,30 +322,9 @@ list(REMOVE_DUPLICATES OCOS_COMPILE_DEFINITIONS)
target_compile_definitions(ocos_operators PRIVATE ${OCOS_COMPILE_DEFINITIONS})
target_link_libraries(ocos_operators PRIVATE ${ocos_libraries})
file(GLOB shared_TARGET_SRC "shared/*.cc" "shared/*.h")
if(OCOS_ENABLE_PYTHON)
set(Python3_FIND_REGISTRY NEVER CACHE STRING "...")
if(NOT "${Python3_FIND_REGISTRY}" STREQUAL "NEVER")
message(FATAL_ERROR "Python3_FIND_REGISTRY is not NEVER")
endif()
find_package(Python3 COMPONENTS Interpreter Development.Module NumPy)
if (NOT Python3_FOUND)
message(FATAL_ERROR "Python3 or NumPy not found!")
endif()
if (WIN32)
list(APPEND shared_TARGET_SRC "${PROJECT_SOURCE_DIR}/onnxruntime_extensions/ortcustomops.def")
endif()
file(GLOB TARGET_SRC_PYOPS "pyop/*.cc" "pyop/*.h")
add_library(ortcustomops SHARED ${TARGET_SRC_PYOPS} ${shared_TARGET_SRC})
standardize_output_folder(ortcustomops)
list(APPEND OCOS_COMPILE_DEFINITIONS PYTHON_OP_SUPPORT)
# building static lib has higher priority
elseif(OCOS_ENABLE_STATIC_LIB)
add_library(ortcustomops STATIC ${shared_TARGET_SRC})
add_library(onnxruntime_extensions ALIAS ortcustomops)
elseif(CMAKE_SYSTEM_NAME STREQUAL "Emscripten")
add_executable(ortcustomops ${shared_TARGET_SRC})
file(GLOB shared_TARGET_LIB_SRC "shared/lib/*.cc" "shared/lib/*.h")
if(CMAKE_SYSTEM_NAME STREQUAL "Emscripten")
add_executable(ortcustomops ${shared_TARGET_LIB_SRC})
set_target_properties(ortcustomops PROPERTIES LINK_FLAGS " \
-s WASM=1 \
-s NO_EXIT_RUNTIME=0 \
@ -346,42 +342,43 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "Emscripten")
set_property(TARGET ortcustomops APPEND_STRING PROPERTY LINK_FLAGS " -s ASSERTIONS=0 -s DEMANGLE_SUPPORT=0")
endif()
else()
list(APPEND shared_TARGET_SRC "${PROJECT_SOURCE_DIR}/shared/ortcustomops.def")
add_library(ortcustomops SHARED ${shared_TARGET_SRC})
if (CMAKE_SYSTEM_NAME STREQUAL "Android")
if (OCOS_ENABLE_SPM_TOKENIZER)
target_link_libraries(ortcustomops PUBLIC log)
set_property(TARGET ortcustomops APPEND_STRING PROPERTY LINK_FLAGS "-Wl,-s -Wl,--version-script -Wl,${PROJECT_SOURCE_DIR}/shared/ortcustomops.ver")
endif()
endif()
add_library(ortcustomops STATIC ${shared_TARGET_LIB_SRC})
add_library(onnxruntime_extensions ALIAS ortcustomops)
standardize_output_folder(ortcustomops)
set(_BUILD_SHARED_LIBRARY TRUE)
endif()
target_compile_definitions(ortcustomops PRIVATE ${OCOS_COMPILE_DEFINITIONS} ${GTEST_CXX_FLAGS})
target_compile_definitions(ortcustomops PUBLIC ${OCOS_COMPILE_DEFINITIONS} ${GTEST_CXX_FLAGS})
target_include_directories(ortcustomops PUBLIC
"$<TARGET_PROPERTY:ocos_operators,INTERFACE_INCLUDE_DIRECTORIES>")
target_link_libraries(ortcustomops PUBLIC ocos_operators)
if(OCOS_ENABLE_PYTHON)
message(STATUS "Fetch pybind11")
include(pybind11)
target_include_directories(ortcustomops PRIVATE
$<TARGET_PROPERTY:Python3::Module,INTERFACE_INCLUDE_DIRECTORIES>
$<TARGET_PROPERTY:Python3::NumPy,INTERFACE_INCLUDE_DIRECTORIES>
${pybind11_INCLUDE_DIRS}
)
target_compile_definitions(ortcustomops PRIVATE
$<TARGET_PROPERTY:Python3::Module,INTERFACE_COMPILE_DEFINITIONS>)
target_link_libraries(ortcustomops PRIVATE Python3::Module)
if(NOT "${OCOS_EXTENTION_NAME}" STREQUAL "")
if(NOT WIN32)
set_target_properties(ortcustomops PROPERTIES
LIBRARY_OUTPUT_NAME ${OCOS_EXTENTION_NAME}
PREFIX ""
SUFFIX "")
if (_BUILD_SHARED_LIBRARY)
file(GLOB shared_TARGET_SRC "shared/*.cc" "shared/*.h" "shared/*.def")
add_library(extensions_shared SHARED ${shared_TARGET_SRC})
standardize_output_folder(extensions_shared)
if (CMAKE_SYSTEM_NAME STREQUAL "Android")
if (OCOS_ENABLE_SPM_TOKENIZER)
target_link_libraries(extensions_shared PUBLIC log)
endif()
endif()
if (LINUX OR CMAKE_SYSTEM_NAME STREQUAL "Android")
set_property(TARGET extensions_shared APPEND_STRING PROPERTY LINK_FLAGS "-Wl,-s -Wl,--version-script -Wl,${PROJECT_SOURCE_DIR}/shared/ortcustomops.ver")
endif()
target_include_directories(extensions_shared PUBLIC
"$<TARGET_PROPERTY:ortcustomops,INTERFACE_INCLUDE_DIRECTORIES>")
target_link_libraries(extensions_shared PRIVATE ortcustomops)
set_target_properties(extensions_shared PROPERTIES OUTPUT_NAME "ortextensions")
endif()
if(OCOS_BUILD_PYTHON)
message(STATUS "Python Build is enabled")
include(ext_python)
endif()
if(OCOS_BUILD_JAVA)
message(STATUS "Java Build is enabled")
include(ext_java)
endif()
# clean up the requirements.txt files from 3rd party project folder to suppress the code security false alarms
@ -399,12 +396,6 @@ endforeach()
# test section
if (OCOS_ENABLE_CTEST)
# Enable CTest
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH)
find_library(ONNXRUNTIME onnxruntime HINTS "${ONNXRUNTIME_LIB_DIR}")
if (NOT ONNXRUNTIME)
message(FATAL_ERROR "The ctest needs the prebuilt onnxruntime libraries directory, please specify it by ONNXRUNTIME_LIB_DIR.")
endif()
enable_testing()
message(STATUS "Fetch CTest")
include(CTest)
@ -413,11 +404,17 @@ if (OCOS_ENABLE_CTEST)
message(STATUS "Fetch googletest")
include(googletest)
file(GLOB static_TEST_SRC "${TEST_SRC_DIR}/static_test/*.cc")
add_executable(operators_test ${static_TEST_SRC})
standardize_output_folder(operators_test)
target_link_libraries(operators_test PRIVATE gtest_main ocos_operators ${ocos_libraries})
add_test(NAME operators_test COMMAND $<TARGET_FILE:operators_test>)
add_executable(ocos_test ${static_TEST_SRC})
standardize_output_folder(ocos_test)
target_link_libraries(ocos_test PRIVATE gtest_main ocos_operators ${ocos_libraries})
add_test(NAME ocos_test COMMAND $<TARGET_FILE:ocos_test>)
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH)
find_library(ONNXRUNTIME onnxruntime HINTS "${ONNXRUNTIME_LIB_DIR}")
if (ONNXRUNTIME-NOTFOUND)
message(WARNING "The prebuilt onnxruntime libraries directory cannot found (via ONNXRUNTIME_LIB_DIR), the extensions_test will be skipped.")
else()
set(LINUX_CC_FLAGS "")
# needs to link with stdc++fs in Linux
if(UNIX AND NOT APPLE AND NOT CMAKE_SYSTEM_NAME STREQUAL "Android")
@ -425,18 +422,20 @@ if (OCOS_ENABLE_CTEST)
endif()
file(GLOB shared_TEST_SRC "${TEST_SRC_DIR}/shared_test/*.cc")
add_executable(ortcustomops_test ${shared_TEST_SRC})
standardize_output_folder(ortcustomops_test)
add_executable(extensions_test ${shared_TEST_SRC})
standardize_output_folder(extensions_test)
target_include_directories(extensions_test PRIVATE ${spm_INCLUDE_DIRS}
"$<TARGET_PROPERTY:extensions_shared,INTERFACE_INCLUDE_DIRECTORIES>")
if (ONNXRUNTIME_LIB_DIR)
target_link_directories(ortcustomops_test PRIVATE ${ONNXRUNTIME_LIB_DIR})
target_link_directories(extensions_test PRIVATE ${ONNXRUNTIME_LIB_DIR})
endif()
target_link_libraries(ortcustomops_test PRIVATE ortcustomops onnxruntime gtest_main ${ocos_libraries} ${LINUX_CC_FLAGS})
target_link_libraries(extensions_test PRIVATE ocos_operators extensions_shared onnxruntime gtest_main ${ocos_libraries} ${LINUX_CC_FLAGS})
if (WIN32)
file(TO_CMAKE_PATH "${ONNXRUNTIME_LIB_DIR}/*" ONNXRUNTIME_LIB_FILEPATTERN)
file(GLOB ONNXRUNTIME_LIB_FILES CONFIGURE_DEPENDS "${ONNXRUNTIME_LIB_FILEPATTERN}")
add_custom_command(
TARGET ortcustomops_test POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${ONNXRUNTIME_LIB_FILES} $<TARGET_FILE_DIR:ortcustomops_test>)
TARGET extensions_test POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${ONNXRUNTIME_LIB_FILES} $<TARGET_FILE_DIR:extensions_test>)
endif()
set(TEST_DATA_SRC ${TEST_SRC_DIR}/data)
@ -444,9 +443,10 @@ if (OCOS_ENABLE_CTEST)
# Copy test data from source to destination.
add_custom_command(
TARGET ortcustomops_test POST_BUILD
TARGET extensions_test POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
${TEST_DATA_SRC}
${TEST_DATA_DES})
add_test(NAME ortcustomops_test COMMAND $<TARGET_FILE:ortcustomops_test>)
add_test(NAME extensions_test COMMAND $<TARGET_FILE:extensions_test>)
endif()
endif()

Просмотреть файл

@ -1,22 +1,27 @@
#!/bin/bash
# The example file on building the static library for android
# The example build file on building Android package.
set -e -x -u
OSNAME=android
if [[ -z ${NDK_ROOT+x} ]]; then NDK_ROOT=`ls -d $HOME/Android/Sdk/ndk/* 2>/dev/null`; fi
if [[ -z ${NDK_ROOT+x} ]]; then NDK_ROOT=`ls -Ad $HOME/Android/Sdk/ndk/* 2>/dev/null | head -1`; fi
if [[ -z "${NDK_ROOT}" ]]
then
echo "ERROR: cannot find where NDK was installed, using NDK_ROOT to specify it"
exit 7
fi
if [[ -z ${ANDROID_SDK_ROOT+x} ]]; then
export ANDROID_SDK_ROOT=$(dirname $(dirname ${NDK_ROOT}))
fi
mkdir -p out/$OSNAME/Release && cd out/$OSNAME/Release
# ANDROID_ABI would be armeabi-v7a arm64-v8a x86 x86_64
# ANDROID_PLATFORM, the minimum level is 24, i.e., due to
# the great change of file system permission in Android 7
cmake "$@" \
-DCMAKE_TOOLCHAIN_FILE=${NDK_ROOT}/build/cmake/android.toolchain.cmake \
-DANDROID_NDK=${NDK_ROOT} \
-DANDROID_ABI=armeabi-v7a \
-DANDROID_PLATFORM=android-19 \
-DOCOS_ENABLE_SPM_TOKENIZER=ON \
-DANDROID_PLATFORM=android-24 \
-DOCOS_BUILD_ANDROID=ON \
../../.. && cmake --build . --config Release --parallel

Просмотреть файл

@ -3,7 +3,7 @@ SETLOCAL ENABLEDELAYEDEXPANSION
IF DEFINED VSINSTALLDIR GOTO :VSDEV_CMD
IF NOT DEFINED VCVARS GOTO :NOT_FOUND
CALL %VCVARS%
CALL "%VCVARS%"
:VSDEV_CMD
set GENERATOR="Visual Studio 16 2019"

193
cmake/ext_java.cmake Normal file
Просмотреть файл

@ -0,0 +1,193 @@
include(FindJava)
find_package(Java REQUIRED)
include(UseJava)
if (NOT CMAKE_SYSTEM_NAME STREQUAL "Android")
find_package(JNI REQUIRED)
endif()
set(JAVA_ROOT ${PROJECT_SOURCE_DIR}/java)
set(JAVA_OUTPUT_TEMP ${CMAKE_CURRENT_BINARY_DIR}/java-temp)
set(JAVA_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/java)
# use the gradle wrapper if it exists
if(EXISTS "${JAVA_ROOT}/gradlew")
set(GRADLE_EXECUTABLE "${JAVA_ROOT}/gradlew")
else()
# fall back to gradle on our PATH
find_program(GRADLE_EXECUTABLE gradle)
if(NOT GRADLE_EXECUTABLE)
message(SEND_ERROR "Gradle installation not found")
endif()
endif()
message(STATUS "Using gradle: ${GRADLE_EXECUTABLE}")
# Specify the Java source files
file(GLOB_RECURSE onnxruntime_extensions4j_gradle_files "${JAVA_ROOT}/*.gradle")
file(GLOB_RECURSE onnxruntime_extensions4j_src "${JAVA_ROOT}/src/main/java/ai/onnxruntime/extensions/*.java")
set(JAVA_OUTPUT_JAR ${JAVA_OUTPUT_TEMP}/build/libs/onnxruntime_extensions.jar)
# this jar is solely used to signaling mechanism for dependency management in CMake
# if any of the Java sources change, the jar (and generated headers) will be regenerated and the onnxruntime_extensions4j_jni target will be rebuilt
set(GRADLE_ARGS --console=plain clean jar -p ${JAVA_ROOT} -x test )
if(WIN32)
set(GRADLE_ARGS ${GRADLE_ARGS} -Dorg.gradle.daemon=false)
elseif (CMAKE_SYSTEM_NAME STREQUAL "Android")
# For Android build, we may run gradle multiple times in same build,
# sometimes gradle JVM will run out of memory if we keep the daemon running
# it is better to not keep a daemon running
set(GRADLE_ARGS ${GRADLE_ARGS} --no-daemon)
endif()
file(MAKE_DIRECTORY ${JAVA_OUTPUT_TEMP})
add_custom_command(OUTPUT ${JAVA_OUTPUT_JAR} COMMAND ${GRADLE_EXECUTABLE} ${GRADLE_ARGS} WORKING_DIRECTORY ${JAVA_OUTPUT_TEMP} DEPENDS ${onnxruntime_extensions4j_gradle_files} ${onnxruntime_extensions4j_src})
add_custom_target(onnxruntime_extensions4j DEPENDS ${JAVA_OUTPUT_JAR})
set_source_files_properties(${JAVA_OUTPUT_JAR} PROPERTIES GENERATED TRUE)
set_property(TARGET onnxruntime_extensions4j APPEND PROPERTY ADDITIONAL_CLEAN_FILES "${JAVA_OUTPUT_DIR}")
# Specify the native sources
file(GLOB onnxruntime_extensions4j_native_src
"${JAVA_ROOT}/src/main/native/*.c"
"${JAVA_ROOT}/src/main/native/*.h"
"${PROJECT_SOURCE_DIR}/include/*.h"
)
# Build the JNI library
add_library(onnxruntime_extensions4j_jni SHARED ${onnxruntime_extensions4j_native_src})
# depend on java sources. if they change, the JNI should recompile
add_dependencies(onnxruntime_extensions4j_jni onnxruntime_extensions4j)
target_include_directories(onnxruntime_extensions4j_jni PRIVATE ortcustomops)
# the JNI headers are generated in the onnxruntime_extensions4j target
target_include_directories(onnxruntime_extensions4j_jni PRIVATE ${JAVA_ROOT}/build/headers ${JNI_INCLUDE_DIRS})
target_link_libraries(onnxruntime_extensions4j_jni PRIVATE ortcustomops)
standardize_output_folder(onnxruntime_extensions4j_jni)
set(JAVA_PACKAGE_OUTPUT_DIR ${JAVA_OUTPUT_DIR}/build)
file(MAKE_DIRECTORY ${JAVA_PACKAGE_OUTPUT_DIR})
if (CMAKE_SYSTEM_NAME STREQUAL "Android")
set(ANDROID_PACKAGE_OUTPUT_DIR ${JAVA_PACKAGE_OUTPUT_DIR}/android)
file(MAKE_DIRECTORY ${ANDROID_PACKAGE_OUTPUT_DIR})
endif()
if (CMAKE_SYSTEM_NAME STREQUAL "Android")
if (OCOS_ENABLE_SPM_TOKENIZER)
target_link_libraries(onnxruntime_extensions4j_jni PUBLIC log)
endif()
endif()
# Set platform and arch for packaging
# Checks the names set by MLAS on non-Windows platforms first
if(APPLE)
get_target_property(ONNXRUNTIME4J_OSX_ARCH onnxruntime_extensions4j_jni OSX_ARCHITECTURES)
list(LENGTH ONNXRUNTIME4J_OSX_ARCH ONNXRUNTIME4J_OSX_ARCH_LEN)
if(ONNXRUNTIME4J_OSX_ARCH)
if(ONNXRUNTIME4J_OSX_ARCH_LEN LESS_EQUAL 1)
list(GET ONNXRUNTIME4J_OSX_ARCH 0 JNI_ARCH)
message("Set Java ARCH TO macOS/iOS ${JNI_ARCH}")
else()
message(FATAL_ERROR "Java is currently not supported for macOS universal")
endif()
else()
set(JNI_ARCH ${CMAKE_HOST_SYSTEM_PROCESSOR})
message("Set Java ARCH TO macOS/iOS ${JNI_ARCH}")
endif()
if(JNI_ARCH STREQUAL "x86_64")
set(JNI_ARCH x64)
elseif(JNI_ARCH STREQUAL "arm64")
set(JNI_ARCH aarch64)
endif()
elseif (CMAKE_SYSTEM_NAME STREQUAL "Android")
set(JNI_ARCH ${ANDROID_ABI})
elseif (CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
set(JNI_ARCH x64)
else()
# Now mirror the checks used with MSVC
if(MSVC)
if(CMAKE_GENERATOR_PLATFORM STREQUAL "ARM64")
set(JNI_ARCH aarch64)
elseif(CMAKE_GENERATOR_PLATFORM STREQUAL "x64")
set(JNI_ARCH x64)
else()
# if everything else failed then we're on a 32-bit arch and Java isn't supported
message(FATAL_ERROR "Java is currently not supported on 32-bit x86 architecture")
endif()
else()
# if everything else failed then we're on a 32-bit arch and Java isn't supported
message(FATAL_ERROR "Java is currently not supported on 32-bit x86 architecture")
endif()
endif()
if (WIN32)
set(JAVA_PLAT "win")
elseif (APPLE)
set(JAVA_PLAT "osx")
elseif (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
set(JAVA_PLAT "linux")
else()
# We don't do distribution for Android
# Set for completeness
set(JAVA_PLAT "android")
endif()
# Similar to Nuget schema
set(JAVA_OS_ARCH ${JAVA_PLAT}-${JNI_ARCH})
# expose native libraries to the gradle build process
set(JAVA_PACKAGE_DIR ai/onnxruntime/extensions/native/${JAVA_OS_ARCH})
set(JAVA_NATIVE_LIB_DIR ${JAVA_OUTPUT_DIR}/native-lib)
set(JAVA_NATIVE_JNI_DIR ${JAVA_OUTPUT_DIR}/native-jni)
set(JAVA_PACKAGE_LIB_DIR ${JAVA_NATIVE_LIB_DIR}/${JAVA_PACKAGE_DIR})
set(JAVA_PACKAGE_JNI_DIR ${JAVA_NATIVE_JNI_DIR}/${JAVA_PACKAGE_DIR})
file(MAKE_DIRECTORY ${JAVA_PACKAGE_LIB_DIR})
file(MAKE_DIRECTORY ${JAVA_PACKAGE_JNI_DIR})
# On Windows TARGET_LINKER_FILE_NAME is the .lib, TARGET_FILE_NAME is the .dll
if (WIN32)
#Our static analysis plugin set /p:LinkCompiled=false
if(NOT onnxruntime_extensions_ENABLE_STATIC_ANALYSIS)
add_custom_command(TARGET onnxruntime_extensions4j_jni POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:onnxruntime_extensions> ${JAVA_PACKAGE_LIB_DIR}/$<TARGET_FILE_NAME:onnxruntime_extensions>)
add_custom_command(TARGET onnxruntime_extensions4j_jni POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:onnxruntime_extensions4j_jni> ${JAVA_PACKAGE_JNI_DIR}/$<TARGET_FILE_NAME:onnxruntime_extensions4j_jni>)
endif()
else()
add_custom_command(TARGET onnxruntime_extensions4j_jni POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:onnxruntime_extensions> ${JAVA_PACKAGE_LIB_DIR}/$<TARGET_LINKER_FILE_NAME:onnxruntime_extensions>)
add_custom_command(TARGET onnxruntime_extensions4j_jni POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:onnxruntime_extensions4j_jni> ${JAVA_PACKAGE_JNI_DIR}/$<TARGET_LINKER_FILE_NAME:onnxruntime_extensions4j_jni>)
endif()
# run the build process (this copies the results back into CMAKE_CURRENT_BINARY_DIR)
set(GRADLE_ARGS --console=plain cmakeBuild -p ${JAVA_ROOT} -DcmakeBuildDir=${CMAKE_CURRENT_BINARY_DIR})
if(WIN32)
set(GRADLE_ARGS ${GRADLE_ARGS} -Dorg.gradle.daemon=false)
elseif (CMAKE_SYSTEM_NAME STREQUAL "Android")
# For Android build, we may run gradle multiple times in same build,
# sometimes gradle JVM will run out of memory if we keep the daemon running
# it is better to not keep a daemon running
set(GRADLE_ARGS ${GRADLE_ARGS} --no-daemon)
endif()
message(STATUS "GRADLE_ARGS: ${GRADLE_ARGS}")
add_custom_command(TARGET onnxruntime_extensions4j_jni POST_BUILD COMMAND ${GRADLE_EXECUTABLE} ${GRADLE_ARGS} WORKING_DIRECTORY ${JAVA_OUTPUT_TEMP})
if (CMAKE_SYSTEM_NAME STREQUAL "Android")
set(ANDROID_PACKAGE_JNILIBS_DIR ${JAVA_OUTPUT_DIR}/android)
set(ANDROID_PACKAGE_ABI_DIR ${ANDROID_PACKAGE_JNILIBS_DIR}/${ANDROID_ABI})
file(MAKE_DIRECTORY ${ANDROID_PACKAGE_JNILIBS_DIR})
file(MAKE_DIRECTORY ${ANDROID_PACKAGE_ABI_DIR})
# Copy onnxruntime_extensions.so and onnxruntime_extensions4j_jni.so for building Android AAR package
add_custom_command(TARGET onnxruntime_extensions4j_jni POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:onnxruntime_extensions> ${ANDROID_PACKAGE_ABI_DIR}/$<TARGET_LINKER_FILE_NAME:onnxruntime_extensions>)
add_custom_command(TARGET onnxruntime_extensions4j_jni POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:onnxruntime_extensions4j_jni> ${ANDROID_PACKAGE_ABI_DIR}/$<TARGET_LINKER_FILE_NAME:onnxruntime_extensions4j_jni>)
# Generate the Android AAR package
add_custom_command(TARGET onnxruntime_extensions4j_jni POST_BUILD COMMAND ${GRADLE_EXECUTABLE} -b build-android.gradle -c settings-android.gradle build -DjniLibsDir=${ANDROID_PACKAGE_JNILIBS_DIR} -DbuildDir=${ANDROID_PACKAGE_OUTPUT_DIR} -DminSdkVer=${ANDROID_MIN_SDK} -DheadersDir=${ANDROID_HEADERS_DIR} WORKING_DIRECTORY ${JAVA_ROOT})
if (onnxruntime_extensions_BUILD_UNIT_TESTS)
set(ANDROID_TEST_PACKAGE_ROOT ${JAVA_ROOT}/src/test/android)
set(ANDROID_TEST_PACKAGE_DIR ${JAVA_OUTPUT_DIR}/androidtest/android)
#copy the androidtest project into cmake binary directory
file(MAKE_DIRECTORY ${JAVA_OUTPUT_DIR}/androidtest)
file(COPY ${ANDROID_TEST_PACKAGE_ROOT} DESTINATION ${JAVA_OUTPUT_DIR}/androidtest)
set(ANDROID_TEST_PACKAGE_LIB_DIR ${ANDROID_TEST_PACKAGE_DIR}/app/libs)
file(MAKE_DIRECTORY ${ANDROID_TEST_PACKAGE_LIB_DIR})
# Copy the built Android AAR package to libs folder of our test app
add_custom_command(TARGET onnxruntime_extensions4j_jni POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different ${ANDROID_PACKAGE_OUTPUT_DIR}/outputs/aar/onnxruntime_extensions-debug.aar ${ANDROID_TEST_PACKAGE_LIB_DIR}/onnxruntime_extensions-mobile.aar)
# Build Android test apk for java package
add_custom_command(TARGET onnxruntime_extensions4j_jni POST_BUILD COMMAND ${GRADLE_EXECUTABLE} clean WORKING_DIRECTORY ${ANDROID_TEST_PACKAGE_DIR})
add_custom_command(TARGET onnxruntime_extensions4j_jni POST_BUILD COMMAND ${GRADLE_EXECUTABLE} assembleDebug assembleDebugAndroidTest -DminSdkVer=${ANDROID_MIN_SDK} WORKING_DIRECTORY ${ANDROID_TEST_PACKAGE_DIR})
endif()
endif()

39
cmake/ext_python.cmake Normal file
Просмотреть файл

@ -0,0 +1,39 @@
set(Python3_FIND_REGISTRY NEVER CACHE STRING "...")
if(NOT "${Python3_FIND_REGISTRY}" STREQUAL "NEVER")
message(FATAL_ERROR "Python3_FIND_REGISTRY is not NEVER")
endif()
find_package(Python3 COMPONENTS Interpreter Development.Module NumPy)
if (NOT Python3_FOUND)
message(FATAL_ERROR "Python3 or NumPy not found!")
endif()
if (WIN32)
list(APPEND shared_TARGET_SRC "${PROJECT_SOURCE_DIR}/pyop/extensions_pydll.def")
endif()
file(GLOB TARGET_SRC_PYOPS "pyop/*.cc" "pyop/*.h" "shared/*.cc")
add_library(extensions_pydll SHARED ${TARGET_SRC_PYOPS} ${shared_TARGET_LIB_SRC})
standardize_output_folder(extensions_pydll)
list(APPEND OCOS_COMPILE_DEFINITIONS PYTHON_OP_SUPPORT)
target_compile_definitions(extensions_pydll PRIVATE ${OCOS_COMPILE_DEFINITIONS})
message(STATUS "Fetch pybind11")
include(pybind11)
target_include_directories(extensions_pydll PRIVATE
${pybind11_INCLUDE_DIRS}
$<TARGET_PROPERTY:Python3::Module,INTERFACE_INCLUDE_DIRECTORIES>
$<TARGET_PROPERTY:Python3::NumPy,INTERFACE_INCLUDE_DIRECTORIES>
$<TARGET_PROPERTY:ocos_operators,INTERFACE_INCLUDE_DIRECTORIES>)
target_compile_definitions(extensions_pydll PRIVATE
$<TARGET_PROPERTY:Python3::Module,INTERFACE_COMPILE_DEFINITIONS>)
target_link_libraries(extensions_pydll PRIVATE Python3::Module ocos_operators)
if(NOT "${OCOS_EXTENTION_NAME}" STREQUAL "")
if(NOT WIN32)
set_target_properties(extensions_pydll PROPERTIES
LIBRARY_OUTPUT_NAME ${OCOS_EXTENTION_NAME}
PREFIX ""
SUFFIX "")
endif()
endif()

Просмотреть файл

@ -1,37 +0,0 @@
# The pre/post processing code to ONNX model
Most pre and post processing of the DL models are written in Python code, when the user running the converted ONNX model with Python snippets, it would be very efficient and productive to convert these code snippets into the ONNX model, since the ONNX graph is actually a computation graph, it can represent the most programming code, theoretically.
In the onnxruntime_extensions package, there is a utility to help on that. This tool is to trace the data flow in the processing code and convert all operation in the tracing logging into the ONNX graph, and merge all these graphs into in one single ONNX model. It supports the Python numeric operators and PyTorch's operation APIs (only a subset of the tensor API)
###Usage
In the onnxruntime_extensions.utils, there is an API ```trace_for_onnx```, when it was fed with the input variables in Python code, it start a tracing session to log all operation starting from these variables. Also if there are some PyTorch API calls in the processing code, you need replace the import statement from ```import torch``` to ```from onnxruntime_extensions.onnxprocess import torch_wrapper as torch```, which will enable these PyTorch API can be traced as well.
Overall, it will look like:
```python
from onnxruntime_extensions.onnxprocess import trace_for_onnx
from onnxruntime_extensions.onnxprocess import torch_wrapper as torch # overload torch API if it is needed
# the raw input, like text, image, or ...
input_text = ...
with trace_for_onnx(input_text, names=['string_input']) as tc_sess:
# The pre or/and post processing code starts
...
...
...
output = ...
# Save all trace objects into an ONNX model
tc_sess.save_to_onnx('<all_in_one.onnx>', output)
```
Then the all-in-one model can be inference from the raw text directly
```python
from onnxruntime_extensions.eager_op import EagerOp
# the input raw text
input_text = ...
full_model = EagerOp.from_model('<all_in_one.onnx>')
output = full_model(input_text)
print(output)
```
Or you do inference on this model with any other programming ONNXRuntime API, like C++, C#, Java and etc.

Просмотреть файл

@ -105,7 +105,6 @@ const OrtCustomOp** LoadCustomOpClasses() {
#if defined(PYTHON_OP_SUPPORT)
const OrtCustomOp* FetchPyCustomOps(size_t& count);
OrtStatusPtr RegisterPythonDomainAndOps(OrtSessionOptions*, const OrtApi*);
bool EnablePyCustomOps(bool enable = true);
#endif
#ifdef ENABLE_MATH

Просмотреть файл

@ -4,11 +4,17 @@
#pragma once
#include "onnxruntime_c_api.h"
#ifdef _WIN32
#define ORTX_EXPORT __declspec(dllexport)
#else
#define ORTX_EXPORT
#endif
#ifdef __cplusplus
extern "C" {
#endif
OrtStatus* ORT_API_CALL RegisterCustomOps(OrtSessionOptions* options, const OrtApiBase* api);
ORTX_EXPORT OrtStatus* ORT_API_CALL RegisterCustomOps(OrtSessionOptions* options, const OrtApiBase* api);
#ifdef __cplusplus
}

27
java/README.md Normal file
Просмотреть файл

@ -0,0 +1,27 @@
# ONNXRuntime-Extensions Java/Android API and Package
This java and Android API and packaging principles were inspired by the https://github.com/microsoft/onnxruntime/tree/main/java, and openly share credits for API with the contributors in onnxruntime repo.
<br />
## Building
<br />
### Tools required
1. install visual studio 2022 (with cmake, git, desktop C++)
2. OpenJDK: https://docs.microsoft.com/en-us/java/openjdk/download
(OpenJDK 11.0.15 LTS)
3. Gradle: https://gradle.org/releases/
(v6.9.2)
### Build command
./build.sh **-DOCOS_BUILD_JAVA=ON**
and find onnxruntime-extensions-0.5.0.jar at out/$OS/$CMake_BUILD_TYPE/java/build/libs
<br />
## Usage
There is a Java example project checked in tutorial folder, [demo4j](../tutorials/demo4j) which provide a showcase how extensions package works with ONNXRuntime's Java API

167
java/build-android.gradle Normal file
Просмотреть файл

@ -0,0 +1,167 @@
apply plugin: 'com.android.library'
apply plugin: 'maven-publish'
def jniLibsDir = System.properties['jniLibsDir']
def buildDir = System.properties['buildDir']
def headersDir = System.properties['headersDir']
def publishDir = System.properties['publishDir']
def minSdkVer = System.properties['minSdkVer']
def targetSdkVer = System.properties['targetSdkVer']
def buildVariant = System.properties['buildVariant'] ?: "Full"
boolean isMobileBuild = (buildVariant == "Mobile")
// Since Android requires a higher numbers indicating more recent versions
// This function assume ORT version number will be in formart of A.B.C such as 1.7.0
// We generate version code A[0{0,1}]B[0{0,1}]C,
// for example '1.7.0' -> 10700, '1.6.15' -> 10615
def getVersionCode(String version){
String[] codes = version.split('\\.');
// This will have problem if we have 3 digit [sub]version number, such as 1.7.199
// but it is highly unlikely to happen
String versionCodeStr = String.format("%d%02d%02d", codes[0] as int, codes[1] as int, codes[2] as int);
return versionCodeStr as int;
}
project.buildDir = buildDir
project.version = rootProject.file('../.version.txt').text.trim()
project.group = "com.microsoft.onnxruntime.extensions"
def mavenArtifactId = isMobileBuild ? project.name + '-mobile' : project.name + '-android'
def mobileDescription = 'ONNXRuntime-Extensions Mobile is a library for Android for pre- and post-processing on inference.'
def defaultDescription = 'ONNXRuntime-Extensions is a library for Android for pre- and post-processing on inference.'
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:4.0.1'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
mavenCentral()
}
}
android {
compileSdkVersion 29
buildToolsVersion "29.0.2"
defaultConfig {
minSdkVersion minSdkVer
targetSdkVersion targetSdkVer
versionCode = getVersionCode(project.version)
versionName = project.version
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
android {
lintOptions {
abortOnError false
}
}
buildTypes {
release {
minifyEnabled false
debuggable false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
sourceSets {
main {
jniLibs.srcDirs = [jniLibsDir]
}
}
}
task sourcesJar(type: Jar) {
classifier "sources"
from android.sourceSets.main.java.srcDirs
}
task javadoc(type: Javadoc) {
source = android.sourceSets.main.java.srcDirs
classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
}
task javadocJar(type: Jar, dependsOn: javadoc) {
classifier = 'javadoc'
from javadoc.destinationDir
}
artifacts {
archives javadocJar
archives sourcesJar
}
dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0'
testImplementation 'com.google.protobuf:protobuf-java:3.20.1'
}
publishing {
publications {
maven(MavenPublication) {
groupId = project.group
artifactId = mavenArtifactId
version = project.version
// Three artifacts, the `aar`, the sources and the javadoc
artifact("$buildDir/outputs/aar/${project.name}-release.aar")
artifact javadocJar
artifact sourcesJar
pom {
name = 'onnxruntime-extensions'
description = isMobileBuild ? mobileDescription : defaultDescription
url = 'https://microsoft.github.io/onnxruntime/'
licenses {
license {
name = 'MIT License'
url = 'https://opensource.org/licenses/MIT'
}
}
organization {
name = 'Microsoft'
url = 'http://www.microsoft.com'
}
scm {
connection = 'scm:git:git://github.com:microsoft/onnxruntime-extensions.git'
developerConnection = 'scm:git:ssh://github.com/microsoft/onnxruntime-extensions.git'
url = 'http://github.com/microsoft/onnxruntime-extensions'
}
developers {
developer {
id = 'onnxruntime'
name = 'ONNX Runtime'
email = 'onnxruntime@microsoft.com'
}
}
}
}
}
//publish to filesystem repo
repositories{
maven {
url "$publishDir"
}
}
}

249
java/build.gradle Normal file
Просмотреть файл

@ -0,0 +1,249 @@
plugins {
id 'java-library'
id 'maven-publish'
id 'signing'
id 'jacoco'
id 'com.diffplug.spotless' version '5.17.0'
}
allprojects {
repositories {
mavenCentral()
}
}
project.group = "com.microsoft.onnxruntime"
version = rootProject.file('../.version.txt').text.trim()
// cmake runs will inform us of the build directory of the current run
def cmakeBuildDir = System.properties['cmakeBuildDir']
def cmakeJavaDir = "${cmakeBuildDir}/java"
def cmakeNativeLibDir = "${cmakeJavaDir}/native-lib"
def cmakeNativeJniDir = "${cmakeJavaDir}/native-jni"
def cmakeNativeTestDir = "${cmakeJavaDir}/native-test"
def cmakeBuildOutputDir = "${cmakeJavaDir}/build"
def mavenUser = System.properties['mavenUser']
def mavenPwd = System.properties['mavenPwd']
def mavenArtifactId = project.name
java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
// This jar tasks serves as a CMAKE signalling
// mechanism. The jar will be overwritten by allJar task
jar {
}
// Add explicit sources jar with pom file.
task sourcesJar(type: Jar, dependsOn: classes) {
classifier = "sources"
from sourceSets.main.allSource
into("META-INF/maven/$project.group/$mavenArtifactId") {
from { generatePomFileForMavenPublication }
rename ".*", "pom.xml"
}
}
// Add explicit javadoc jar with pom file
task javadocJar(type: Jar, dependsOn: javadoc) {
classifier = "javadoc"
from javadoc.destinationDir
into("META-INF/maven/$project.group/$mavenArtifactId") {
from { generatePomFileForMavenPublication }
rename ".*", "pom.xml"
}
}
wrapper {
gradleVersion = '6.1.1'
}
spotless {
java {
removeUnusedImports()
googleJavaFormat()
}
format 'gradle', {
target '**/*.gradle'
trimTrailingWhitespace()
indentWithTabs()
}
}
compileJava {
dependsOn spotlessJava
options.compilerArgs += ["-h", "${project.buildDir}/headers/"]
if (!JavaVersion.current().isJava8()) {
// Ensures only methods present in Java 8 are used
options.compilerArgs.addAll(['--release', '8'])
// Gradle versions before 6.6 require that these flags are unset when using "-release"
java.sourceCompatibility = null
java.targetCompatibility = null
}
}
compileTestJava {
if (!JavaVersion.current().isJava8()) {
// Ensures only methods present in Java 8 are used
options.compilerArgs.addAll(['--release', '8'])
// Gradle versions before 6.6 require that these flags are unset when using "-release"
java.sourceCompatibility = null
java.targetCompatibility = null
}
}
sourceSets.test {
// add test resource files
resources.srcDirs += [
"${rootProject.projectDir}/../java/testdata"
]
if (cmakeBuildDir != null) {
// add compiled native libs
resources.srcDirs += [
cmakeNativeLibDir,
cmakeNativeJniDir,
cmakeNativeTestDir
]
}
}
if (cmakeBuildDir != null) {
// generate tasks to be called from cmake
// Overwrite jar location
task allJar(type: Jar) {
manifest {
attributes('Automatic-Module-Name': project.group,
'Implementation-Title': 'onnxruntime-extensions',
'Implementation-Version': project.version)
}
into("META-INF/maven/$project.group/$mavenArtifactId") {
from { generatePomFileForMavenPublication }
rename ".*", "pom.xml"
}
from sourceSets.main.output
from cmakeNativeJniDir
from cmakeNativeLibDir
}
task cmakeBuild(type: Copy) {
from project.buildDir
include 'libs/**'
include 'docs/**'
into cmakeBuildOutputDir
}
cmakeBuild.dependsOn allJar
cmakeBuild.dependsOn sourcesJar
cmakeBuild.dependsOn javadocJar
cmakeBuild.dependsOn javadoc
task cmakeCheck(type: Copy) {
from project.buildDir
include 'reports/**'
into cmakeBuildOutputDir
}
cmakeCheck.dependsOn check
}
dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0'
testImplementation 'com.google.protobuf:protobuf-java:3.20.1'
}
processTestResources {
duplicatesStrategy(DuplicatesStrategy.INCLUDE) // allows duplicates in the test resources
}
test {
java {
dependsOn spotlessJava
}
if (System.getProperty("JAVA_FULL_TEST") != null) {
// Forces each test class to be run in a separate JVM,
// which is necessary for testing the environment thread pool which is ignored if full test is not set.
forkEvery 1
}
useJUnitPlatform()
if (cmakeBuildDir != null) {
workingDir cmakeBuildDir
}
systemProperties System.getProperties().subMap(['JAVA_FULL_TEST'])
testLogging {
events "passed", "skipped", "failed"
showStandardStreams = true
showStackTraces = true
exceptionFormat = "full"
}
}
jacocoTestReport {
reports {
xml.enabled true
csv.enabled true
html.destination file("${buildDir}/jacocoHtml")
}
}
publishing {
publications {
maven(MavenPublication) {
groupId = project.group
artifactId = mavenArtifactId
from components.java
pom {
name = 'onnxruntime-extensions'
description = 'ONNXRuntime-Extensions is a library for Android for pre- and post-processing on inference.'
url = 'https://microsoft.github.io/onnxruntime/'
licenses {
license {
name = 'MIT License'
url = 'https://opensource.org/licenses/MIT'
}
}
organization {
name = 'Microsoft'
url = 'http://www.microsoft.com'
}
scm {
connection = 'scm:git:git://github.com:microsoft/onnxruntime-extensions.git'
developerConnection = 'scm:git:ssh://github.com/microsoft/onnxruntime-extensions.git'
url = 'http://github.com/microsoft/onnxruntime-extensions'
}
developers {
developer {
id = 'onnxruntime'
name = 'ONNX Runtime'
email = 'onnxruntime@microsoft.com'
}
}
}
}
}
repositories {
maven {
url 'https://oss.sonatype.org/service/local/staging/deploy/maven2/'
credentials {
username mavenUser
password mavenPwd
}
}
}
}
// Generates a task signMavenPublication that will
// build all artifacts.
signing {
// Queries env vars:
// ORG_GRADLE_PROJECT_signingKey
// ORG_GRADLE_PROJECT_signingPassword but can be changed to properties
def signingKey = findProperty("signingKey")
def signingPassword = findProperty("signingPassword")
useInMemoryPgpKeys(signingKey, signingPassword)
sign publishing.publications.maven
}

Просмотреть файл

@ -0,0 +1,2 @@
rootProject.name = 'onnxruntime-extensions'
rootProject.buildFileName = 'build-android.gradle'

1
java/settings.gradle Normal file
Просмотреть файл

@ -0,0 +1 @@
rootProject.name = 'onnxruntime-extensions'

Просмотреть файл

@ -0,0 +1,2 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="ai.onnxruntime.extensions" />

Просмотреть файл

@ -0,0 +1,128 @@
package ai.onnxruntime.extensions;
import java.io.*;
import java.nio.file.Files;
import java.util.Locale;
import java.nio.file.StandardCopyOption;
public final class OrtxLibrary {
// the default name in Android could be simple.
private static String libraryFileName = "onnxruntime_extensions4j_jni";
private static final String OS_ARCH_STR = getOsArch();
/**
* Check if we're running on Android.
*
* @return True if the property java.vendor equals The Android Project, false otherwise.
*/
static boolean isAndroid() {
return System.getProperty("java.vendor", "generic").equals("The Android Project");
}
/* Computes and initializes OS_ARCH_STR (such as linux-x64) */
private static String getOsArch() {
String detectedOS = null;
String os = System.getProperty("os.name", "generic").toLowerCase(Locale.ENGLISH);
if (os.contains("mac") || os.contains("darwin")) {
detectedOS = "osx";
} else if (os.contains("win")) {
detectedOS = "win";
} else if (os.contains("nux")) {
detectedOS = "linux";
} else if (isAndroid()) {
detectedOS = "android";
} else {
throw new IllegalStateException("Unsupported os:" + os);
}
String detectedArch = null;
String arch = System.getProperty("os.arch", "generic").toLowerCase(Locale.ENGLISH);
if (arch.startsWith("amd64") || arch.startsWith("x86_64")) {
detectedArch = "x64";
} else if (arch.startsWith("x86")) {
// 32-bit x86 is not supported by the Java API
detectedArch = "x86";
} else if (arch.startsWith("aarch64")) {
detectedArch = "aarch64";
} else if (arch.startsWith("ppc64")) {
detectedArch = "ppc64";
} else if (isAndroid()) {
detectedArch = arch;
} else {
throw new IllegalStateException("Unsupported arch:" + arch);
}
return detectedOS + '-' + detectedArch;
}
private static String getLibraryResourceName(){
return "/ai/onnxruntime/extensions/native/" + OS_ARCH_STR +
"/" + System.mapLibraryName("onnxruntime_extensions4j_jni");
}
static{
try{
File tempLibraryFile = null;
if (!isAndroid()) {
libraryFileName = getLibraryResourceName();
// Obtain filename from path
String[] parts = libraryFileName.split("/");
String filename = parts[parts.length - 1];
// Prepare temporary file
File temporaryDir = createTempDirectory("ortx4j");
temporaryDir.deleteOnExit();
tempLibraryFile = new File(temporaryDir, filename);
try (InputStream is = OrtxLibrary.class.getResourceAsStream(libraryFileName)) {
Files.copy(is, tempLibraryFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
tempLibraryFile.delete();
throw e;
} catch (NullPointerException e) {
tempLibraryFile.delete();
throw new FileNotFoundException("File " + libraryFileName + " was not found inside JAR.");
}
libraryFileName = tempLibraryFile.getAbsolutePath();
}
try {
if (isAndroid()) {
System.loadLibrary(libraryFileName);
}
else {
System.load(libraryFileName);
}
} finally {
if (tempLibraryFile != null) {
tempLibraryFile.deleteOnExit();
}
}
} catch(IOException e1){
throw new RuntimeException(e1);
}
}
public static String getExtractedLibraryPath() {
if (isAndroid()) {
return "lib" + libraryFileName + ".so";
}
else {
return libraryFileName;
}
}
private static File createTempDirectory(String prefix) throws IOException {
String tempDir = System.getProperty("java.io.tmpdir");
File generatedDir = new File(tempDir, prefix + System.nanoTime());
if (!generatedDir.mkdir())
throw new IOException("Failed to create temp directory " + generatedDir.getName());
return generatedDir;
}
public static native long getNativeExtensionOperatorRegister();
}

Просмотреть файл

@ -0,0 +1,25 @@
package ai.onnxruntime.extensions;
public final class OrtxPackage implements AutoCloseable {
private static volatile OrtxPackage INSTANCE;
public String getLibraryPath() {
return OrtxLibrary.getExtractedLibraryPath();
}
public static synchronized OrtxPackage getPackage() {
if (INSTANCE == null) {
return new OrtxPackage();
}
else {
return INSTANCE;
}
}
@Override
public void close() {
// Reserved
}
}

Просмотреть файл

@ -0,0 +1,11 @@
#include "ai_onnxruntime_extensions_OrtxLibrary.h"
#include "onnxruntime_extensions.h"
/*
* Class: ai_onnxruntime_extensions_OrtxLibrary
* Method: getNativeExtensionOperatorRegister
* Signature: ()J
*/
JNIEXPORT jlong JNICALL Java_ai_onnxruntime_extensions_Utils_getNativeExtensionOperatorRegister(JNIEnv* env, jclass cls) {
return (jlong)(&RegisterCustomOps);
}

Просмотреть файл

@ -0,0 +1,13 @@
package ai.onnxruntime.extensions;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
public class OrtxTest {
@Test
void getRegisterTest() {
long handle = OrtxLibrary.getNativeExtensionOperatorRegister();
Assertions.assertNotEquals(handle, Long.valueOf(0));
}
}

Просмотреть файл

@ -7,7 +7,7 @@ import sys
import copy
import onnx
from onnx import helper
from ._ortcustomops import ( # noqa
from ._extensions_pydll import ( # noqa
PyCustomOpDef, enable_py_op, add_custom_op, hash_64, default_opset_domain)
@ -16,7 +16,7 @@ def get_library_path():
The custom operator library binary path
:return: A string of the this library path.
"""
mod = sys.modules['onnxruntime_extensions._ortcustomops']
mod = sys.modules['onnxruntime_extensions._extensions_pydll']
return mod.__file__

Просмотреть файл

@ -1,4 +0,0 @@
LIBRARY "ortcustomops.dll"
EXPORTS
RegisterCustomOps @1
PyInit__ortcustomops @2

Просмотреть файл

@ -0,0 +1,4 @@
LIBRARY "extensions_pydll"
EXPORTS
RegisterCustomOps @1
PyInit__extensions_pydll @2

Просмотреть файл

@ -486,7 +486,7 @@ void AddObjectMethods(pybind11::module& m) {
.def_readonly_static("dt_bfloat16", &PyCustomOpDef::dt_bfloat16);
}
PYBIND11_MODULE(_ortcustomops, m) {
PYBIND11_MODULE(_extensions_pydll, m) {
m.doc() = "pybind11 stateful interface to ONNXRuntime-Extensions";
init_numpy();

Просмотреть файл

@ -92,3 +92,6 @@ struct PyCustomOpFactory : Ort::CustomOpBase<PyCustomOpFactory, PyCustomOpKernel
std::string op_type_;
std::string op_domain_;
};
bool EnablePyCustomOps(bool enable = true);

Просмотреть файл

@ -64,7 +64,7 @@ class BuildCMakeExt(_build_ext):
Perform build_cmake before doing the 'normal' stuff
"""
for extension in self.extensions:
if extension.name == 'onnxruntime_extensions._ortcustomops':
if extension.name == 'onnxruntime_extensions._extensions_pydll':
self.build_cmake(extension)
def build_cmake(self, extension):
@ -76,7 +76,7 @@ class BuildCMakeExt(_build_ext):
config = 'RelWithDebInfo' if self.debug else 'Release'
cmake_args = [
'-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=' + str(ext_fullpath.parent.absolute()),
'-DOCOS_ENABLE_PYTHON=ON',
'-DOCOS_BUILD_PYTHON=ON',
'-DOCOS_ENABLE_CTEST=OFF',
'-DOCOS_EXTENTION_NAME=' + ext_fullpath.name,
'-DCMAKE_BUILD_TYPE=' + config
@ -106,7 +106,7 @@ class BuildCMakeExt(_build_ext):
config_dir = '.'
if not (build_temp / 'build.ninja').exists():
config_dir = config
self.copy_file(build_temp / 'bin' / config_dir / 'ortcustomops.dll', ext_fullpath)
self.copy_file(build_temp / 'bin' / config_dir / 'extensions_pydll.dll', ext_fullpath)
else:
self.copy_file(build_temp / 'lib' / ext_fullpath.name, ext_fullpath)
@ -142,7 +142,7 @@ if sys.platform == "win32":
ext_modules = [
setuptools.extension.Extension(
name=str('onnxruntime_extensions._ortcustomops'),
name=str('onnxruntime_extensions._extensions_pydll'),
sources=[])
]
@ -186,9 +186,6 @@ setup(
'Operating System :: POSIX :: Linux',
"Programming Language :: C++",
'Programming Language :: Python',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
"Programming Language :: Python :: Implementation :: CPython",
'License :: OSI Approved :: MIT License'
]

5
shared/extensions.cc Normal file
Просмотреть файл

@ -0,0 +1,5 @@
// this is a stub C++ file for DLL/dlib/so generation
#include "onnxruntime_extensions.h"
// need a reference to a function from the static library for ld in Linux
auto exported_func_1 = &RegisterCustomOps;

Просмотреть файл

@ -62,7 +62,7 @@ extern "C" bool ORT_API_CALL AddExternalCustomOp(const OrtCustomOp* c_op) {
return true;
}
extern "C" OrtStatus* ORT_API_CALL RegisterCustomOps(OrtSessionOptions* options, const OrtApiBase* api) {
extern "C" ORTX_EXPORT OrtStatus* ORT_API_CALL RegisterCustomOps(OrtSessionOptions* options, const OrtApiBase* api) {
OrtCustomOpDomain* domain = nullptr;
const OrtApi* ortApi = api->GetApi(ORT_API_VERSION);
std::set<std::string> pyop_nameset;

Просмотреть файл

@ -1,4 +1,4 @@
LIBRARY "ortcustomops.dll"
LIBRARY "ortextensions.dll"
EXPORTS
RegisterCustomOps @1
AddExternalCustomOp @2

Просмотреть файл

@ -1,4 +1,6 @@
{ global:
RegisterCustomOps;
AddExternalCustomOp;
local: *; };
{
global:
RegisterCustomOps;
AddExternalCustomOp;
local: *;
};

Просмотреть файл

@ -13,13 +13,13 @@
const char* GetLibraryPath() {
#if defined(_WIN32)
return "ortcustomops.dll";
return "ortextensions.dll";
#elif defined(__APPLE__)
return "libortcustomops.dylib";
return "libortextensions.dylib";
#elif defined(ANDROID) || defined(__ANDROID__)
return "libortcustomops.so";
return "libortextensions.so";
#else
return "lib/libortcustomops.so";
return "lib/libortextensions.so";
#endif
}

6
tutorials/demo4j/.gitattributes поставляемый Normal file
Просмотреть файл

@ -0,0 +1,6 @@
#
# https://help.github.com/articles/dealing-with-line-endings/
#
# These are explicitly windows files and should use crlf
*.bat text eol=crlf

8
tutorials/demo4j/.gitignore поставляемый Normal file
Просмотреть файл

@ -0,0 +1,8 @@
# Ignore Gradle project-specific cache directory
.gradle
# Ignore Gradle build output directory
build
libs/
gradlew*
gradle-wrapper*

Просмотреть файл

@ -0,0 +1,4 @@
# How to start
1. copy JAR package from $REPO/out/$OS/RelWithDebInfo/java/build/libs/onnxruntime-extensions-${VERSION}.jar into app/libs folder.
2. build and run this java project.

Просмотреть файл

@ -0,0 +1,39 @@
/*
* This file was generated by the Gradle 'init' task.
*
* This generated file contains a sample Java application project to get you started.
* For more details take a look at the 'Building Java & JVM projects' chapter in the Gradle
* User Manual available at https://docs.gradle.org/7.3/userguide/building_java_projects.html
*/
plugins {
// Apply the application plugin to add support for building a CLI application in Java.
application
}
repositories {
// Use Maven Central for resolving dependencies.
mavenCentral()
}
dependencies {
// Use JUnit Jupiter for testing.
testImplementation("org.junit.jupiter:junit-jupiter:5.7.2")
// onnxruntime and its extensions package
implementation("com.microsoft.onnxruntime:onnxruntime:1.12.1")
implementation(files("libs/onnxruntime-extensions-0.5.0.jar"))
// This dependency is used by the application.
implementation("com.google.guava:guava:30.1.1-jre")
}
application {
// Define the main class for the application.
mainClass.set("demo4j.App")
}
tasks.named<Test>("test") {
// Use JUnit Platform for unit tests.
useJUnitPlatform()
}

Просмотреть файл

@ -0,0 +1,39 @@
/*
* This Java source file was generated by the Gradle 'init' task.
*/
package demo4j;
import java.util.Arrays;
import java.util.Map;
import java.nio.file.Paths;
import ai.onnxruntime.*;
import ai.onnxruntime.extensions.OrtxPackage;
public class App {
public String inference(){
try {
var env = OrtEnvironment.getEnvironment();
var sess_opt = new OrtSession.SessionOptions();
/* Register the custom ops from onnxruntime-extensions */
sess_opt.registerCustomOpLibrary(OrtxPackage.getPackage().getLibraryPath());
/* do a quick inference on Bert Tokenizer custom ops with Ort */
var modelPath = Paths.get(this.getClass().getClassLoader().getResource("test_bert_tokenizer.onnx").getPath());
var session = env.createSession(modelPath.toString(), sess_opt);
var t1 = OnnxTensor.createTensor(env, new String[]{"This is a test"});
var inputs = Map.of("text", t1);
try (var r = session.run(inputs)) {
long[] tokenIds = (long[])r.get("input_ids").get().getValue();
return Arrays.toString(tokenIds);
}
} catch(OrtException e1) {
return e1.getMessage();
}
}
public static void main(String[] args) {
System.out.println(new App().inference());
}
}

Двоичные данные
tutorials/demo4j/app/src/main/resources/test_bert_tokenizer.onnx Executable file

Двоичный файл не отображается.

Просмотреть файл

@ -0,0 +1,14 @@
/*
* This Java source file was generated by the Gradle 'init' task.
*/
package demo4j;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class AppTest {
@Test void appHasAGreeting() {
App classUnderTest = new App();
assertNotNull(classUnderTest.inference(), "app should have a greeting");
}
}

Просмотреть файл

@ -0,0 +1,11 @@
/*
* This file was generated by the Gradle 'init' task.
*
* The settings file is used to specify which projects to include in your build.
*
* Detailed information about configuring a multi-project build in Gradle can be found
* in the user manual at https://docs.gradle.org/7.3/userguide/multi_project_builds.html
*/
rootProject.name = "demo4j"
include("app")