Committed by
GitHub
Simplify the usage of our non-Android Java API (#2533)
This PR simplifies the usage of the non-Android Java API by providing platform-specific JAR files that include native shared libraries, eliminating the need for users to manually manage native dependencies. - Refactored LibraryUtils.java to support multiple library loading methods including extracting from JAR resources - Added build infrastructure to create platform-specific native library JAR files - Introduced debug capabilities and improved error handling for library loading
正在显示
7 个修改的文件
包含
471 行增加
和
81 行删除
.github/workflows/jar.yaml
0 → 100644
| 1 | +name: jar | ||
| 2 | + | ||
| 3 | +on: | ||
| 4 | + push: | ||
| 5 | + branches: | ||
| 6 | + - refactor-jar | ||
| 7 | + tags: | ||
| 8 | + - 'v[0-9]+.[0-9]+.[0-9]+*' | ||
| 9 | + | ||
| 10 | + workflow_dispatch: | ||
| 11 | + | ||
| 12 | +concurrency: | ||
| 13 | + group: jar-${{ github.ref }} | ||
| 14 | + cancel-in-progress: true | ||
| 15 | + | ||
| 16 | +permissions: | ||
| 17 | + contents: write | ||
| 18 | +jobs: | ||
| 19 | + jar: | ||
| 20 | + runs-on: ${{ matrix.os }} | ||
| 21 | + name: ${{ matrix.os }} ${{ matrix.arch }} | ||
| 22 | + strategy: | ||
| 23 | + fail-fast: false | ||
| 24 | + matrix: | ||
| 25 | + include: | ||
| 26 | + - os: ubuntu-24.04-arm | ||
| 27 | + arch: "arm64" | ||
| 28 | + | ||
| 29 | + - os: ubuntu-latest | ||
| 30 | + arch: "x64" | ||
| 31 | + | ||
| 32 | + - os: macos-latest | ||
| 33 | + arch: "arm64" | ||
| 34 | + | ||
| 35 | + - os: macos-13 | ||
| 36 | + arch: "x64" | ||
| 37 | + | ||
| 38 | + - os: windows-latest | ||
| 39 | + arch: "x64" | ||
| 40 | + | ||
| 41 | + steps: | ||
| 42 | + - uses: actions/checkout@v4 | ||
| 43 | + with: | ||
| 44 | + fetch-depth: 0 | ||
| 45 | + | ||
| 46 | + - uses: actions/setup-java@v4 | ||
| 47 | + with: | ||
| 48 | + distribution: 'temurin' # See 'Supported distributions' for available options | ||
| 49 | + java-version: '21' | ||
| 50 | + | ||
| 51 | + - name: Show java version | ||
| 52 | + shell: bash | ||
| 53 | + run: | | ||
| 54 | + java --version | ||
| 55 | + | ||
| 56 | + - name: Download libs ${{ matrix.os }} ${{ matrix.arch }} | ||
| 57 | + if: ${{ matrix.os == 'ubuntu-24.04-arm' && matrix.arch == 'arm64' }} | ||
| 58 | + shell: bash | ||
| 59 | + run: | | ||
| 60 | + SHERPA_ONNX_VERSION=$(grep "SHERPA_ONNX_VERSION" ./CMakeLists.txt | cut -d " " -f 2 | cut -d '"' -f 2) | ||
| 61 | + curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/v$SHERPA_ONNX_VERSION/sherpa-onnx-v$SHERPA_ONNX_VERSION-linux-aarch64-jni.tar.bz2 | ||
| 62 | + tar xvf ./*.tar.bz2 | ||
| 63 | + | ||
| 64 | + src=sherpa-onnx-v$SHERPA_ONNX_VERSION-linux-aarch64-jni | ||
| 65 | + dst=sherpa-onnx/java-api/resources/sherpa-onnx/native/linux-aarch64 | ||
| 66 | + | ||
| 67 | + mkdir -p $dst | ||
| 68 | + cp -v $src/lib/libsherpa-onnx-jni.so $dst/ | ||
| 69 | + cp -v $src/lib/libonnxruntime.so $dst/ | ||
| 70 | + | ||
| 71 | + ls -lh $dst | ||
| 72 | + rm -rf $src* | ||
| 73 | + | ||
| 74 | + - name: Download libs ${{ matrix.os }} ${{ matrix.arch }} | ||
| 75 | + if: ${{ matrix.os == 'ubuntu-latest' && matrix.arch == 'x64' }} | ||
| 76 | + shell: bash | ||
| 77 | + run: | | ||
| 78 | + SHERPA_ONNX_VERSION=$(grep "SHERPA_ONNX_VERSION" ./CMakeLists.txt | cut -d " " -f 2 | cut -d '"' -f 2) | ||
| 79 | + curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/v$SHERPA_ONNX_VERSION/sherpa-onnx-v$SHERPA_ONNX_VERSION-linux-x64-jni.tar.bz2 | ||
| 80 | + tar xvf ./*.tar.bz2 | ||
| 81 | + | ||
| 82 | + src=sherpa-onnx-v$SHERPA_ONNX_VERSION-linux-x64-jni | ||
| 83 | + dst=sherpa-onnx/java-api/resources/sherpa-onnx/native/linux-x64 | ||
| 84 | + | ||
| 85 | + mkdir -p $dst | ||
| 86 | + cp -v $src/lib/libsherpa-onnx-jni.so $dst/ | ||
| 87 | + cp -v $src/lib/libonnxruntime.so $dst/ | ||
| 88 | + | ||
| 89 | + ls -lh $dst | ||
| 90 | + rm -rf $src* | ||
| 91 | + | ||
| 92 | + - name: Download libs ${{ matrix.os }} ${{ matrix.arch }} | ||
| 93 | + if: ${{ matrix.os == 'macos-latest' && matrix.arch == 'arm64' }} | ||
| 94 | + shell: bash | ||
| 95 | + run: | | ||
| 96 | + SHERPA_ONNX_VERSION=$(grep "SHERPA_ONNX_VERSION" ./CMakeLists.txt | cut -d " " -f 2 | cut -d '"' -f 2) | ||
| 97 | + curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/v$SHERPA_ONNX_VERSION/sherpa-onnx-v$SHERPA_ONNX_VERSION-osx-arm64-jni.tar.bz2 | ||
| 98 | + tar xvf ./*.tar.bz2 | ||
| 99 | + | ||
| 100 | + src=sherpa-onnx-v$SHERPA_ONNX_VERSION-osx-arm64-jni | ||
| 101 | + dst=sherpa-onnx/java-api/resources/sherpa-onnx/native/osx-aarch64 | ||
| 102 | + | ||
| 103 | + mkdir -p $dst | ||
| 104 | + cp -v $src/lib/libonnxruntime.1.17.1.dylib $dst/ | ||
| 105 | + cp -v $src/lib/libsherpa-onnx-jni.dylib $dst/ | ||
| 106 | + | ||
| 107 | + ls -lh $dst | ||
| 108 | + rm -rf $src* | ||
| 109 | + | ||
| 110 | + - name: Download libs ${{ matrix.os }} ${{ matrix.arch }} | ||
| 111 | + if: ${{ matrix.os == 'macos-13' && matrix.arch == 'x64' }} | ||
| 112 | + shell: bash | ||
| 113 | + run: | | ||
| 114 | + SHERPA_ONNX_VERSION=$(grep "SHERPA_ONNX_VERSION" ./CMakeLists.txt | cut -d " " -f 2 | cut -d '"' -f 2) | ||
| 115 | + curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/v$SHERPA_ONNX_VERSION/sherpa-onnx-v$SHERPA_ONNX_VERSION-osx-x86_64-jni.tar.bz2 | ||
| 116 | + tar xvf ./*.tar.bz2 | ||
| 117 | + | ||
| 118 | + src=sherpa-onnx-v$SHERPA_ONNX_VERSION-osx-x86_64-jni | ||
| 119 | + dst=sherpa-onnx/java-api/resources/sherpa-onnx/native/osx-x64 | ||
| 120 | + | ||
| 121 | + mkdir -p $dst | ||
| 122 | + cp -v $src/lib/libonnxruntime.1.17.1.dylib $dst/ | ||
| 123 | + cp -v $src/lib/libsherpa-onnx-jni.dylib $dst/ | ||
| 124 | + | ||
| 125 | + ls -lh $dst | ||
| 126 | + rm -rf $src* | ||
| 127 | + | ||
| 128 | + - name: Download libs ${{ matrix.os }} ${{ matrix.arch }} | ||
| 129 | + if: ${{ matrix.os == 'windows-latest' && matrix.arch == 'x64' }} | ||
| 130 | + shell: bash | ||
| 131 | + run: | | ||
| 132 | + SHERPA_ONNX_VERSION=$(grep "SHERPA_ONNX_VERSION" ./CMakeLists.txt | cut -d " " -f 2 | cut -d '"' -f 2) | ||
| 133 | + curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/v$SHERPA_ONNX_VERSION/sherpa-onnx-v$SHERPA_ONNX_VERSION-win-x64-jni.tar.bz2 | ||
| 134 | + tar xvf ./*.tar.bz2 | ||
| 135 | + | ||
| 136 | + src=sherpa-onnx-v$SHERPA_ONNX_VERSION-win-x64-jni | ||
| 137 | + ls -lh $src | ||
| 138 | + ls -lh $src/lib | ||
| 139 | + dst=sherpa-onnx/java-api/resources/sherpa-onnx/native/win-x64 | ||
| 140 | + | ||
| 141 | + mkdir -p $dst | ||
| 142 | + cp -v $src/lib/onnxruntime.dll $dst/ | ||
| 143 | + cp -v $src/lib/sherpa-onnx-jni.dll $dst/ | ||
| 144 | + | ||
| 145 | + ls -lh $dst | ||
| 146 | + rm -rf $src* | ||
| 147 | + | ||
| 148 | + - name: Create java jar (source code) | ||
| 149 | + shell: bash | ||
| 150 | + run: | | ||
| 151 | + cd sherpa-onnx/java-api | ||
| 152 | + make | ||
| 153 | + | ||
| 154 | + ls -lh build | ||
| 155 | + | ||
| 156 | + - name: Create java jar (native lib) | ||
| 157 | + shell: bash | ||
| 158 | + run: | | ||
| 159 | + SHERPA_ONNX_VERSION=v$(grep "SHERPA_ONNX_VERSION" ./CMakeLists.txt | cut -d " " -f 2 | cut -d '"' -f 2) | ||
| 160 | + | ||
| 161 | + cd sherpa-onnx/java-api | ||
| 162 | + | ||
| 163 | + ls -lh resources/sherpa-onnx/native | ||
| 164 | + | ||
| 165 | + echo "--" | ||
| 166 | + | ||
| 167 | + ls -lh resources/sherpa-onnx/native/*/ | ||
| 168 | + | ||
| 169 | + jar cfvm ./sherpa-onnx-native.jar MANIFEST.MF -C ./resources . | ||
| 170 | + | ||
| 171 | + ls -lh *.jar | ||
| 172 | + | ||
| 173 | + os=${{ matrix.os }} | ||
| 174 | + arch=${{ matrix.arch }} | ||
| 175 | + | ||
| 176 | + if [[ $os == "ubuntu-24.04-arm" && $arch == "arm64" ]]; then | ||
| 177 | + mv -v sherpa-onnx-native.jar sherpa-onnx-native-lib-linux-aarch64-$SHERPA_ONNX_VERSION.jar | ||
| 178 | + elif [[ $os == "ubuntu-latest" && $arch == "x64" ]]; then | ||
| 179 | + mv -v sherpa-onnx-native.jar sherpa-onnx-native-lib-linux-x64-$SHERPA_ONNX_VERSION.jar | ||
| 180 | + elif [[ $os == "macos-latest" && $arch == "arm64" ]]; then | ||
| 181 | + mv -v sherpa-onnx-native.jar sherpa-onnx-native-lib-osx-aarch64-$SHERPA_ONNX_VERSION.jar | ||
| 182 | + elif [[ $os == "macos-13" && $arch == "x64" ]]; then | ||
| 183 | + mv -v sherpa-onnx-native.jar sherpa-onnx-native-lib-osx-x64-$SHERPA_ONNX_VERSION.jar | ||
| 184 | + elif [[ $os == "windows-latest" && $arch == "x64" ]]; then | ||
| 185 | + mv -v sherpa-onnx-native.jar sherpa-onnx-native-lib-win-x64-$SHERPA_ONNX_VERSION.jar | ||
| 186 | + else | ||
| 187 | + echo "Unknown os $os with arch $arch" | ||
| 188 | + fi | ||
| 189 | + | ||
| 190 | + - name: Show java jar (source code) | ||
| 191 | + shell: bash | ||
| 192 | + run: | | ||
| 193 | + cd sherpa-onnx/java-api | ||
| 194 | + | ||
| 195 | + unzip -l build/sherpa-onnx.jar | ||
| 196 | + | ||
| 197 | + - name: Show java jar (native lib) | ||
| 198 | + shell: bash | ||
| 199 | + run: | | ||
| 200 | + cd sherpa-onnx/java-api | ||
| 201 | + | ||
| 202 | + unzip -l sherpa-onnx*.jar | ||
| 203 | + | ||
| 204 | + - name: Release jar | ||
| 205 | + if: github.repository_owner == 'k2-fsa' && github.event_name == 'push' && contains(github.ref, 'refs/tags/') | ||
| 206 | + uses: svenstaro/upload-release-action@v2 | ||
| 207 | + with: | ||
| 208 | + file_glob: true | ||
| 209 | + overwrite: true | ||
| 210 | + file: ./sherpa-onnx/java-api/sherpa-onnx-native-*.jar | ||
| 211 | + | ||
| 212 | + - name: Release jar | ||
| 213 | + if: github.repository_owner == 'csukuangfj' && github.event_name == 'push' && contains(github.ref, 'refs/tags/') | ||
| 214 | + uses: svenstaro/upload-release-action@v2 | ||
| 215 | + with: | ||
| 216 | + file_glob: true | ||
| 217 | + overwrite: true | ||
| 218 | + file: ./sherpa-onnx/java-api/sherpa-onnx-native-*.jar | ||
| 219 | + repo_name: k2-fsa/sherpa-onnx | ||
| 220 | + repo_token: ${{ secrets.UPLOAD_GH_SHERPA_ONNX_TOKEN }} | ||
| 221 | + tag: v1.12.10 | ||
| 222 | + | ||
| 223 | + - name: Test KittenTTS | ||
| 224 | + shell: bash | ||
| 225 | + run: | | ||
| 226 | + SHERPA_ONNX_VERSION=v$(grep "SHERPA_ONNX_VERSION" ./CMakeLists.txt | cut -d " " -f 2 | cut -d '"' -f 2) | ||
| 227 | + | ||
| 228 | + os=${{ matrix.os }} | ||
| 229 | + arch=${{ matrix.arch }} | ||
| 230 | + | ||
| 231 | + if [[ $os == "ubuntu-24.04-arm" && $arch == "arm64" ]]; then | ||
| 232 | + native_jar=sherpa-onnx-native-lib-linux-aarch64-$SHERPA_ONNX_VERSION.jar | ||
| 233 | + elif [[ $os == "ubuntu-latest" && $arch == "x64" ]]; then | ||
| 234 | + native_jar=sherpa-onnx-native-lib-linux-x64-$SHERPA_ONNX_VERSION.jar | ||
| 235 | + elif [[ $os == "macos-latest" && $arch == "arm64" ]]; then | ||
| 236 | + native_jar=sherpa-onnx-native-lib-osx-aarch64-$SHERPA_ONNX_VERSION.jar | ||
| 237 | + elif [[ $os == "macos-13" && $arch == "x64" ]]; then | ||
| 238 | + native_jar=sherpa-onnx-native-lib-osx-x64-$SHERPA_ONNX_VERSION.jar | ||
| 239 | + elif [[ $os == "windows-latest" && $arch == "x64" ]]; then | ||
| 240 | + native_jar=sherpa-onnx-native-lib-win-x64-$SHERPA_ONNX_VERSION.jar | ||
| 241 | + else | ||
| 242 | + echo "Unknown os $os with arch $arch" | ||
| 243 | + fi | ||
| 244 | + | ||
| 245 | + echo "native_jar: $native_jar" | ||
| 246 | + ls -lh sherpa-onnx/java-api/$native_jar | ||
| 247 | + | ||
| 248 | + if [[ ${{ matrix.os }} == "windows-latest" ]]; then | ||
| 249 | + SEP=";" | ||
| 250 | + else | ||
| 251 | + SEP=":" | ||
| 252 | + fi | ||
| 253 | + cd java-api-examples | ||
| 254 | + | ||
| 255 | + curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/kitten-nano-en-v0_1-fp16.tar.bz2 | ||
| 256 | + tar xf kitten-nano-en-v0_1-fp16.tar.bz2 | ||
| 257 | + rm kitten-nano-en-v0_1-fp16.tar.bz2 | ||
| 258 | + | ||
| 259 | + java \ | ||
| 260 | + -cp "../sherpa-onnx/java-api/build/sherpa-onnx.jar${SEP}../sherpa-onnx/java-api/$native_jar" \ | ||
| 261 | + NonStreamingTtsKittenEn.java |
| @@ -20,7 +20,7 @@ jobs: | @@ -20,7 +20,7 @@ jobs: | ||
| 20 | fail-fast: false | 20 | fail-fast: false |
| 21 | matrix: | 21 | matrix: |
| 22 | os: [ubuntu-latest] | 22 | os: [ubuntu-latest] |
| 23 | - java-version: ['8', '11', '16', '17', '18', '19', '20', '21', '22', '23', '24'] | 23 | + java-version: ['24'] |
| 24 | 24 | ||
| 25 | steps: | 25 | steps: |
| 26 | - uses: actions/checkout@v4 | 26 | - uses: actions/checkout@v4 |
| @@ -46,7 +46,6 @@ jobs: | @@ -46,7 +46,6 @@ jobs: | ||
| 46 | du -h -d1 . | 46 | du -h -d1 . |
| 47 | 47 | ||
| 48 | - name: Build jar ${{ matrix.java-version }} | 48 | - name: Build jar ${{ matrix.java-version }} |
| 49 | - if: matrix.java-version == '23' | ||
| 50 | shell: bash | 49 | shell: bash |
| 51 | run: | | 50 | run: | |
| 52 | SHERPA_ONNX_VERSION=v$(grep "SHERPA_ONNX_VERSION" ./CMakeLists.txt | cut -d " " -f 2 | cut -d '"' -f 2) | 51 | SHERPA_ONNX_VERSION=v$(grep "SHERPA_ONNX_VERSION" ./CMakeLists.txt | cut -d " " -f 2 | cut -d '"' -f 2) |
| @@ -57,17 +56,6 @@ jobs: | @@ -57,17 +56,6 @@ jobs: | ||
| 57 | cd ../.. | 56 | cd ../.. |
| 58 | ls -lh *.jar | 57 | ls -lh *.jar |
| 59 | 58 | ||
| 60 | - - name: Build jar ${{ matrix.java-version }} | ||
| 61 | - shell: bash | ||
| 62 | - run: | | ||
| 63 | - SHERPA_ONNX_VERSION=v$(grep "SHERPA_ONNX_VERSION" ./CMakeLists.txt | cut -d " " -f 2 | cut -d '"' -f 2) | ||
| 64 | - cd sherpa-onnx/java-api | ||
| 65 | - make | ||
| 66 | - ls -lh build/ | ||
| 67 | - cp build/sherpa-onnx.jar ../../sherpa-onnx-$SHERPA_ONNX_VERSION-java${{ matrix.java-version }}.jar | ||
| 68 | - cd ../.. | ||
| 69 | - ls -lh *.jar | ||
| 70 | - | ||
| 71 | - uses: actions/upload-artifact@v4 | 59 | - uses: actions/upload-artifact@v4 |
| 72 | with: | 60 | with: |
| 73 | name: release-jni-linux-jar-${{ matrix.java-version }} | 61 | name: release-jni-linux-jar-${{ matrix.java-version }} |
| @@ -80,12 +68,11 @@ jobs: | @@ -80,12 +68,11 @@ jobs: | ||
| 80 | file_glob: true | 68 | file_glob: true |
| 81 | overwrite: true | 69 | overwrite: true |
| 82 | file: ./*.jar | 70 | file: ./*.jar |
| 83 | - # repo_name: k2-fsa/sherpa-onnx | ||
| 84 | - # repo_token: ${{ secrets.UPLOAD_GH_SHERPA_ONNX_TOKEN }} | ||
| 85 | - # tag: v1.12.1 | 71 | + repo_name: k2-fsa/sherpa-onnx |
| 72 | + repo_token: ${{ secrets.UPLOAD_GH_SHERPA_ONNX_TOKEN }} | ||
| 73 | + tag: v1.12.10 | ||
| 86 | 74 | ||
| 87 | - name: Build sherpa-onnx | 75 | - name: Build sherpa-onnx |
| 88 | - if: matrix.java-version == '23' | ||
| 89 | uses: addnab/docker-run-action@v3 | 76 | uses: addnab/docker-run-action@v3 |
| 90 | with: | 77 | with: |
| 91 | image: quay.io/pypa/manylinux2014_x86_64 | 78 | image: quay.io/pypa/manylinux2014_x86_64 |
| @@ -151,7 +138,6 @@ jobs: | @@ -151,7 +138,6 @@ jobs: | ||
| 151 | ls -lh install/bin | 138 | ls -lh install/bin |
| 152 | 139 | ||
| 153 | - name: Display dependencies of sherpa-onnx for linux | 140 | - name: Display dependencies of sherpa-onnx for linux |
| 154 | - if: matrix.java-version == '23' | ||
| 155 | shell: bash | 141 | shell: bash |
| 156 | run: | | 142 | run: | |
| 157 | du -h -d1 . | 143 | du -h -d1 . |
| @@ -170,13 +156,11 @@ jobs: | @@ -170,13 +156,11 @@ jobs: | ||
| 170 | readelf -d build/bin/sherpa-onnx | 156 | readelf -d build/bin/sherpa-onnx |
| 171 | 157 | ||
| 172 | - uses: actions/upload-artifact@v4 | 158 | - uses: actions/upload-artifact@v4 |
| 173 | - if: matrix.java-version == '23' | ||
| 174 | with: | 159 | with: |
| 175 | name: release-jni-linux-${{ matrix.java-version }} | 160 | name: release-jni-linux-${{ matrix.java-version }} |
| 176 | path: build/install/* | 161 | path: build/install/* |
| 177 | 162 | ||
| 178 | - name: Copy files | 163 | - name: Copy files |
| 179 | - if: matrix.java-version == '23' | ||
| 180 | shell: bash | 164 | shell: bash |
| 181 | run: | | 165 | run: | |
| 182 | du -h -d1 . | 166 | du -h -d1 . |
| @@ -194,8 +178,19 @@ jobs: | @@ -194,8 +178,19 @@ jobs: | ||
| 194 | tar cjvf ${dst}.tar.bz2 $dst | 178 | tar cjvf ${dst}.tar.bz2 $dst |
| 195 | du -h -d1 . | 179 | du -h -d1 . |
| 196 | 180 | ||
| 181 | + - name: Release pre-compiled binaries and libs for linux x64 | ||
| 182 | + if: (github.repository_owner == 'csukuangfj' || github.repository_owner == 'k2-fsa') && github.event_name == 'push' && contains(github.ref, 'refs/tags/') | ||
| 183 | + uses: svenstaro/upload-release-action@v2 | ||
| 184 | + with: | ||
| 185 | + file_glob: true | ||
| 186 | + overwrite: true | ||
| 187 | + file: sherpa-onnx-*.tar.bz2 | ||
| 188 | + # repo_name: k2-fsa/sherpa-onnx | ||
| 189 | + # repo_token: ${{ secrets.UPLOAD_GH_SHERPA_ONNX_TOKEN }} | ||
| 190 | + # tag: v1.12.10 | ||
| 191 | + | ||
| 197 | - name: Publish to huggingface | 192 | - name: Publish to huggingface |
| 198 | - if: (github.repository_owner == 'csukuangfj' || github.repository_owner == 'k2-fsa') && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && matrix.java-version == '23' | 193 | + if: (github.repository_owner == 'csukuangfj' || github.repository_owner == 'k2-fsa') && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') |
| 199 | env: | 194 | env: |
| 200 | HF_TOKEN: ${{ secrets.HF_TOKEN }} | 195 | HF_TOKEN: ${{ secrets.HF_TOKEN }} |
| 201 | uses: nick-fields/retry@v3 | 196 | uses: nick-fields/retry@v3 |
| @@ -215,6 +210,7 @@ jobs: | @@ -215,6 +210,7 @@ jobs: | ||
| 215 | cd huggingface | 210 | cd huggingface |
| 216 | dst=jni/$SHERPA_ONNX_VERSION | 211 | dst=jni/$SHERPA_ONNX_VERSION |
| 217 | mkdir -p $dst | 212 | mkdir -p $dst |
| 213 | + git lfs track "*.jar" | ||
| 218 | 214 | ||
| 219 | cp -v ../sherpa-onnx-*.tar.bz2 $dst/ | 215 | cp -v ../sherpa-onnx-*.tar.bz2 $dst/ |
| 220 | cp -v ../*.jar $dst/ | 216 | cp -v ../*.jar $dst/ |
| @@ -227,14 +223,3 @@ jobs: | @@ -227,14 +223,3 @@ jobs: | ||
| 227 | git commit -m "add more files" | 223 | git commit -m "add more files" |
| 228 | 224 | ||
| 229 | git push https://csukuangfj:$HF_TOKEN@huggingface.co/csukuangfj/sherpa-onnx-libs main | 225 | git push https://csukuangfj:$HF_TOKEN@huggingface.co/csukuangfj/sherpa-onnx-libs main |
| 230 | - | ||
| 231 | - - name: Release pre-compiled binaries and libs for linux x64 | ||
| 232 | - if: (github.repository_owner == 'csukuangfj' || github.repository_owner == 'k2-fsa') && github.event_name == 'push' && contains(github.ref, 'refs/tags/') && matrix.java-version == '23' | ||
| 233 | - uses: svenstaro/upload-release-action@v2 | ||
| 234 | - with: | ||
| 235 | - file_glob: true | ||
| 236 | - overwrite: true | ||
| 237 | - file: sherpa-onnx-*.tar.bz2 | ||
| 238 | - # repo_name: k2-fsa/sherpa-onnx | ||
| 239 | - # repo_token: ${{ secrets.UPLOAD_GH_SHERPA_ONNX_TOKEN }} | ||
| 240 | - # tag: v1.12.0 |
| @@ -6,6 +6,7 @@ import com.k2fsa.sherpa.onnx.*; | @@ -6,6 +6,7 @@ import com.k2fsa.sherpa.onnx.*; | ||
| 6 | 6 | ||
| 7 | public class NonStreamingTtsKittenEn { | 7 | public class NonStreamingTtsKittenEn { |
| 8 | public static void main(String[] args) { | 8 | public static void main(String[] args) { |
| 9 | + LibraryUtils.enableDebug(); | ||
| 9 | // please visit | 10 | // please visit |
| 10 | // https://k2-fsa.github.io/sherpa/onnx/tts/pretrained_models/kitten.html | 11 | // https://k2-fsa.github.io/sherpa/onnx/tts/pretrained_models/kitten.html |
| 11 | // to download model files | 12 | // to download model files |
sherpa-onnx/java-api/MANIFEST.MF
0 → 100644
| 1 | +Manifest-Version: 1.0 |
| @@ -109,17 +109,28 @@ $(info -- java files $(java_files)) | @@ -109,17 +109,28 @@ $(info -- java files $(java_files)) | ||
| 109 | $(info --) | 109 | $(info --) |
| 110 | $(info -- class files $(class_files)) | 110 | $(info -- class files $(class_files)) |
| 111 | 111 | ||
| 112 | -.phony: all clean | 112 | +.PHONY: all clean native |
| 113 | 113 | ||
| 114 | all: $(out_jar) | 114 | all: $(out_jar) |
| 115 | 115 | ||
| 116 | +# macos x86_x64 -> osx-x64 | ||
| 117 | +# macos arm64 -> osx-aarch64 | ||
| 118 | +# linux x86_x64 -> linux-x64 | ||
| 119 | +# linux arm64 -> linux-aarch64 | ||
| 120 | +# windows x86_x64 -> win-x64 | ||
| 121 | +# windows arm64 -> win-aarch64 | ||
| 122 | +# windows x86 -> win-x86 | ||
| 123 | +native: | ||
| 124 | + jar cfvm ./sherpa-onnx-native.jar MANIFEST.MF -C ./resources . | ||
| 125 | + | ||
| 116 | $(out_jar): $(class_files) | 126 | $(out_jar): $(class_files) |
| 117 | # jar --create --verbose --file $(out_jar) -C $(out_dir) ./ | 127 | # jar --create --verbose --file $(out_jar) -C $(out_dir) ./ |
| 118 | - jar cvf $(out_jar) -C $(out_dir) ./ | 128 | + # jar cvf $(out_jar) -C $(out_dir) ./ |
| 129 | + jar cfvm $@ MANIFEST.MF -C $(out_dir) . | ||
| 119 | 130 | ||
| 120 | clean: | 131 | clean: |
| 121 | $(RM) -rfv $(out_dir) | 132 | $(RM) -rfv $(out_dir) |
| 122 | 133 | ||
| 123 | $(class_files): $(out_dir)/$(package_dir)/%.class: src/main/java/$(package_dir)/%.java | 134 | $(class_files): $(out_dir)/$(package_dir)/%.class: src/main/java/$(package_dir)/%.java |
| 124 | mkdir -p build | 135 | mkdir -p build |
| 125 | - javac -d $(out_dir) -cp $(out_dir) $< | 136 | + javac --release 8 -Xlint:-options -d $(out_dir) -cp $(out_dir) $< |
| @@ -4,42 +4,170 @@ import java.io.File; | @@ -4,42 +4,170 @@ import java.io.File; | ||
| 4 | import java.io.IOException; | 4 | import java.io.IOException; |
| 5 | import java.io.InputStream; | 5 | import java.io.InputStream; |
| 6 | import java.nio.file.Files; | 6 | import java.nio.file.Files; |
| 7 | +import java.nio.file.Path; | ||
| 7 | import java.nio.file.StandardCopyOption; | 8 | import java.nio.file.StandardCopyOption; |
| 8 | import java.util.Locale; | 9 | import java.util.Locale; |
| 10 | +import java.util.Objects; | ||
| 11 | + | ||
| 12 | +/* | ||
| 13 | +# We support the following loading methods | ||
| 14 | + | ||
| 15 | +## Method 1 Specify the property sherpa_onnx.native.path | ||
| 16 | + | ||
| 17 | +We assume the path contains the libraries sherpa-onnx-jni and onnxruntime. | ||
| 18 | + | ||
| 19 | +java \ | ||
| 20 | + -Dsherpa_onnx.native.path=/Users/fangjun/sherpa-onnx/build/install/lib \ | ||
| 21 | + -cp /Users/fangjun/sherpa-onnx/sherpa-onnx/java-api/build/sherpa-onnx.jar | ||
| 22 | + xxx.java | ||
| 23 | + | ||
| 24 | +## Method 2 Specify the native jar library | ||
| 25 | + | ||
| 26 | +java \ | ||
| 27 | + -cp /Users/fangjun/sherpa-onnx/sherpa-onnx/java-api/build/sherpa-onnx.jar:/path/to/sherpa-onnx-osx-x64.jar | ||
| 28 | + xxx.java | ||
| 29 | + | ||
| 30 | +Note that you need to replace : in -cp with ; on windows. | ||
| 31 | + | ||
| 32 | +## Method 3 Specify the property java.library.path | ||
| 33 | + | ||
| 34 | +We assume the path contains the libraries sherpa-onnx-jni and onnxruntime. | ||
| 35 | + | ||
| 36 | +java \ | ||
| 37 | + -Djava.library.path=/Users/fangjun/sherpa-onnx/build/install/lib \ | ||
| 38 | + -cp /Users/fangjun/sherpa-onnx/sherpa-onnx/java-api/build/sherpa-onnx.jar | ||
| 39 | + xxx.java | ||
| 40 | + | ||
| 41 | + */ | ||
| 9 | 42 | ||
| 10 | public class LibraryUtils { | 43 | public class LibraryUtils { |
| 11 | // System property to override native library path | 44 | // System property to override native library path |
| 12 | private static final String NATIVE_PATH_PROP = "sherpa_onnx.native.path"; | 45 | private static final String NATIVE_PATH_PROP = "sherpa_onnx.native.path"; |
| 13 | private static final String LIB_NAME = "sherpa-onnx-jni"; | 46 | private static final String LIB_NAME = "sherpa-onnx-jni"; |
| 14 | 47 | ||
| 48 | + private static boolean debug = false; | ||
| 49 | + | ||
| 50 | + private static String detectedOS; | ||
| 51 | + | ||
| 52 | + public static void enableDebug() { | ||
| 53 | + debug = true; | ||
| 54 | + } | ||
| 55 | + | ||
| 56 | + public static void disableDebug() { | ||
| 57 | + debug = false; | ||
| 58 | + } | ||
| 59 | + | ||
| 15 | public static void load() { | 60 | public static void load() { |
| 16 | - String libFileName = System.mapLibraryName(LIB_NAME); | 61 | + // 1. Try to load from external directory specified by -Dsherpa_onnx.native.path if provided |
| 62 | + if (loadFromSherpaOnnxNativePath()) { | ||
| 63 | + return; | ||
| 64 | + } | ||
| 17 | 65 | ||
| 66 | + // 2. Load from resources contains in some jar file | ||
| 18 | try { | 67 | try { |
| 19 | - // 1. Try loading from external directory if provided | 68 | + if (loadFromResourceInJar()) { |
| 69 | + return; | ||
| 70 | + } | ||
| 71 | + } catch (IOException e) { | ||
| 72 | + // pass | ||
| 73 | + } | ||
| 74 | + | ||
| 75 | + // 3. fallback to -Djava.library.path | ||
| 76 | + // java -Djava.library.path=C:\mylibs;D:\otherlibs -cp sherpa-onnx.jar xxx.java | ||
| 77 | + // | ||
| 78 | + // It throws if it cannot load the lib sherpa-onnx-jni | ||
| 79 | + System.loadLibrary(LIB_NAME); | ||
| 80 | + } | ||
| 81 | + | ||
| 82 | + // You specify -Dsherpa_onnx.native.path=/path/to/some/dir | ||
| 83 | + // where /path/to/some/dir contains the sherpa-onnx-jni and onnxruntime libs | ||
| 84 | + private static boolean loadFromSherpaOnnxNativePath() { | ||
| 85 | + String libFileName = System.mapLibraryName(LIB_NAME); | ||
| 20 | String nativePath = System.getProperty(NATIVE_PATH_PROP); | 86 | String nativePath = System.getProperty(NATIVE_PATH_PROP); |
| 87 | + | ||
| 21 | if (nativePath != null) { | 88 | if (nativePath != null) { |
| 22 | File nativeDir = new File(nativePath); | 89 | File nativeDir = new File(nativePath); |
| 23 | File libInDir = new File(nativeDir, libFileName); | 90 | File libInDir = new File(nativeDir, libFileName); |
| 24 | if (nativeDir.isDirectory() && libInDir.exists()) { | 91 | if (nativeDir.isDirectory() && libInDir.exists()) { |
| 25 | - System.out.println("Loading native lib from external directory: " + libInDir.getAbsolutePath()); | 92 | + if (debug) { |
| 93 | + System.out.printf("Loading from: %s\n", libInDir.getAbsolutePath()); | ||
| 94 | + } | ||
| 95 | + | ||
| 26 | System.load(libInDir.getAbsolutePath()); | 96 | System.load(libInDir.getAbsolutePath()); |
| 27 | - return; | 97 | + return true; |
| 28 | } | 98 | } |
| 29 | } | 99 | } |
| 30 | 100 | ||
| 31 | - // 2. Fallback to extracting and loading from the JAR | ||
| 32 | - File libFile = init(libFileName); | ||
| 33 | - System.out.println("Loading native lib from: " + libFile.getAbsolutePath()); | ||
| 34 | - System.load(libFile.getAbsolutePath()); | ||
| 35 | - } catch (RuntimeException ex) { | ||
| 36 | - System.loadLibrary(LIB_NAME); | 101 | + if (debug) { |
| 102 | + System.out.println("nativePath is null"); | ||
| 37 | } | 103 | } |
| 104 | + | ||
| 105 | + return false; | ||
| 38 | } | 106 | } |
| 39 | 107 | ||
| 40 | - /* Computes and initializes OS_ARCH_STR (such as linux-x64) */ | ||
| 41 | - private static String initOsArch() { | ||
| 42 | - String detectedOS = null; | 108 | + private static boolean loadFromResourceInJar() throws IOException { |
| 109 | + | ||
| 110 | + String libFileName = System.mapLibraryName(LIB_NAME); | ||
| 111 | + String sherpaOnnxJniPath = "sherpa-onnx/native/" + getOsArch() + '/' + libFileName; | ||
| 112 | + | ||
| 113 | + Path tempDirectory = null; | ||
| 114 | + try { | ||
| 115 | + | ||
| 116 | + if (!resourceExists(sherpaOnnxJniPath)) { | ||
| 117 | + if (debug) { | ||
| 118 | + System.out.printf("%s does not exist\n", sherpaOnnxJniPath); | ||
| 119 | + } | ||
| 120 | + | ||
| 121 | + return false; | ||
| 122 | + } | ||
| 123 | + | ||
| 124 | + tempDirectory = Files.createTempDirectory("sherpa-onnx-java"); | ||
| 125 | + | ||
| 126 | + if (Objects.equals(detectedOS, "osx")) { | ||
| 127 | + // for macos, we need to first load libonnxruntime.1.17.1.dylib | ||
| 128 | + String onnxruntimePath = "sherpa-onnx/native/" + getOsArch() + '/' + "libonnxruntime.1.17.1.dylib"; | ||
| 129 | + if (!resourceExists(onnxruntimePath)) { | ||
| 130 | + if (debug) { | ||
| 131 | + System.out.printf("%s does not exist\n", onnxruntimePath); | ||
| 132 | + } | ||
| 133 | + | ||
| 134 | + return false; | ||
| 135 | + } | ||
| 136 | + | ||
| 137 | + File tempFile = tempDirectory.resolve("libonnxruntime.1.17.1.dylib").toFile(); | ||
| 138 | + extractResource(onnxruntimePath, tempFile); | ||
| 139 | + System.load(tempFile.getAbsolutePath()); | ||
| 140 | + } else { | ||
| 141 | + String onnxLibFileName = System.mapLibraryName("onnxruntime"); | ||
| 142 | + String onnxruntimePath = "sherpa-onnx/native/" + getOsArch() + '/' + onnxLibFileName; | ||
| 143 | + if (!resourceExists(onnxruntimePath)) { | ||
| 144 | + if (debug) { | ||
| 145 | + System.out.printf("%s does not exist\n", onnxruntimePath); | ||
| 146 | + } | ||
| 147 | + | ||
| 148 | + return false; | ||
| 149 | + } | ||
| 150 | + | ||
| 151 | + File tempFile = tempDirectory.resolve(onnxLibFileName).toFile(); | ||
| 152 | + extractResource(onnxruntimePath, tempFile); | ||
| 153 | + System.load(tempFile.getAbsolutePath()); | ||
| 154 | + } | ||
| 155 | + | ||
| 156 | + File tempFile = tempDirectory.resolve(libFileName).toFile(); | ||
| 157 | + extractResource(sherpaOnnxJniPath, tempFile); | ||
| 158 | + System.load(tempFile.getAbsolutePath()); | ||
| 159 | + } finally { | ||
| 160 | + if (tempDirectory != null) { | ||
| 161 | + cleanUpTempDir(tempDirectory.toFile()); | ||
| 162 | + } | ||
| 163 | + } | ||
| 164 | + | ||
| 165 | + return true; | ||
| 166 | + } | ||
| 167 | + | ||
| 168 | + // this method is copied and modified from | ||
| 169 | + // https://github.com/microsoft/onnxruntime/blob/main/java/src/main/java/ai/onnxruntime/OnnxRuntime.java#L118 | ||
| 170 | + private static String getOsArch() { | ||
| 43 | String os = System.getProperty("os.name", "generic").toLowerCase(Locale.ENGLISH); | 171 | String os = System.getProperty("os.name", "generic").toLowerCase(Locale.ENGLISH); |
| 44 | if (os.contains("mac") || os.contains("darwin")) { | 172 | if (os.contains("mac") || os.contains("darwin")) { |
| 45 | detectedOS = "osx"; | 173 | detectedOS = "osx"; |
| @@ -50,58 +178,60 @@ public class LibraryUtils { | @@ -50,58 +178,60 @@ public class LibraryUtils { | ||
| 50 | } else { | 178 | } else { |
| 51 | throw new IllegalStateException("Unsupported os:" + os); | 179 | throw new IllegalStateException("Unsupported os:" + os); |
| 52 | } | 180 | } |
| 53 | - String detectedArch = null; | ||
| 54 | - String arch = System.getProperty("os.arch", "generic").toLowerCase(Locale.ENGLISH); | 181 | + |
| 182 | + String detectedArch; | ||
| 183 | + String arch = System.getProperty("os.arch", "generic") | ||
| 184 | + .toLowerCase(Locale.ENGLISH); | ||
| 55 | if (arch.startsWith("amd64") || arch.startsWith("x86_64")) { | 185 | if (arch.startsWith("amd64") || arch.startsWith("x86_64")) { |
| 56 | detectedArch = "x64"; | 186 | detectedArch = "x64"; |
| 57 | } else if (arch.startsWith("x86")) { | 187 | } else if (arch.startsWith("x86")) { |
| 58 | // 32-bit x86 is not supported by the Java API | 188 | // 32-bit x86 is not supported by the Java API |
| 59 | detectedArch = "x86"; | 189 | detectedArch = "x86"; |
| 60 | - } else if (arch.startsWith("aarch64")) { | 190 | + } else if (arch.startsWith("aarch64") || arch.startsWith("arm64")) { |
| 61 | detectedArch = "aarch64"; | 191 | detectedArch = "aarch64"; |
| 62 | } else { | 192 | } else { |
| 63 | throw new IllegalStateException("Unsupported arch:" + arch); | 193 | throw new IllegalStateException("Unsupported arch:" + arch); |
| 64 | } | 194 | } |
| 65 | - return detectedOS + '-' + detectedArch; | ||
| 66 | - } | ||
| 67 | 195 | ||
| 68 | - private static File init(String libFileName) { | ||
| 69 | - String osName = System.getProperty("os.name").toLowerCase(); | ||
| 70 | - String osArch = System.getProperty("os.arch").toLowerCase(); | ||
| 71 | - String userHome = System.getProperty("user.home"); | ||
| 72 | - System.out.printf("Detected OS=%s, ARCH=%s, HOME=%s%n", osName, osArch, userHome); | ||
| 73 | - | ||
| 74 | - String archName = initOsArch(); | ||
| 75 | - | ||
| 76 | - // Prepare destination directory under ~/lib/<archName>/ | ||
| 77 | - String dstDir = userHome + File.separator + "lib" + File.separator + archName; | ||
| 78 | - File libFile = new File(dstDir, libFileName); | ||
| 79 | - File parentDir = libFile.getParentFile(); | ||
| 80 | - if (!parentDir.exists() && !parentDir.mkdirs()) { | ||
| 81 | - throw new RuntimeException("Unable to create directory: " + parentDir); | 196 | + return detectedOS + '-' + detectedArch; |
| 82 | } | 197 | } |
| 83 | 198 | ||
| 84 | - // Extract the native library from JAR | ||
| 85 | - extractResource("/native/" + archName + "/" + libFileName, libFile); | ||
| 86 | - return libFile; | 199 | + private static void extractResource(String resourcePath, File destination) { |
| 200 | + if (debug) { | ||
| 201 | + System.out.printf("Copying from resource path %s to %s\n", resourcePath, destination.toPath()); | ||
| 87 | } | 202 | } |
| 88 | 203 | ||
| 89 | - /** | ||
| 90 | - * Copies a resource file from the jar to the specified destination. | ||
| 91 | - * | ||
| 92 | - * @param resourcePath The resource path inside the jar, e.g.: | ||
| 93 | - * /native/linux_x64/libonnxruntime.so | ||
| 94 | - * @param destination The destination file on disk | ||
| 95 | - */ | ||
| 96 | - private static void extractResource(String resourcePath, File destination) { | ||
| 97 | - try (InputStream in = LibraryUtils.class.getResourceAsStream(resourcePath)) { | 204 | + try (InputStream in = LibraryUtils.class.getClassLoader().getResourceAsStream(resourcePath)) { |
| 98 | if (in == null) { | 205 | if (in == null) { |
| 99 | throw new RuntimeException("Resource not found: " + resourcePath); | 206 | throw new RuntimeException("Resource not found: " + resourcePath); |
| 100 | } | 207 | } |
| 101 | Files.copy(in, destination.toPath(), StandardCopyOption.REPLACE_EXISTING); | 208 | Files.copy(in, destination.toPath(), StandardCopyOption.REPLACE_EXISTING); |
| 102 | } catch (IOException e) { | 209 | } catch (IOException e) { |
| 103 | - throw new RuntimeException("Failed to extract resource " + resourcePath + " to " + destination.getAbsolutePath(), | ||
| 104 | - e); | 210 | + throw new RuntimeException("Failed to extract resource " + resourcePath + " to " + destination.getAbsolutePath(), e); |
| 211 | + } | ||
| 212 | + } | ||
| 213 | + | ||
| 214 | + // From ChatGPT: | ||
| 215 | + // Class.getResourceAsStream(String path) behaves differently than ClassLoader | ||
| 216 | + // - No leading slash → relative to the package of LibraryUtils | ||
| 217 | + // - Leading slash → absolute path relative to classpath root | ||
| 218 | + // | ||
| 219 | + // ClassLoader.getResourceAsStream always uses absolute paths relative to classpath root, | ||
| 220 | + // no leading slash needed | ||
| 221 | + | ||
| 222 | + private static boolean resourceExists(String path) { | ||
| 223 | + return LibraryUtils.class.getClassLoader().getResource(path) != null; | ||
| 224 | + } | ||
| 225 | + | ||
| 226 | + private static void cleanUpTempDir(File dir) { | ||
| 227 | + if (!dir.exists()) return; | ||
| 228 | + | ||
| 229 | + File[] files = dir.listFiles(); | ||
| 230 | + if (files != null) { | ||
| 231 | + for (File f : files) { | ||
| 232 | + f.deleteOnExit(); // schedule each .so for deletion | ||
| 233 | + } | ||
| 105 | } | 234 | } |
| 235 | + dir.deleteOnExit(); // schedule the directory itself | ||
| 106 | } | 236 | } |
| 107 | } | 237 | } |
-
请 注册 或 登录 后发表评论