diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9d8b4cb..bdfeb3c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,11 +2,11 @@ name: CI on: [push] jobs: - build-binaries: + build-binaries-unix: strategy: fail-fast: false matrix: - os: [windows-latest, macos-latest, ubuntu-latest] + os: [macos-latest, ubuntu-latest] name: ${{ matrix.os }} build runs-on: ${{ matrix.os }} @@ -20,16 +20,45 @@ jobs: uses: actions/setup-java@v1 with: java-version: 8 - - name: Make gradlew executable (Unix) + - name: Make gradlew executable run: "chmod +x gradlew" - if: runner.os != 'Windows' - - name: Build native with gradle (Unix) + - name: Build native with gradle run: "./gradlew -PCI=true opus-jni-native:build" - if: runner.os != 'Windows' + - name: Prepare artifacts + shell: bash + run: | + mkdir artifacts + for file in $(cat ci/binaries); do # File generated by gradle + echo "Found binary artifact ${file}" + cp "${file}" artifacts + done + - name: Upload artifacts + uses: actions/upload-artifact@v1 + with: + name: native-binaries + path: artifacts + + build-binaries-windows: + strategy: + fail-fast: false + matrix: + arch: [32bit, 64bit] + + name: windows-latest build + runs-on: windows-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + with: + submodules: recursive + - name: Install java + uses: actions/setup-java@v1 + with: + java-version: 8 - name: Build native with gradle (Windows) - run: "gradlew -PCI=true opus-jni-native:build" + run: gradlew -PCI=true opus-jni-native:build -P${{ matrix.arch }} shell: cmd - if: runner.os == 'Windows' - name: Prepare artifacts shell: bash run: | @@ -45,7 +74,7 @@ jobs: path: artifacts build-jar: - needs: build-binaries + needs: [build-binaries-unix, build-binaries-windows] runs-on: ubuntu-latest # Doesn't matter, but linux tends to be the fastest name: Build final jar diff --git a/build.gradle b/build.gradle index 3081460..ba9b227 100644 --- a/build.gradle +++ b/build.gradle @@ -19,7 +19,7 @@ def ciBuild = project.hasProperty("CI") && Boolean.parseBoolean(project.property if(!project.hasProperty("nativeBinaryExternalDir")) { if (Os.isFamily(Os.FAMILY_WINDOWS)) { // WARNING, this assumes CMake uses visual studio - // For GCC or Clang the output should be $nativeBinariesDir/libopus-jni-natibe.dll + // For GCC or Clang the output should be $nativeBinariesDir/libopus-jni-native.dll ext.nativeBinaries = Arrays.asList(new File(nativeBinariesDir, "Debug/opus-jni-native.dll")) } else if (Os.isFamily(Os.FAMILY_MAC)) { ext.nativeBinaries = Arrays.asList(new File(nativeBinariesDir, "libopus-jni-native.dylib")) @@ -49,6 +49,12 @@ if(!project.hasProperty("nativeBinaryExternalDir")) { isExternalBuild = true } +if(project.hasProperty("32bit")) { + ext.is32bit = true +} else { + ext.is32bit = false +} + project(":opus-jni-java").afterEvaluate { javaProject -> project("opus-jni-native").afterEvaluate { nativeProject -> nativeProject.tasks["build"].dependsOn(javaProject.tasks["generateJniHeaders"]) @@ -59,6 +65,45 @@ project(":opus-jni-java").afterEvaluate { javaProject -> } } +def getExtension(File file) { + String fileName = file.getName() + + if(fileName.lastIndexOf(".") != -1 && fileName.lastIndexOf(".") != 0) { + return fileName.substring(fileName.lastIndexOf(".") + 1) + } else { + return "" + } +} + +def getPathWithoutExtension(File file) { + String fileName = file.getAbsolutePath() + + if(fileName.lastIndexOf(".") != -1 && fileName.lastIndexOf(".") != 0) { + return fileName.substring(0, fileName.lastIndexOf(".")) + } else { + return "" + } +} + +def processBinary(File binary, boolean doMove) { + String extension = getExtension(binary) + String path = getPathWithoutExtension(binary) + + File newPath = null + if(ext.is32bit) { + newPath = new File(path + "-32." + extension) + } else { + newPath = new File(path + "-64." + extension) + } + + if(doMove) { + println "Moving ${binary.absolutePath} to ${newPath.absolutePath}" + binary.renameTo(newPath) + } + + return newPath +} + if(ciBuild) { def ciDir = file("ci") if(!ciDir.exists() && !ciDir.mkdirs()) { @@ -67,7 +112,21 @@ if(ciBuild) { new File(ciDir, "binaries").withWriter { for(File binary in ext.nativeBinaries) { - it.write(binary.absolutePath) + it.write(processBinary(binary, false).absolutePath) } } + + def binaries = ext.nativeBinaries + + task moveNativeBinaries { + doLast { + for (File binary in binaries) { + processBinary(binary, true) + } + } + } + + project("opus-jni-native").afterEvaluate { nativeProject -> + nativeProject.tasks["build"].finalizedBy(moveNativeBinaries) + } } diff --git a/opus-jni-java/src/main/java/net/labymod/opus/OpusCodec.java b/opus-jni-java/src/main/java/net/labymod/opus/OpusCodec.java index e548fb2..2cef078 100644 --- a/opus-jni-java/src/main/java/net/labymod/opus/OpusCodec.java +++ b/opus-jni-java/src/main/java/net/labymod/opus/OpusCodec.java @@ -213,22 +213,54 @@ public Builder withMaxPacketSize(int maxPacketSize) { public OpusCodec build() { return new OpusCodec(OpusCodecOptions.of(frameSize, sampleRate, channels, bitrate, maxFrameSize, maxPacketSize)); } - } private static String getNativeLibraryName() { + String bitnessArch = System.getProperty("os.arch").toLowerCase(); + String bitnessDataModel = System.getProperty("sun.arch.data.model", null); + if(bitnessDataModel != null) { + bitnessArch = bitnessDataModel.toLowerCase(); + } + + boolean is64bit = bitnessArch.contains("64"); + if(is64bit) { + String library64 = processLibraryName("opus-jni-native-64"); + if(hasResource("/native-binaries/" + library64)) { + return library64; + } + } else { + String library32 = processLibraryName("opus-jni-native-32"); + if(hasResource("/native-binaries/" + library32)) { + return library32; + } + } + + String library = processLibraryName("opus-jni-native"); + if(!hasResource("/native-binaries/" + library)) { + throw new NoSuchElementException("No binary for the current system found, even after trying bit neutral names"); + } else { + return library; + } + } + + private static String processLibraryName(String library) { String systemName = System.getProperty("os.name", "bare-metal?").toLowerCase(); + if (systemName.contains("nux") || systemName.contains("nix")) { - return "libopus-jni-native.so"; + return "lib" + library + ".so"; } else if (systemName.contains("mac")) { - return "libopus-jni-native.dylib"; + return "lib" + library + ".dylib"; } else if (systemName.contains("windows")) { - return "opus-jni-native.dll"; + return library + ".dll"; } else { throw new NoSuchElementException("No native library for system " + systemName); } } + private static boolean hasResource(String resource) { + return OpusCodec.class.getResource(resource) != null; + } + public static void extractNatives(File directory) throws IOException { String nativeLibraryName = getNativeLibraryName(); Files.copy(OpusCodec.class.getResourceAsStream("/native-binaries/" + nativeLibraryName), diff --git a/opus-jni-native/3rdparty/CMakeLists.txt b/opus-jni-native/3rdparty/CMakeLists.txt index c2cd8a7..6a78a1e 100644 --- a/opus-jni-native/3rdparty/CMakeLists.txt +++ b/opus-jni-native/3rdparty/CMakeLists.txt @@ -3,12 +3,15 @@ ############ # Thanks to someone having an old CPU :) +set(AVX_SUPPORTED OFF CACHE BOOL "" FORCE) set(OPUS_X86_MAY_HAVE_SSE OFF CACHE BOOL "" FORCE) set(OPUS_X86_MAY_HAVE_SSE2 OFF CACHE BOOL "" FORCE) set(OPUS_X86_MAY_HAVE_SSE4_1 OFF CACHE BOOL "" FORCE) set(OPUS_X86_MAY_HAVE_AVX OFF CACHE BOOL "" FORCE) set(OPUS_X86_PRESUME_SSE OFF CACHE BOOL "" FORCE) set(OPUS_X86_PRESUME_SSE2 OFF CACHE BOOL "" FORCE) +set(OPUS_X86_MAY_HAVE_SSE4_1 OFF CACHE BOOL "" FORCE) +set(OPUS_X86_MAY_HAVE_AVX OFF CACHE BOOL "" FORCE) set(OPUS_ENABLE_FLOAT_API ON CACHE BOOL "" FORCE) set(OPUS_FIXED_POINT ON CACHE BOOL "" FORCE) add_subdirectory(opus) diff --git a/opus-jni-native/build.gradle b/opus-jni-native/build.gradle index 637d50e..8934978 100644 --- a/opus-jni-native/build.gradle +++ b/opus-jni-native/build.gradle @@ -1,4 +1,5 @@ import net.jan.gradle.cmake.tasks.CMakeBuildTask +import org.apache.tools.ant.taskdefs.condition.Os buildscript { dependencies { @@ -13,6 +14,22 @@ task build(type: CMakeBuildTask) { generationDirectory new File(buildDir, "cmake-gen") cmake { + if(is32bit) { + if(!Os.isFamily(Os.FAMILY_WINDOWS)) { + throw new GradleException("Only windows supports 32bit currently") + } else { + arguments = [ + "-A", "Win32", + "-T", "host=x64" + ] + } + } else if(Os.isFamily(Os.FAMILY_WINDOWS)) { + arguments = [ + "-A", "x64", + "-T", "host=x64" + ] + } + variables = [ "CMAKE_BUILD_TYPE": java.util.Optional.of("Release"), "CMAKE_RUNTIME_OUTPUT_DIRECTORY": java.util.Optional.of(nativeBinariesDir.absolutePath),