Skip to content

Commit 7500958

Browse files
committed
Use distinct paths for JNI and vanilla natives
No longer uses a root "natives" directory, benchmarking multiple implementations is now safe and can't collide with other libraries such as zstd-jni
1 parent 521020b commit 7500958

File tree

12 files changed

+87
-77
lines changed

12 files changed

+87
-77
lines changed

.github/workflows/publish.yml

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ jobs:
9898
cd jni-impl/natives/build-$arch
9999
cmake $COMMON_JNI_NATIVES_CMAKE_FLAGS -A $arch ..
100100
cmake --build . -j 4 --config Release
101-
cp Release/libzstd-jni.dll ../../../output/$arch/libzstd.dll
101+
cp Release/libzstd-jni.dll ../../../output/$arch/libzstd-jni.dll
102102
cd ../../..
103103
done
104104
elif [[ "${{ matrix.os }}" == "ubuntu-latest" ]]; then
@@ -118,15 +118,15 @@ jobs:
118118
cmake $COMMON_JNI_NATIVES_CMAKE_FLAGS ..
119119
fi
120120
cmake --build . -j 4
121-
cp libzstd-jni.so ../../../output/$arch/libzstd.so
121+
cp libzstd-jni.so ../../../output/$arch/libzstd-jni.so
122122
cd ../../..
123123
done
124124
elif [[ "${{ matrix.os }}" == "macos-latest" ]]; then
125125
mkdir jni-impl/natives/build output
126126
cd jni-impl/natives/build
127127
cmake $COMMON_JNI_NATIVES_CMAKE_FLAGS "-DCMAKE_OSX_ARCHITECTURES=arm64;arm64e;x86_64;x86_64h" ..
128128
cmake --build . -j 4 --config Release
129-
cp libzstd-jni.dylib ../../../output/libzstd.dylib
129+
cp libzstd-jni.dylib ../../../output/libzstd-jni.dylib
130130
cd ../../..
131131
fi
132132
@@ -188,12 +188,12 @@ jobs:
188188
mkdir -p jni-impl/src/main/resources/natives/win32-x86-64
189189
mkdir -p jni-impl/src/main/resources/natives/win32-aarch64
190190
mkdir -p jni-impl/src/main/resources/natives/darwin
191-
cp temp-jni-natives/x64/libzstd.so jni-impl/src/main/resources/natives/linux-x86-64/libzstd.so
192-
cp temp-jni-natives/ARM64/libzstd.so jni-impl/src/main/resources/natives/linux-aarch64/libzstd.so
193-
cp temp-jni-natives/ARM/libzstd.so jni-impl/src/main/resources/natives/linux-arm/libzstd.so
194-
cp temp-jni-natives/x64/libzstd.dll jni-impl/src/main/resources/natives/win32-x86-64/libzstd.dll
195-
cp temp-jni-natives/ARM64/libzstd.dll jni-impl/src/main/resources/natives/win32-aarch64/libzstd.dll
196-
cp temp-jni-natives/libzstd.dylib jni-impl/src/main/resources/natives/darwin/libzstd.dylib
191+
cp temp-jni-natives/x64/libzstd-jni.so jni-impl/src/main/resources/natives/linux-x86-64/libzstd-jni.so
192+
cp temp-jni-natives/ARM64/libzstd-jni.so jni-impl/src/main/resources/natives/linux-aarch64/libzstd-jni.so
193+
cp temp-jni-natives/ARM/libzstd-jni.so jni-impl/src/main/resources/natives/linux-arm/libzstd-jni.so
194+
cp temp-jni-natives/x64/libzstd-jni.dll jni-impl/src/main/resources/natives/win32-x86-64/libzstd-jni.dll
195+
cp temp-jni-natives/ARM64/libzstd-jni.dll jni-impl/src/main/resources/natives/win32-aarch64/libzstd-jni.dll
196+
cp temp-jni-natives/libzstd-jni.dylib jni-impl/src/main/resources/natives/darwin/libzstd-jni.dylib
197197
198198
- name: Run tests
199199
env:

.github/workflows/test.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ jobs:
5555
cd build-x64
5656
cmake $COMMON_JNI_NATIVES_CMAKE_FLAGS ..
5757
cmake --build . -j 4
58-
cp libzstd-jni.so ../../../output/x64/libzstd.so
58+
cp libzstd-jni.so ../../../output/x64/libzstd-jni.so
5959
cd ..
6060
6161
- name: Publish Artifacts
@@ -103,7 +103,7 @@ jobs:
103103
mkdir -p natives/src/main/resources/natives/linux-x86-64
104104
mkdir -p jni-impl/src/main/resources/natives/linux-x86-64
105105
cp temp-zstd/x64/libzstd.so natives/src/main/resources/natives/linux-x86-64/libzstd.so
106-
cp temp-jni-natives/x64/libzstd.so jni-impl/src/main/resources/natives/linux-x86-64/libzstd.so
106+
cp temp-jni-natives/x64/libzstd-jni.so jni-impl/src/main/resources/natives/linux-x86-64/libzstd-jni.so
107107
108108
- name: Run tests
109109
env:

api/src/main/java/dev/freya02/discord/zstd/api/DiscordZstdNativesLoader.java

Lines changed: 1 addition & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -51,48 +51,6 @@ public static synchronized boolean load(Path path) {
5151
return true;
5252
}
5353

54-
/**
55-
* Loads the natives from this library's JAR.
56-
*
57-
* @throws UnsupportedOperationException
58-
* If the current platform (OS + architecture) is not supported by default
59-
* @throws IOException
60-
* When the native extraction fails
61-
*
62-
* @return {@code true} if the natives were loaded, {@code false} if they already were
63-
*/
64-
public static synchronized boolean loadFromJar() throws IOException {
65-
if (init)
66-
return false;
67-
68-
String architecture = NativeUtil.getCanonicalArchitecture(System.getProperty("os.arch"));
69-
String osName = System.getProperty("os.name");
70-
71-
String platform;
72-
String extension;
73-
if (osName.startsWith("Linux")) {
74-
if (!architecture.equals("x86-64") && !architecture.equals("aarch64") && !architecture.equals("arm"))
75-
throw new IllegalStateException("Unsupported architecture: " + architecture);
76-
platform = "linux-" + architecture;
77-
extension = "so";
78-
} else if (osName.startsWith("Mac") || osName.startsWith("Darwin")) {
79-
platform = "darwin";
80-
extension = "dylib";
81-
} else if (osName.startsWith("Windows")) {
82-
if (!architecture.equals("x86-64") && !architecture.equals("aarch64"))
83-
throw new IllegalStateException("Unsupported architecture: " + architecture);
84-
platform = "win32-" + architecture;
85-
extension = "dll";
86-
} else {
87-
throw new UnsupportedOperationException("Unsupported OS: " + osName);
88-
}
89-
90-
String resourcePath = String.format("/natives/%s/libzstd.%s", platform, extension);
91-
Path nativePath = NativeUtil.copyNativeFromJar(resourcePath, DiscordZstdNativesLoader.class);
92-
load(nativePath);
93-
return true;
94-
}
95-
9654
/**
9755
* Loads the natives using the provided path from the provided class.
9856
*
@@ -120,7 +78,7 @@ public static synchronized boolean loadFromJar(String resourcePath, Class<?> cla
12078
if (clazz == null)
12179
throw new IllegalArgumentException("clazz is null");
12280

123-
Path nativePath = NativeUtil.copyNativeFromJar(resourcePath, clazz);
81+
Path nativePath = IOUtil.copyNativeFromJar(resourcePath, clazz);
12482
load(nativePath);
12583
return true;
12684
}

api/src/main/java/dev/freya02/discord/zstd/api/NativeUtil.java renamed to api/src/main/java/dev/freya02/discord/zstd/api/IOUtil.java

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,25 +7,14 @@
77
import java.nio.file.Path;
88
import java.nio.file.StandardCopyOption;
99

10-
class NativeUtil {
11-
static String getCanonicalArchitecture(String arch) {
12-
arch = arch.toLowerCase().trim();
13-
if ("i386".equals(arch) || "i686".equals(arch)) {
14-
arch = "x86";
15-
} else if ("x86_64".equals(arch) || "amd64".equals(arch)) {
16-
arch = "x86-64";
17-
}
18-
19-
return arch;
20-
}
21-
10+
class IOUtil {
2211
static Path copyNativeFromJar(String resourcePath, Class<?> clazz) throws IOException {
2312
final Path path = Files.createTempFile("libzstd", null);
2413
path.toFile().deleteOnExit();
2514

2615
try (InputStream stream = clazz.getResourceAsStream(resourcePath)) {
2716
if (stream == null)
28-
throw new FileNotFoundException("Natives not found at " + resourcePath);
17+
throw new FileNotFoundException("Natives not found at '" + resourcePath + "' relative to '" + clazz.getPackage().getName() + "'");
2918

3019
Files.copy(stream, path, StandardCopyOption.REPLACE_EXISTING);
3120
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package dev.freya02.discord.zstd.internal;
2+
3+
public class NativeUtil {
4+
public static System getSystem() {
5+
String architecture = getCanonicalArchitecture(java.lang.System.getProperty("os.arch"));
6+
String osName = java.lang.System.getProperty("os.name");
7+
8+
String platform;
9+
String sharedLibraryExtension;
10+
if (osName.startsWith("Linux")) {
11+
if (!architecture.equals("x86-64") && !architecture.equals("aarch64") && !architecture.equals("arm"))
12+
throw new IllegalStateException("Unsupported architecture: " + architecture);
13+
platform = "linux-" + architecture;
14+
sharedLibraryExtension = "so";
15+
} else if (osName.startsWith("Mac") || osName.startsWith("Darwin")) {
16+
platform = "darwin";
17+
sharedLibraryExtension = "dylib";
18+
} else if (osName.startsWith("Windows")) {
19+
if (!architecture.equals("x86-64") && !architecture.equals("aarch64"))
20+
throw new IllegalStateException("Unsupported architecture: " + architecture);
21+
platform = "win32-" + architecture;
22+
sharedLibraryExtension = "dll";
23+
} else {
24+
throw new UnsupportedOperationException("Unsupported OS: " + osName);
25+
}
26+
27+
return new System(platform, sharedLibraryExtension);
28+
}
29+
30+
private static String getCanonicalArchitecture(String arch) {
31+
arch = arch.toLowerCase().trim();
32+
if ("i386".equals(arch) || "i686".equals(arch)) {
33+
arch = "x86";
34+
} else if ("x86_64".equals(arch) || "amd64".equals(arch)) {
35+
arch = "x86-64";
36+
}
37+
38+
return arch;
39+
}
40+
41+
public static class System {
42+
public final String platform;
43+
public final String sharedLibraryExtension;
44+
45+
private System(String platform, String sharedLibraryExtension) {
46+
this.platform = platform;
47+
this.sharedLibraryExtension = sharedLibraryExtension;
48+
}
49+
}
50+
}

ffm-impl/src/main/java/dev/freya02/discord/zstd/ffm/DiscordZstdFFM.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package dev.freya02.discord.zstd.ffm;
22

33
import dev.freya02.discord.zstd.api.*;
4+
import dev.freya02.discord.zstd.internal.NativeUtil;
45
import org.jspecify.annotations.NullMarked;
56
import org.slf4j.Logger;
67
import org.slf4j.LoggerFactory;
@@ -15,7 +16,11 @@ public DiscordZstdFFM() throws IOException {
1516
LOGGER.debug("Using FFM implementation of discord-zstd-java");
1617

1718
// Load natives if they weren't already
18-
DiscordZstdNativesLoader.loadFromJar();
19+
if (!DiscordZstdNativesLoader.isLoaded()) {
20+
NativeUtil.System system = NativeUtil.getSystem();
21+
String absoluteNativeResource = String.format("/dev/freya02/discord/zstd/natives/%s/libzstd.%s", system.platform, system.sharedLibraryExtension);
22+
DiscordZstdNativesLoader.loadFromJar(absoluteNativeResource, DiscordZstd.class);
23+
}
1924
}
2025

2126
@Override

jna-impl/src/test/java/dev/freya02/discord/zstd/jna/ZstdJNATest.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
package dev.freya02.discord.zstd.jna;
22

33
import dev.freya02.discord.zstd.TestChunks;
4+
import dev.freya02.discord.zstd.api.DiscordZstd;
45
import dev.freya02.discord.zstd.api.DiscordZstdDecompressor;
56
import dev.freya02.discord.zstd.api.DiscordZstdDecompressorFactory;
67
import dev.freya02.discord.zstd.api.DiscordZstdNativesLoader;
8+
import dev.freya02.discord.zstd.internal.NativeUtil;
79
import org.junit.jupiter.api.BeforeAll;
810
import org.junit.jupiter.api.Test;
911

1012
import java.io.IOException;
1113
import java.util.List;
1214

1315
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
14-
import static org.junit.jupiter.api.Assertions.assertTrue;
1516

1617
public class ZstdJNATest {
1718

@@ -24,7 +25,9 @@ public static void setup() {
2425

2526
@Test
2627
public void test_decompression() throws IOException {
27-
assertTrue(DiscordZstdNativesLoader.loadFromJar());
28+
NativeUtil.System system = NativeUtil.getSystem();
29+
String absoluteNativeResource = String.format("/dev/freya02/discord/zstd/natives/%s/libzstd.%s", system.platform, system.sharedLibraryExtension);
30+
DiscordZstdNativesLoader.loadFromJar(absoluteNativeResource, DiscordZstd.class);
2831

2932
DiscordZstdDecompressorFactory factory = new ZstdJNADecompressorFactoryProvider().get(DiscordZstdDecompressor.DEFAULT_BUFFER_SIZE);
3033
DiscordZstdDecompressor decompressor = factory.create();

jni-impl/.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
/src/main/resources/natives
1+
/src/main/resources/dev/freya02/discord/zstd/jni/natives

jni-impl/compile-natives.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,5 @@ mkdir build
2121
cd build || exit
2222
cmake .. -DCMAKE_BUILD_TYPE=Release
2323
cmake --build . -j 8
24-
mkdir -p ../../src/main/resources/natives/linux-"$jna_arch"
25-
cp ./libzstd-jni.so ../../src/main/resources/natives/linux-"$jna_arch"/libzstd.so
24+
mkdir -p ../../src/main/resources/dev/freya02/discord/zstd/jni/natives/linux-"$jna_arch"
25+
cp ./libzstd-jni.so ../../src/main/resources/dev/freya02/discord/zstd/jni/natives/linux-"$jna_arch"/libzstd-jni.so

jni-impl/src/main/java/dev/freya02/discord/zstd/jni/DiscordZstdJNI.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package dev.freya02.discord.zstd.jni;
22

33
import dev.freya02.discord.zstd.api.*;
4+
import dev.freya02.discord.zstd.internal.NativeUtil;
45
import org.jspecify.annotations.NullMarked;
56
import org.slf4j.Logger;
67
import org.slf4j.LoggerFactory;
@@ -15,7 +16,11 @@ public DiscordZstdJNI() throws IOException {
1516
LOGGER.debug("Using JNI implementation of discord-zstd-java");
1617

1718
// Load natives if they weren't already
18-
DiscordZstdNativesLoader.loadFromJar();
19+
if (!DiscordZstdNativesLoader.isLoaded()) {
20+
NativeUtil.System system = NativeUtil.getSystem();
21+
String relativeNativeResource = String.format("natives/%s/libzstd-jni.%s", system.platform, system.sharedLibraryExtension);
22+
DiscordZstdNativesLoader.loadFromJar(relativeNativeResource, DiscordZstdJNI.class);
23+
}
1924
}
2025

2126
@Override

0 commit comments

Comments
 (0)