Skip to content

Commit

Permalink
Merge pull request #53 from Over-Run/os
Browse files Browse the repository at this point in the history
Native libraries related changes
  • Loading branch information
squid233 committed May 19, 2024
2 parents 7c03902 + 697aed5 commit 2d53d84
Show file tree
Hide file tree
Showing 7 changed files with 107 additions and 161 deletions.
63 changes: 44 additions & 19 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

import org.gradle.plugins.ide.idea.model.IdeaModel

plugins {
Expand Down Expand Up @@ -75,7 +74,7 @@ artifactNameMap.forEach { (subprojectName, artifactName) ->

tasks.named<Jar>("jar") {
manifestContentCharset = "utf-8"
setMetadataCharset("utf-8")
metadataCharset = "utf-8"
manifest.attributes(
"Specification-Title" to projName,
"Specification-Vendor" to "Overrun Organization",
Expand Down Expand Up @@ -118,7 +117,6 @@ artifactNameMap.forEach { (subprojectName, artifactName) ->
allprojects {
tasks.withType<Javadoc> {
options {
verbose()
if (this is CoreJavadocOptions) {
if (jdkEnablePreview.toBoolean()) {
addBooleanOption("-enable-preview", true)
Expand Down Expand Up @@ -160,6 +158,47 @@ allprojects {
}
}

Artifact.values().forEach {
project(it.subprojectName) {
val javaComponent = components.findByName("java") as AdhocComponentWithVariants
// Add a different runtime variant for each platform
it.nativeBinding?.platforms?.forEach { platform ->
val nativeFileName = it.nativeFileName(platform)
val file = File("${rootProject.projectDir}/natives/$nativeFileName")

if (file.exists()) {
val archiveTaskName = "${it.nativeBinding?.bindingName}${platform.classifier}Jar"

val nativeJar = tasks.register<Jar>(archiveTaskName) {
archiveBaseName.set(it.artifactName)
archiveClassifier.set(platform.classifier)
from(file) { into(File(nativeFileName).parent) }
}

val nativeRuntimeElements = configurations.create(platform.classifier + "RuntimeElements") {
isCanBeConsumed = true; isCanBeResolved = false
attributes {
attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category.LIBRARY))
attribute(Bundling.BUNDLING_ATTRIBUTE, objects.named(Bundling.EXTERNAL))
attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, targetJavaVersion)
attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(LibraryElements.JAR))
attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage.JAVA_RUNTIME))
attributes.attribute(
OperatingSystemFamily.OPERATING_SYSTEM_ATTRIBUTE,
objects.named(platform.osFamilyName)
)
attributes.attribute(MachineArchitecture.ARCHITECTURE_ATTRIBUTE, objects.named(platform.osArch))
}
outgoing.artifact(tasks.named("jar"))
outgoing.artifact(nativeJar)
extendsFrom(configurations["runtimeElements"])
}
javaComponent.addVariantsFromConfiguration(nativeRuntimeElements) {}
}
}
}
}

publishing.publications {
fun MavenPom.setupPom(pomName: String, pomDescription: String, pomPackaging: String) {
name.set(pomName)
Expand Down Expand Up @@ -192,26 +231,12 @@ publishing.publications {
}

Artifact.values().forEach { module ->
create<MavenPublication>("maven${module.mavenName}") {
create<MavenPublication>("maven${module.name}") {
groupId = projGroupId
artifactId = module.artifactName
version = projVersion
description = module.projectDescription
project(module.subprojectName) {
from(components["java"])
}
module.nativeBinding?.platforms?.forEach {
val nativeName = module.nativeFileName(it)!!
val file = File("${rootProject.projectDir}/natives/$nativeName")
if (file.exists()) {
val nativeParent = File(nativeName).parent
artifact(tasks.register<Jar>("nativeJar${module.mavenName}${it.taskSuffix}") {
archiveBaseName.set(module.artifactName)
archiveClassifier.set(it.classifier)
from(file) { into(nativeParent) }
})
}
}
from(project(module.subprojectName).components["java"])
pom {
setupPom(module.projectName, module.projectDescription, "jar")
}
Expand Down
46 changes: 21 additions & 25 deletions buildSrc/src/main/kotlin/myproject.java-conventions.gradle.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,20 @@
enum class NativePlatform(
val osFamilyName: String,
val osArch: String,
classifier: String,
val nativeLibPrefix: String,
val nativeLibSuffix: String,
val taskSuffix: String
classifier: String = "$osFamilyName-$osArch",
val nativeLibPrefix: String = "lib",
val nativeLibSuffix: String = ".so"
) {
WIN_64("windows", "x64", "windows", "", ".dll", "Win64"),
WIN_ARM64("windows", "arm64", "windows-arm64", "", ".dll", "WinArm64"),
LINUX_64("linux", "x64", "linux", "lib", ".so", "Linux64"),
LINUX_ARM32("linux", "arm32", "linux-arm32", "lib", ".so", "LinuxArm32"),
LINUX_ARM64("linux", "arm64", "linux-arm64", "lib", ".so", "LinuxArm64"),
MACOS("macos", "x64", "macos", "lib", ".dylib", "Macos"),
MACOS_ARM64("macos", "arm64", "macos-arm64", "lib", ".dylib", "MacosArm64");
FREEBSD_X64("freebsd", "x64", classifier = "freebsd"),
LINUX_64("linux", "x64", classifier = "linux"),
LINUX_ARM32("linux", "arm32"),
LINUX_ARM64("linux", "arm64"),
LINUX_PPC64LE("linux", "ppc64le"),
LINUX_RISCV64("linux", "riscv64"),
MACOS("macos", "x64", classifier = "macos", nativeLibSuffix = ".dylib"),
MACOS_ARM64("macos", "arm64", nativeLibSuffix = ".dylib"),
WIN_64("windows", "x64", classifier = "windows", nativeLibPrefix = "", nativeLibSuffix = ".dll"),
WIN_ARM64("windows", "arm64", nativeLibPrefix = "", nativeLibSuffix = ".dll");

companion object {
val ALL = values()
Expand All @@ -42,12 +44,7 @@ enum class NativeBinding(
val basename: String,
vararg val platforms: NativePlatform
) {
GLFW(
"glfw", "glfw3",
NativePlatform.WIN_64,
NativePlatform.LINUX_64, NativePlatform.LINUX_ARM64,
NativePlatform.MACOS, NativePlatform.MACOS_ARM64
),
GLFW("glfw", "glfw", *NativePlatform.ALL),
NFD("nfd", "nfd", *NativePlatform.ALL),
STB("stb", "stb", *NativePlatform.ALL)
}
Expand All @@ -57,38 +54,37 @@ enum class Artifact(
val projectName: String,
val projectDescription: String,
val subprojectName: String,
val mavenName: String,
val nativeBinding: NativeBinding? = null
) {
CORE(
"overrungl", "OverrunGL",
"The OverrunGL core library.",
":core", "Core"
":core"
),
GLFW(
"overrungl-glfw", "OverrunGL - GLFW bindings",
"A multi-platform library for OpenGL, OpenGL ES and Vulkan development on the desktop. It provides a simple API for creating windows, contexts and surfaces, receiving input and events.",
":glfw", "Glfw", NativeBinding.GLFW
":glfw", NativeBinding.GLFW
),
JOML(
"overrungl-joml", "OverrunGL - JOML native access",
"A Java math library for OpenGL rendering calculations",
":joml", "Joml"
":joml"
),
NFD(
"overrungl-nfd", "OverrunGL - Native File Dialog",
"A tiny, neat C library that portably invokes native file open and save dialogs.",
":nfd", "Nfd", NativeBinding.NFD
":nfd", NativeBinding.NFD
),
OPENGL(
"overrungl-opengl", "OverrunGL - OpenGL bindings",
"The most widely adopted 2D and 3D graphics API in the industry, bringing thousands of applications to a wide variety of computer platforms.",
":opengl", "Opengl"
":opengl"
),
STB(
"overrungl-stb", "OverrunGL - stb bindings",
"Single-file public domain libraries for fonts, images, ogg vorbis files and more.",
":stb", "Stb", NativeBinding.STB
":stb", NativeBinding.STB
),
// VULKAN("overrungl-vulkan", "OverrunGL - Vulkan bindings",
// "A new generation graphics and compute API that provides high-efficiency, cross-platform access to modern GPUs used in a wide variety of devices from PCs and consoles to mobile phones and embedded platforms.",
Expand All @@ -97,6 +93,6 @@ enum class Artifact(

fun nativeFileName(platform: NativePlatform): String? {
return if (nativeBinding == null) null
else "${nativeBinding.bindingName}/${platform.osFamilyName}/${platform.osArch}/${platform.nativeLibPrefix}${nativeBinding.basename}${platform.nativeLibSuffix}"
else "${nativeBinding.bindingName}/${platform.osFamilyName}-${platform.osArch}/${platform.nativeLibPrefix}${nativeBinding.basename}${platform.nativeLibSuffix}"
}
}
79 changes: 28 additions & 51 deletions doc/internal/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@

To publish this library, you need a GPG key and the write permission of Maven Central.

### CI

- [glfw](https://github.com/Over-Run/glfw-ci)
- [nfd](https://github.com/Over-Run/nfd-ci)
- [stb](https://github.com/Over-Run/stb-ci)

### Packing Natives

The build script packs the native libraries into jars.
Expand All @@ -12,56 +18,27 @@ The tree structure of the native libraries is:

```text
natives
├─ glfw
│ ├─ linux
│ │ ├─ arm64
│ │ │ └─ libglfw3.so
│ │ └─ x64
│ │ └─ libglfw3.so
│ ├─ macos
│ │ ├─ arm64
│ │ │ └─ libglfw3.dylib
│ │ └─ x64
│ │ └─ libglfw3.dylib
│ └─ windows
│ └─ x64
│ └─ glfw3.dll
├─ nfd https://github.com/Over-Run/nfd-ci
│ ├─ linux
│ │ ├─ arm32
│ │ │ └─ libnfd.so
│ │ ├─ arm64
│ │ │ └─ libnfd.so
│ │ └─ x64
│ │ └─ libnfd.so
│ ├─ macos
│ │ ├─ arm64
│ │ │ └─ libnfd.dylib
│ │ └─ x64
│ │ └─ libnfd.dylib
│ └─ windows
│ ├─ arm64
│ │ └─ nfd.dll
│ └─ x64
│ └─ nfd.dll
└─ stb https://github.com/Over-Run/stb-ci
├─ linux
│ ├─ arm32
│ │ └─ libstb.so
│ ├─ arm64
│ │ └─ libstb.so
│ └─ x64
│ └─ libstb.so
├─ macos
│ ├─ arm64
│ │ └─ libstb.dylib
│ └─ x64
│ └─ libstb.dylib
└─ windows
├─ arm64
│ └─ stb.dll
└─ x64
└─ stb.dll
└─ <module-name>
├─ freebsd-x64
│ └─ lib<basename>.so
├─ linux-arm32
│ └─ lib<basename>.so
├─ linux-arm64
│ └─ lib<basename>.so
├─ linux-ppc64le
│ └─ lib<basename>.so
├─ linux-riscv64
│ └─ lib<basename>.so
├─ linux-x64
│ └─ lib<basename>.so
├─ macos-arm64
│ └─ lib<basename>.dylib
├─ macos-x64
│ └─ lib<basename>.dylib
├─ windows-arm64
│ └─ <basename>.dll
└─ windows-x64
└─ <basename>.dll
```

The `natives` directory is in the project directory.
The `natives` directory is in the root project directory.
6 changes: 3 additions & 3 deletions modules/overrungl.core/src/main/java/overrungl/OverrunGL.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,15 @@ public final class OverrunGL {
/**
* The version of GLFW native libraries.
*/
public static final String GLFW_VERSION = "3.4.0.0";
public static final String GLFW_VERSION = "3.5.0.0";
/**
* The version of NFD native libraries.
*/
public static final String NFD_VERSION = "0.1.0.0";
public static final String NFD_VERSION = "1.1.1.0";
/**
* The version of STB native libraries.
*/
public static final String STB_VERSION = "0.1.0.3";
public static final String STB_VERSION = "0.1.0.4";
private static final Consumer<String> DEFAULT_LOGGER = System.err::println;
private static Consumer<String> apiLogger = DEFAULT_LOGGER;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ public final class RuntimeHelper {
* The native linker.
*/
private static final Linker LINKER = Linker.nativeLinker();
private static final Path tmpdir = Path.of(System.getProperty("java.io.tmpdir"));
private static final Path tmpdir = Path.of(System.getProperty("java.io.tmpdir"))
.resolve(STR."overrungl\{System.getProperty("user.name")}");
private static final StackWalker STACK_WALKER = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);
private static final Map<String, MemoryLayout> CANONICAL_LAYOUTS = LINKER.canonicalLayouts();
/**
Expand Down Expand Up @@ -102,24 +103,23 @@ public static SymbolLookup load(String module, String basename, String version)
uri = localFile;
} else {
// 2. Load from classpath
var file = tmpdir.resolve(STR."overrungl\{System.getProperty("user.name")}");
try {
if (!Files.exists(file)) {
if (!Files.exists(tmpdir)) {
// Create directory
Files.createDirectories(file);
} else if (!Files.isDirectory(file)) {
Files.createDirectories(tmpdir);
} else if (!Files.isDirectory(tmpdir)) {
// Remove
Files.delete(file);
Files.delete(tmpdir);
// Create directory
Files.createDirectories(file);
Files.createDirectories(tmpdir);
}
} catch (IOException e) {
throw new IllegalStateException(STR."Couldn't create directory: \{file}; try setting -Doverrungl.natives to a valid path", e);
throw new IllegalStateException(STR."Couldn't create directory: \{tmpdir}; try setting -Doverrungl.natives to a valid path", e);
}
var libFile = file.resolve(STR."\{basename}-\{version}\{suffix}");
var libFile = tmpdir.resolve(STR."\{basename}-\{version}\{suffix}");
if (!Files.exists(libFile)) {
// Extract
final String fromPath = STR."\{module}/\{os.familyName()}/\{Architecture.current()}/\{path}";
final String fromPath = STR."\{module}/\{os.familyName()}-\{Architecture.current()}/\{path}";
try (var is = STACK_WALKER.getCallerClass().getClassLoader().getResourceAsStream(fromPath)) {
Files.copy(Objects.requireNonNull(is, STR."File not found in classpath: \{fromPath}"), libFile);
} catch (Exception e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ final class Handles {
static final SymbolLookup lookup;

static {
final Supplier<SymbolLookup> lib = () -> RuntimeHelper.load("glfw", "glfw3", OverrunGL.GLFW_VERSION);
final Supplier<SymbolLookup> lib = () -> RuntimeHelper.load("glfw", "glfw", OverrunGL.GLFW_VERSION);
final var function = Configurations.GLFW_SYMBOL_LOOKUP.get();
lookup = function != null ? function.apply(lib) : lib.get();
}
Expand Down
Loading

0 comments on commit 2d53d84

Please sign in to comment.