"filters" for native dependencies
to handle all the various variants of naming used for deps we might want to support:
//DEPS org.lwjgl:lwjgl:3.3.6:natives-macos{platform=osx} //DEPS org.lwjgl:lwjgl:3.3.6:natives-windows-arm64{platform=win_arm64}
semi inspired from jreleaser notion of platform filters.
The important part being that whatever we choose as the name for an os and an arch would always work regardless of what the author of the artifact called it, right?
So if we choose "osx" like in your example (would we call it "osx"??) all the following would match on a Mac (any Mac), right?
//DEPS org.lwjgl:lwjgl:3.3.6:natives-macos{platform=osx} //DEPS org.lwjgl:lwjgl:3.3.6:natives-osx{platform=osx} //DEPS org.lwjgl:lwjgl:3.3.6:natives-mac{platform=osx}
Because it has nothing to do with the classifier of the artifact but only with the filter that says platform=osx.
(just wanted this clearly stated)
Edit: or would you want to be able to filter on "old" macs (osx) and "new" macs (macos)?
We would just need something that is consistent from jbang usage perspective. So we get to pick one - and stick with it forever more.
A "filter" for runtime options would allow the -XstartOnFirstThread JVM runtime option only to be specified for macOS.
Unsure about the exact syntax, but I think
//RUNTIME_OPTIONS{platform=macos} -XstartOnFirstThread
is better than using
//RUNTIME_OPTIONS -XstartOnFirstThread{platform=macos}
But then one should consider specifying platform specific DEPS as
//DEPS{platform=macos} org.lwjgl:lwjgl:3.3.6:natives-macos org.lwjgl:lwjgl-glfw:3.3.6:natives-macos org.lwjgl:lwjgl-opengl:3.3.6:natives-macos
So in general use
//DEPS{guard-clause} dep1 dep2 dep3 .... depn
//RUNTIME_OPTIONS{guard-clause} opt1 opt2 opt3 ... optn
Java library https://github.com/ezylang/EvalEx could be used to evaluate the guard clause or guard expression, but it requires Java 11+ and JBang supports Java 8+.
//DEPS{platform == 'macos'} org.lwjgl:lwjgl:3.3.6:natives-macos org.lwjgl:lwjgl-glfw:3.3.6:natives-macos org.lwjgl:lwjgl-opengl:3.3.6:natives-macos
// https://github.com/ezylang/EvalEx
//DEPS com.ezylang:EvalEx:3.5.0
// Create a new EvalEx instance
Expression expression = new Expression("platform == 'macos'");
// Set the variable 'platform' to the value Util.getPlatform()
expression.with("platform", Util.getPlatform());
// Evaluate the expression
boolean result = expression.eval().getBooleanValue();
// Print the result (true or false)
System.out.println(result);
An aspect to consider is us being able to translate these into Gradle and maven in context of export and edit.
An aspect to consider is us being able to translate these into Gradle and maven in context of export and edit.
Gradle
dependencies {
// Other dependencies
if (org.gradle.internal.os.OperatingSystem.current().isMacOs()) {
// Specify your dependency for macOS only
implementation 'org.lwjgl:lwjgl:3.3.6:natives-macos'
implementation 'org.lwjgl:lwjgl-glfw:3.3.6:natives-macos'
implementation 'org.lwjgl:lwjgl-opengl:3.3.6:natives-macos'
}
}
Maven
<project>
...
<profiles>
<profile>
<id>macos-only</id>
<activation>
<os>
<name>Mac OS X</name>
</os>
</activation>
<dependencies>
<dependency>
<groupId>org.lwjgl</groupId>
<artifactId>lwjgl</artifactId>
<version>3.3.6</version>
<classifier>natives-macos</classifier>
</dependency>
....
</dependencies>
</profile>
</profiles>
...
</project>
How would you get to that from that list of filters?
How would you get to that from that list of filters?
A simpler gaurd-clause expression syntax would help. Instead of using a general expression format
the guard-clause could be restricted to only allow <osType> or <osType>,<archType> to be specified, for example:
//DEPS{macos} org.lwjgl:lwjgl:3.3.6:natives-macos org.lwjgl:lwjgl-glfw:3.3.6:natives-macos org.lwjgl:lwjgl-opengl:3.3.6:natives-macos
or
//DEPS{macos,arm64} org.lwjgl:lwjgl:3.3.6:natives-macos-arm64 org.lwjgl:lwjgl-glfw:3.3.6:natives-macos-arm64 org.lwjgl:lwjgl-opengl:3.3.6:natives-macos-arm64
A secondary data structure for dependencies would be created. It could be a hashmap with key=guard-clause and value a List<String> of deps. But this structure might not fit into JBang's current design.
Map the secondary dependencies data structure to Gradle or Maven build file content.
build.gradle
if (org.gradle.internal.os.OperatingSystem.current().isMacOs() && System.getProperty("os.arch") == "aarch64") {
println "Detected macOS ARM64. Adding LWJGL natives for macOS ARM64."
runtimeOnly "org.lwjgl:lwjgl:3.3.6:natives-macos-arm64"
}
pom.xml
<profiles>
<!-- Profile to activate specifically for macOS ARM64 -->
<profile>
<id>macos-arm64-natives</id>
<activation>
<os>
<family>mac</family>
<arch>aarch64</arch>
</os>
</activation>
<dependencies>
<!-- LWJGL natives for macOS ARM64 -->
<dependency>
<groupId>org.lwjgl</groupId>
<artifactId>lwjgl</artifactId>
<version>3.3.6</version>
<classifier>natives-macos-arm64</classifier>
</dependency>
<dependency>
<groupId>org.lwjgl</groupId>
<artifactId>lwjgl-glfw</artifactId>
<version>3.3.6</version>
<classifier>natives-macos-arm64</classifier>
</dependency>
<dependency>
<groupId>org.lwjgl</groupId>
<artifactId>lwjgl-opengl</artifactId>
<version>3.3.6</version>
<classifier>natives-macos-arm64</classifier>
</dependency>
</dependencies>
</profile>
</profiles>
The same can be done for RUNTIME_OPTIONS.
//RUNTIME_OPTIONS{macos} -XstartOnFirstThread
Alternatively, the guard expressions could be viewed as a filter to be applied to restrict dependencies or runtime options to the current platform that is being used. This would simplify an initial implementation, and export to maven or gradle will not have to be changed as it will only support a single platform (the current one).
In a parallel universe JBangX exists supporting TOML as an embedded configuration language (smile)
java = "21+"
deps = ["org.apache.commons:commons-lang3:3.12.0", "org.slf4j:slf4j-api:2.0.7"]
runtimeOptions = ["-Xmx2g"]
[platform.macos.opt]
runtimeOptions = ["-XstartOnFirstThread"]
[platform.macos.cpu.arm64]
deps = ["org.lwjgl:lwjgl:3.3.6:natives-macos-arm64", "org.lwjgl:lwjgl-glfw:3.3.6:natives-macos-arm64", "org.lwjgl:lwjgl-opengl:3.3.6:natives-macos-arm64"]
[platform.macos.cpu.x86_64]
deps = ["org.lwjgl:lwjgl:3.3.6:natives-macos", "org.lwjgl:lwjgl-glfw:3.3.6:natives-macos", "org.lwjgl:lwjgl-opengl:3.3.6:natives-macos"]
The same config in YAML (converted from TOML).
java: 21+
deps:
- org.apache.commons:commons-lang3:3.12.0
- org.slf4j:slf4j-api:2.0.7
runtimeOptions:
- -Xmx2g
platform:
macos:
opt:
runtimeOptions:
- -XstartOnFirstThread
cpu:
arm64:
deps:
- org.lwjgl:lwjgl:3.3.6:natives-macos-arm64
- org.lwjgl:lwjgl-glfw:3.3.6:natives-macos-arm64
- org.lwjgl:lwjgl-opengl:3.3.6:natives-macos-arm64
x86_64:
deps:
- org.lwjgl:lwjgl:3.3.6:natives-macos
- org.lwjgl:lwjgl-glfw:3.3.6:natives-macos
- org.lwjgl:lwjgl-opengl:3.3.6:natives-macos
The same config but expressed as JSON (converted from TOML).
{
"deps": [
"org.apache.commons:commons-lang3:3.12.0",
"org.slf4j:slf4j-api:2.0.7"
],
"java": "21+",
"runtimeOptions": [
"-Xmx2g"
],
"platform": {
"macos": {
"cpu": {
"arm64": {
"deps": [
"org.lwjgl:lwjgl:3.3.6:natives-macos-arm64",
"org.lwjgl:lwjgl-glfw:3.3.6:natives-macos-arm64",
"org.lwjgl:lwjgl-opengl:3.3.6:natives-macos-arm64"
]
},
"x86_64": {
"deps": [
"org.lwjgl:lwjgl:3.3.6:natives-macos",
"org.lwjgl:lwjgl-glfw:3.3.6:natives-macos",
"org.lwjgl:lwjgl-opengl:3.3.6:natives-macos"
]
}
},
"opt": {
"runtimeOptions": [
"-XstartOnFirstThread"
]
}
}
}
}
No amount of toml helps to map this to maven/gradle.
The point is about ensuring the selections aren't open-ended so we can with high likelihood map to maven/gradle when needed. Doesn't have to be perfect but "close enough".
No amount of toml helps to map this to maven/gradle.
Parsing the source file is a non-issue when using toml. That's nice benefit.
The design explored with the TOML config could be retrofitted to the current version of JBang as:
//RUNTIME_OPTIONS[platform.macos.opt] -XstartOnFirstThread`
//DEPS[platform.macos.cpu.x86_64] org.lwjgl:lwjgl:3.3.6:natives-macos org.lwjgl:lwjgl-glfw:3.3.6:natives-macos org.lwjgl:lwjgl-opengl:3.3.6:natives-macos
No amount of toml helps to map this to maven/gradle.
Parsing the source file is a non-issue when using toml. That's nice benefit.
sorry - but I'm not following what any of this (filtering of native deps) has to do with TOML.
The design explored with the TOML config could be retrofitted to the current version of JBang as:
//RUNTIME_OPTIONS[platform.macos.opt] -XstartOnFirstThread`//DEPS[platform.macos.cpu.x86_64] org.lwjgl:lwjgl:3.3.6:natives-macos org.lwjgl:lwjgl-glfw:3.3.6:natives-macos org.lwjgl:lwjgl-opengl:3.3.6:natives-macos
how is this better/worse than the notion {key0,key1=value2,key2=value2} implemented at #2133 ?
how is this better/worse than the notion {key0,key1=value2,key2=value2} implemented at https://github.com/jbangdev/jbang/pull/2133 ?
This concept is orthogonal to what is proposed in #2133. It provides a mechanism for grouping JBang directives into a hierarchical namespace. #2133 is only concerned with dependencies and adds additional attributes to individual dependencies. Thus two completely different concepts. I'll open a new issue for the hierarchical namespace proposal.
@wfouche I get that you are suggesting to put the {attrlist} at the directive level instead of individual deps - thats fine - its what is in the original proposal (//DEPS{compile} g:a:v) on https://github.com/jbangdev/jbang/issues/2126 but PR didn't start with that as it prevents one from declaring these properties on commandline.
You are proposing a different syntax - and I'm trying to understand why. Wether it its intentional or you simply missed that the original proposal suggests to allow specifying the {attrlist} on the directive?
Whether it its intentional
Yes, I'm thinking of a different (more limited) grouping mechanism. Have created https://github.com/jbangdev/jbang/issues/2188 to discuss it in more detail.
But I can see how //DEPS{os=macos,cpu=arm64} would accomplish the same.