Skip to content

Commit a3f6710

Browse files
committed
graalvm native image and shared library
1 parent 41657da commit a3f6710

File tree

7 files changed

+142
-25
lines changed

7 files changed

+142
-25
lines changed

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,10 +173,11 @@ By default it will generate next artifacts in `${outputDirectory} ` folder:
173173
| `extra` | :x: | | Map with extra properties to be used in customized Velocity templates, accesible through `$info.extra` variable. |
174174
| `fileAssociations` | :x: | [`FileAssociation[]`](https://github.com/fvarrui/JavaPackager/blob/master/src/main/java/io/github/fvarrui/javapackager/model/FileAssociation.java) | Associate file extensions or MIME types to the app. |
175175
| `forceInstaller` | :x: | `false` | If `true`, skips operating system check when generating installers. |
176-
| `nativeImage` | :x: | `false` | If `true`, generates a native-image. Note that `jdkVendor` must be set to `graalvm` for this to work. |
176+
| `nativeImage` | :x: | `false` | If `true`, generates a native image for the current operating system. Note that `jdkVendor` must be set to `graalvm` for this to work. |
177+
| `sharedLibrary` | :x: | `false` | If `true`, generates a shared library for the current operating system. Note that `jdkVendor` must be set to `graalvm` for this to work. |
177178
| `generateInstaller` | :x: | `true` | Generates an installer for the app. |
178179
| `jdkVersion` | :x: | `latest` | JDK version to download and use. The latest version is used by default. See all available versions here: [adoptium](https://api.adoptium.net/v3/info/available_releases). |
179-
| `jdkVendor` | :x: | `graalvm` | JDK vendor to download the JDK from. Currently supported: `adoptium, graalvm` |
180+
| `jdkVendor` | :x: | `graalvm` | JDK vendor to download the JDK from. Currently supported: `adoptium, graalvm` |
180181
| `jdkPath` | :x: | `null` | If null downloads (if necessary and also updates it if needed) the right JDK for the selected platform and sets this value to `<temp-dir>/jdk/win` or `<temp-dir>/jdk/linux` or `<temp-dir>/jdk/mac`. The downloaded JDK will be used to generate a customized JRE. |
181182
| `jreDirectoryName` | :x: | `"jre"` | Bundled JRE directory name. |
182183
| `jreMinVersion` | :x: | | JRE minimum version. If an appropriate version cannot be found display error message. Disabled if a JRE is bundled. |

src/main/java/io/github/fvarrui/javapackager/PackageTask.java

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import io.github.fvarrui.javapackager.model.*;
44
import io.github.fvarrui.javapackager.packagers.PackagerFactory;
5+
import io.github.fvarrui.javapackager.utils.Const;
56
import io.github.fvarrui.javapackager.utils.updater.AdoptV3API;
67
import org.apache.commons.lang3.StringUtils;
78
import org.apache.maven.plugins.annotations.Parameter;
@@ -61,6 +62,13 @@ public class PackageTask {
6162
@Input
6263
@Optional
6364
protected Boolean nativeImage;
65+
/**
66+
* If true generates a shared library. Note that {@link #jdkVendor} must be set to graalvm for this to work.
67+
*/
68+
@Parameter(property = "sharedLibrary")
69+
@Input
70+
@Optional
71+
protected Boolean sharedLibrary;
6472
/**
6573
* Full path to your app main class.
6674
*/
@@ -366,6 +374,7 @@ public PackageTask() throws IOException {
366374
this.modules = new ArrayList<>();
367375
this.forceInstaller = false;
368376
this.nativeImage = false;
377+
this.sharedLibrary = false;
369378
this.mainClass = "${exec.mainClass}"; //TODO gradle?
370379
//this.appName = (isGradle ? gradleProject.getName() : "${project.name}");
371380
//this.appDisplayName = (isGradle ? gradleProject.getName() : "${project.name}");
@@ -381,7 +390,7 @@ public PackageTask() throws IOException {
381390
this.jrePath = null;
382391
this.jdkPath = null;
383392
this.jdkVersion = new AdoptV3API().getLatestRelease();
384-
this.jdkVendor = "graalvm";
393+
this.jdkVendor = Const.graalvm;
385394
this.additionalResources = new ArrayList<>();
386395
this.modules = new ArrayList<>();
387396
this.additionalModules = new ArrayList<>();
@@ -465,6 +474,10 @@ public Boolean isNativeImage() {
465474
return nativeImage;
466475
}
467476

477+
public Boolean isSharedLibrary() {
478+
return sharedLibrary;
479+
}
480+
468481
/**
469482
* Get main class
470483
*
@@ -889,6 +902,11 @@ public PackageTask nativeImage(Boolean nativeImage) {
889902
return this;
890903
}
891904

905+
public PackageTask sharedLibrary(Boolean sharedLibrary) {
906+
this.sharedLibrary = sharedLibrary;
907+
return this;
908+
}
909+
892910
/**
893911
* Set main class
894912
*

src/main/java/io/github/fvarrui/javapackager/packagers/Context.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ public Context() {
3232
getInstallerGenerators(Platform.linux).add(new GenerateNativeImage());
3333
getInstallerGenerators(Platform.mac).add(new GenerateNativeImage());
3434
getInstallerGenerators(Platform.windows).add(new GenerateNativeImage());
35+
36+
getInstallerGenerators(Platform.linux).add(new GenerateSharedLibrary());
37+
getInstallerGenerators(Platform.mac).add(new GenerateSharedLibrary());
38+
getInstallerGenerators(Platform.windows).add(new GenerateSharedLibrary());
3539
}
3640

3741
// common properties
Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,10 @@
11
package io.github.fvarrui.javapackager.packagers;
22

3-
import io.github.fvarrui.javapackager.utils.Const;
4-
import io.github.fvarrui.javapackager.utils.Logger;
5-
import io.github.fvarrui.javapackager.utils.VelocityUtils;
6-
import io.github.fvarrui.javapackager.utils.XMLUtils;
3+
import io.github.fvarrui.javapackager.utils.*;
74

85
import java.io.File;
96
import java.util.Objects;
107

11-
import static io.github.fvarrui.javapackager.utils.CommandUtils.execute;
12-
13-
/**
14-
* TODO
15-
*/
168
public class GenerateNativeImage extends ArtifactGenerator<Packager> {
179

1810
public GenerateNativeImage() {
@@ -36,15 +28,9 @@ public boolean skip(Packager packager) {
3628

3729
@Override
3830
protected File doApply(Packager packager) throws Exception {
39-
40-
File assetsFolder = packager.getAssetsFolder();
41-
String name = packager.task.getAppName();
4231
File outputDirectory = packager.task.getOutputDirectory();
43-
String version = packager.task.getVersion();
44-
45-
//TODO
46-
47-
return null;
32+
GraalVM graalVM = new GraalVM(packager.task.getJdkPath());
33+
return graalVM.generateNativeImage(packager.task.getPlatform(), outputDirectory);
4834
}
4935

5036
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package io.github.fvarrui.javapackager.packagers;
2+
3+
import io.github.fvarrui.javapackager.utils.Const;
4+
import io.github.fvarrui.javapackager.utils.GraalVM;
5+
import io.github.fvarrui.javapackager.utils.Logger;
6+
7+
import java.io.File;
8+
import java.util.Objects;
9+
10+
public class GenerateSharedLibrary extends ArtifactGenerator<Packager> {
11+
12+
public GenerateSharedLibrary() {
13+
super("Shared library");
14+
}
15+
16+
@Override
17+
public boolean skip(Packager packager) {
18+
19+
if (!packager.task.isSharedLibrary()) {
20+
return true;
21+
}
22+
23+
if (!Objects.equals(packager.task.getJdkVendor(), Const.graalvm)) {
24+
Logger.warn(getArtifactName() + " cannot be generated because '"+Const.graalvm +"' was expected as jdkVendor, but provided '"+packager.task.getJdkVendor()+"'!");
25+
return true;
26+
}
27+
28+
return false;
29+
}
30+
31+
@Override
32+
protected File doApply(Packager packager) throws Exception {
33+
File outputDirectory = packager.task.getOutputDirectory();
34+
GraalVM graalVM = new GraalVM(packager.task.getJdkPath());
35+
return graalVM.generateSharedLibrary(packager.task.getPlatform(), outputDirectory);
36+
}
37+
38+
}

src/main/java/io/github/fvarrui/javapackager/packagers/Packager.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,7 @@
1515
import io.github.fvarrui.javapackager.model.MacConfig;
1616
import io.github.fvarrui.javapackager.model.Platform;
1717
import io.github.fvarrui.javapackager.model.WindowsConfig;
18-
import io.github.fvarrui.javapackager.utils.FileUtils;
19-
import io.github.fvarrui.javapackager.utils.IconUtils;
20-
import io.github.fvarrui.javapackager.utils.Logger;
21-
import io.github.fvarrui.javapackager.utils.VelocityUtils;
18+
import io.github.fvarrui.javapackager.utils.*;
2219
import io.github.fvarrui.javapackager.utils.updater.TaskJavaUpdater;
2320

2421
/**
@@ -135,6 +132,11 @@ private void init() throws Exception {
135132
taskJavaUpdater.execute(task.getJdkVersion(), task.getJdkVendor());
136133
task.jdkPath(taskJavaUpdater.jdkPath);
137134
if(task.getPackagingJdk() == null) task.packagingJdk(taskJavaUpdater.jdkPath);
135+
} else{
136+
// Custom JDK path doesn't support native image
137+
// since there is currently no check to see if the JDK is GraalVM
138+
if(task.isNativeImage())
139+
throw new Exception("Custom JDK does not support native-image! Select "+ Const.graalvm+" as JDK vendor to fix this.");
138140
}
139141
if (!task.getJdkPath().exists()) {
140142
throw new Exception("JDK path doesn't exist: " + task.getJdkPath());
Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,82 @@
11
package io.github.fvarrui.javapackager.utils;
22

3+
import io.github.fvarrui.javapackager.model.Platform;
4+
import org.codehaus.plexus.util.cli.CommandLineException;
5+
36
import java.io.File;
7+
import java.io.FileNotFoundException;
8+
import java.io.IOException;
49
import java.nio.file.NotDirectoryException;
510

611
public class GraalVM {
712
public File dir;
13+
public File dirBin;
14+
public File guScript;
815

9-
public GraalVM(File dir) throws NotDirectoryException {
16+
public GraalVM(File dir) throws NotDirectoryException, FileNotFoundException {
1017
if(!dir.isDirectory()) throw new NotDirectoryException(dir.toString());
1118
this.dir = dir;
19+
this.dirBin = new File(dir+"/bin");
20+
if(!dirBin.exists()) throw new FileNotFoundException(dirBin.toString());
21+
for (File file : dirBin.listFiles()) {
22+
if(file.getName().contains("gu.")){
23+
this.guScript = file;
24+
break;
25+
}
26+
}
27+
if(guScript==null || !guScript.exists()) throw new FileNotFoundException("gu script not found inside: "+dirBin);
28+
}
29+
30+
public void guInstall(String name) throws IOException, CommandLineException {
31+
CommandUtils.execute(guScript, "install", name);
32+
}
33+
34+
public File getNativeImageExe(){
35+
File nativeImage = null;
36+
for (File file : dirBin.listFiles()) {
37+
if(file.getName().contains("native-image")){
38+
nativeImage = file;
39+
break;
40+
}
41+
}
42+
return nativeImage;
1243
}
1344

45+
public File generateNativeImage(Platform platform, File outputDirectory) throws IOException, CommandLineException {
46+
guInstall("native-image");
47+
// TODO install other platform dependent dependencies here
48+
49+
File jarFile = null;
50+
for (File file : outputDirectory.listFiles()) {
51+
if(file.getName().endsWith("shaded.jar") || file.getName().endsWith("all.jar") || file.getName().endsWith("dependencies.jar")){
52+
jarFile = file;
53+
break;
54+
}
55+
}
56+
if(jarFile==null || !jarFile.exists())
57+
throw new FileNotFoundException("File ending with \"shaded.jar\" or \"all.jar\" or \"dependencies.jar\"" +
58+
" not found inside: "+outputDirectory);
59+
CommandUtils.executeWithResult(outputDirectory, // working dir = output dir
60+
getNativeImageExe().toString(), "-jar", jarFile, jarFile.getName());
61+
return new File(outputDirectory+"/"+jarFile.getName() + (platform == Platform.windows ? ".exe" : ""));
62+
}
63+
64+
public File generateSharedLibrary(Platform platform, File outputDirectory) throws IOException, CommandLineException {
65+
guInstall("native-image");
66+
// TODO install other platform dependent dependencies here
67+
68+
File jarFile = null;
69+
for (File file : outputDirectory.listFiles()) {
70+
if(file.getName().endsWith("shaded.jar") || file.getName().endsWith("all.jar") || file.getName().endsWith("dependencies.jar")){
71+
jarFile = file;
72+
break;
73+
}
74+
}
75+
if(jarFile==null || !jarFile.exists())
76+
throw new FileNotFoundException("File ending with \"shaded.jar\" or \"all.jar\" or \"dependencies.jar\"" +
77+
" not found inside: "+outputDirectory);
78+
CommandUtils.executeWithResult(outputDirectory, // working dir = output dir
79+
getNativeImageExe().toString(), "-jar", jarFile, jarFile.getName(), "--shared");
80+
return new File(outputDirectory+"/"+jarFile.getName() + (platform == Platform.windows ? ".dll" : ".so"));
81+
}
1482
}

0 commit comments

Comments
 (0)