Skip to content

Commit

Permalink
Merged in matt_harbison/appbundler (pull request #51)
Browse files Browse the repository at this point in the history
jlink bundled JRE support
  • Loading branch information
sreilly committed May 30, 2019
2 parents 44d6bea + 6d9d8ca commit 7e624ce
Show file tree
Hide file tree
Showing 6 changed files with 309 additions and 2 deletions.
90 changes: 90 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -183,4 +183,94 @@ Example 2, use installed Java but require Java 8 (or later) JRE and not a JDK:
</bundleapp>
</target>

Example 3, bundle a stripped down JRE that only needs java.base and java.desktop for a non modularized app:

<target name="bundle">
<!-- Obtain path to the selected JRE -->
<exec executable="/usr/libexec/java_home"
failonerror="true"
outputproperty="runtime">
<arg value="-v"/>
<arg value="11"/>
</exec>

<taskdef name="bundleapp"
classpath="appbundler-1.0ea.jar"
classname="com.oracle.appbundler.AppBundlerTask"/>

<bundleapp
classpathref="runclasspathref"
outputdirectory="${dist}"
name="${bundle.name}"
displayname="${bundle.displayname}"
executableName="MyApp"
identifier="com.company.product"
shortversion="${version.public}"
version="${version.internal}"
icon="${icons.path}/${bundle.icns}"
mainclassname="Main"
copyright="2019 Your Company"
applicationCategory="public.app-category.finance">

<jlink runtime="${runtime}">
<jmod name="java.base"/>
<jmod name="java.desktop"/>

<!-- Zip the generated modules file (Optional) -->
<argument value="--compress=2"/>

<!-- Preserve all release properties, but update the modules
- list. (Optional)
-
- See https://bugs.openjdk.java.net/browse/JDK-8179563
-->
<argument value="--release-info=${runtime}/release"/>
</jlink>
</bundleapp>
</target>

Example 4, bundle a stripped down JRE that only needs java.base and java.desktop for a modularized app:

<target name="bundle">
<!-- Obtain path to the selected JRE -->
<exec executable="/usr/libexec/java_home"
failonerror="true"
outputproperty="runtime">
<arg value="-v"/>
<arg value="11"/>
</exec>

<taskdef name="bundleapp"
classpath="appbundler-1.0ea.jar"
classname="com.oracle.appbundler.AppBundlerTask"/>

<bundleapp
classpathref="runclasspathref"
outputdirectory="${dist}"
name="${bundle.name}"
displayname="${bundle.displayname}"
executableName="MyApp"
identifier="com.company.product"
shortversion="${version.public}"
version="${version.internal}"
icon="${icons.path}/${bundle.icns}"
mainclassname="mymodule/org.company.MainClass"
copyright="2019 Your Company"
applicationCategory="public.app-category.finance">

<jlink runtime="${runtime}">
<jmod name="java.base"/>
<jmod name="java.desktop"/>

<!-- Zip the generated modules file (Optional) -->
<argument value="--compress=2"/>

<!-- Preserve all release properties, but update the modules
- list. (Optional)
-
- See https://bugs.openjdk.java.net/browse/JDK-8179563
-->
<argument value="--release-info=${runtime}/release"/>
</jlink>
</bundleapp>
</target>
13 changes: 11 additions & 2 deletions appbundler/native/main.m
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,9 @@ int launch(char *commandName, int progargc, char *progargv[]) {
// Get the main class name
NSString *mainClassName = [infoDictionary objectForKey:@JVM_MAIN_CLASS_NAME_KEY];

if ( jnlplauncher != nil ) {
bool runningModule = [mainClassName containsString:@"/"];

if ( jnlplauncher != nil && !runningModule ) {

const_appclasspath = [[runtimePath stringByAppendingPathComponent:@DEPLOY_LIB] fileSystemRepresentation];

Expand Down Expand Up @@ -571,6 +573,9 @@ int launch(char *commandName, int progargc, char *progargv[]) {
// Initialize the arguments to JLI_Launch()
// +5 due to the special directories and the sandbox enabled property
int argc = 1 + [systemArguments count] + [options count] + [defaultOptions count] + 1 + [arguments count] + newProgargc;
if (runningModule)
argc++;

char *argv[argc];

int i = 0;
Expand All @@ -592,7 +597,11 @@ int launch(char *commandName, int progargc, char *progargv[]) {
if (isDebugging) { DLog(@"DefaultOption: %@",defaultOption); }
}

argv[i++] = strdup([mainClassName UTF8String]);
if (runningModule) {
argv[i++] = "-m";
argv[i++] = strdup([mainClassName UTF8String]);
} else
argv[i++] = strdup([mainClassName UTF8String]);

for (NSString *argument in arguments) {
argument = [argument stringByReplacingOccurrencesOfString:@APP_ROOT_PREFIX withString:[mainBundle bundlePath]];
Expand Down
22 changes: 22 additions & 0 deletions appbundler/src/com/oracle/appbundler/AppBundlerTask.java
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ public class AppBundlerTask extends Task {
private String jnlpLauncherName = null;
private String jarLauncherName = null;
private Runtime runtime = null;
private JLink jlink = null;
private ArrayList<FileSet> classPath = new ArrayList<>();
private ArrayList<FileSet> libraryPath = new ArrayList<>();
private ArrayList<Option> options = new ArrayList<>();
Expand Down Expand Up @@ -230,9 +231,26 @@ public void addConfiguredRuntime(Runtime runtime) throws BuildException {
throw new BuildException("Runtime already specified.");
}

if (this.jlink != null) {
throw new BuildException("Cannot specify runtime and jlink together.");
}

this.runtime = runtime;
}

public void addConfiguredJLink(JLink jlink) throws BuildException {
if (this.jlink != null) {
throw new BuildException("JLink already specified.");
}

if (this.runtime != null) {
throw new BuildException("Cannot specify runtime and jlink together.");
}

jlink.setTask(this);
this.jlink = jlink;
}

public void setClasspathRef(Reference ref) {

this.classPathRef = ref;
Expand Down Expand Up @@ -499,6 +517,8 @@ private void copyResources(File resourcesDirectory) throws IOException {
private void copyRuntime(File plugInsDirectory) throws IOException {
if (runtime != null) {
runtime.copyTo(plugInsDirectory);
} else if (jlink != null) {
jlink.copyTo(plugInsDirectory);
}
}

Expand Down Expand Up @@ -640,6 +660,8 @@ private void writeInfoPlist(File file) throws IOException {
// Write runtime
if (runtime != null) {
writeProperty(xout, "JVMRuntime", runtime.getDir().getParentFile().getParentFile().getName());
} else if (jlink != null) {
writeProperty(xout, "JVMRuntime", jlink.getDir().getParentFile().getParentFile().getName());
}

if(jvmRequired != null) {
Expand Down
140 changes: 140 additions & 0 deletions appbundler/src/com/oracle/appbundler/JLink.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
/*
* Copyright 2019, ATTO Technology, Inc. All rights reserved.
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. ATTO Technology designates this
* particular file as subject to the "Classpath" exception as provided
* by ATTO Technology in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/

package com.oracle.appbundler;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.taskdefs.ExecTask;

/**
* Class representing a module that will be passed to jlink to build the bundled
* JVM.
*/
public class JLink {
private String runtime = null;
private ArrayList<String> jmods = new ArrayList<>();
private ArrayList<String> arguments = new ArrayList<>();
private ExecTask exec = new ExecTask();

public JLink() {
exec.init();
}

public String getRuntime() {
return runtime;
}

public void setRuntime(String runtime) {
this.runtime = runtime;
}

public void setTask(AppBundlerTask task) {
exec.bindToOwner(task);
}

/* Provide canonical path so that runtime can be specified via a
* version-agnostic path (relative link, e.g. `current-jre`) while
* still preserving the original runtime directory name, e.g.
* `jre1.8.0_45.jre`.
*/
public File getDir() {
File dir = new File(runtime);
try {
return dir.getCanonicalFile();
} catch (IOException e) {
return dir;
}
}

public void addConfiguredJMod(JMod jmod) throws BuildException {
String name = jmod.getName();

if (name == null) {
throw new BuildException("Name is required.");
}

jmods.add(name);
}

public void addConfiguredArgument(Argument argument) throws BuildException {
String value = argument.getValue();

if (value == null) {
throw new BuildException("Value is required.");
}

arguments.add(value);
}

public void copyTo(File targetDir) throws IOException {
File runtimeHomeDirectory = getDir();
File runtimeContentsDirectory = runtimeHomeDirectory.getParentFile();
File runtimeDirectory = runtimeContentsDirectory.getParentFile();

// Create root plug-in directory
File pluginDirectory = new File(targetDir, runtimeDirectory.getName());
pluginDirectory.mkdir();

// Create Contents directory
File pluginContentsDirectory = new File(pluginDirectory, runtimeContentsDirectory.getName());
pluginContentsDirectory.mkdir();

// Copy MacOS directory
File runtimeMacOSDirectory = new File(runtimeContentsDirectory, "MacOS");
AppBundlerTask.copy(runtimeMacOSDirectory, new File(pluginContentsDirectory, runtimeMacOSDirectory.getName()));


// Copy Info.plist file
File runtimeInfoPlistFile = new File(runtimeContentsDirectory, "Info.plist");
AppBundlerTask.copy(runtimeInfoPlistFile, new File(pluginContentsDirectory, runtimeInfoPlistFile.getName()));

// Copy included contents of Home directory
File pluginHomeDirectory = new File(pluginContentsDirectory, runtimeHomeDirectory.getName());

exec.setExecutable(runtimeHomeDirectory.getAbsolutePath() + "/bin/jlink");
exec.setFailIfExecutionFails(true);
exec.setFailonerror(true);
for(String s : this.arguments) {
exec.createArg().setValue(s);
}

exec.createArg().setValue("--no-man-pages");
exec.createArg().setValue("--no-header-files");
exec.createArg().setValue("--strip-native-commands"); /* no bin directory */
exec.createArg().setValue("--add-modules");
exec.createArg().setValue(String.join(",", jmods));
exec.createArg().setValue("--output");
exec.createArg().setValue(pluginHomeDirectory.getAbsolutePath());

exec.execute();
}

@Override
public String toString() {
return runtime;
}
}
45 changes: 45 additions & 0 deletions appbundler/src/com/oracle/appbundler/JMod.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright 2019, ATTO Technology, Inc. All rights reserved.
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. ATTO Technology designates this
* particular file as subject to the "Classpath" exception as provided
* by ATTO Technology in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/

package com.oracle.appbundler;

/**
* Class representing a module that will be passed to jlink to build the bundled
* JVM.
*/
public class JMod {
private String name = null;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

@Override
public String toString() {
return name;
}
}
1 change: 1 addition & 0 deletions build.xml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ questions.
includejavaruntime="true"
includeantruntime="true"
target="1.8"
source="1.8"
deprecation="true"
debug="true"
encoding="UTF-8"
Expand Down

0 comments on commit 7e624ce

Please sign in to comment.