Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for @arg file #205

Merged
merged 1 commit into from Feb 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -42,8 +42,12 @@

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.Collections;
import java.util.List;

import static org.graalvm.buildtools.utils.SharedConstants.GRAALVM_EXE_EXTENSION;

Expand All @@ -66,4 +70,16 @@ public static void maybeCreateConfigureUtilSymlink(File configureUtilFile, Path
public static String nativeImageConfigureFileName() {
return "native-image-configure" + GRAALVM_EXE_EXTENSION;
}

public static List<String> convertToArgsFile(List<String> cliArgs) {
try {
File tmpFile = File.createTempFile("native-image", "args");
tmpFile.deleteOnExit();
Files.write(tmpFile.toPath(), cliArgs, StandardCharsets.UTF_8, StandardOpenOption.CREATE);
return Collections.singletonList("@" + tmpFile.getAbsolutePath());
} catch (IOException e) {

return Collections.unmodifiableList(cliArgs);
}
}
}
16 changes: 7 additions & 9 deletions docs/src/docs/asciidoc/gradle-plugin.adoc
Expand Up @@ -174,27 +174,25 @@ include::../snippets/gradle/kotlin/build.gradle.kts[tags=all-config-options]
NOTE: For options that can be set using command-line, if both DSL and command-line options are present, command-line options take precedence.

[[long_classpath_and_fat_jar_support]]
==== Long classpath and fat jar support
==== Long classpath, @argument file and fat jar support

Under Windows, https://github.com/graalvm/native-build-tools/issues/85[it is possible that the length of the classpath exceeds what the operating system supports] when invoking the CLI to build a native image.
As a consequence, if you are running under Windows, the plugin will automatically shorten the classpath of your project by building a so called "fat jar", which includes all entries from the classpath automatically.
Since release 0.9.10, the plugin will automatically pass arguments to the `native-image` tool using an argument file, which should prevent all https://github.com/graalvm/native-build-tools/issues/85[long classpath issues] under Windows.
However, if you are using an older GraalVM release (older than 21.3) which doesn't support argument files, you will need to rely on creating a "fat jar", which includes all entries from the classpath automatically, to workaround the problem:

In case this behavior is not required, you can disable the fat jar creation by calling:

.Disabling the fat jar creation
.Enabling the fat jar creation
[source, groovy, role="multi-language-sample"]
----
include::../snippets/gradle/groovy/build.gradle[tags=disable-fatjar]
include::../snippets/gradle/groovy/build.gradle[tags=enable-fatjar]
----

[source,kotlin,role="multi-language-sample"]
----
include::../snippets/gradle/kotlin/build.gradle.kts[tags=disable-fatjar]
include::../snippets/gradle/kotlin/build.gradle.kts[tags=enable-fatjar]
----

Alternatively, it is possible to use your own fat jar (for example created using the https://imperceptiblethoughts.com/shadow/[Shadow plugin]) by setting the `classpathJar` property directly on the _task_:

.Disabling the fat jar creation
.Enabling a custom fat jar creation
[source, groovy, role="multi-language-sample"]
----
include::../snippets/gradle/groovy/build.gradle[tags=custom-fatjar]
Expand Down
2 changes: 2 additions & 0 deletions docs/src/docs/asciidoc/index.adoc
Expand Up @@ -24,11 +24,13 @@ If you are interested in contributing, please refer to our https://github.com/gr
* Fixed race condition which prevented the agent files to be generated properly if tests were executed concurrently
* Documented version compatibility for the JUnit Platform and Maven Surefire plugin.
- See <<maven-plugin.adoc#testing-support-version-compatibility, Version compatibility>> for details.
* Add support for long classpath by using an argument file when invoking `native-image`

==== Gradle plugin

* Fixed `nativeRun` not working properly under Windows
* Fixed race condition which prevented the agent files to be generated properly if tests were executed concurrently
* Add support for long classpath by using an argument file when invoking `native-image`

=== Release 0.9.9

Expand Down
8 changes: 6 additions & 2 deletions docs/src/docs/asciidoc/maven-plugin.adoc
Expand Up @@ -258,11 +258,15 @@ use cases such as the following:
wish to run those same tests in native mode.

[[long_classpath_and_shading_support]]
== Long classpath and shading support
== Long classpath, @argument file and shading support

Under Windows, https://github.com/graalvm/native-build-tools/issues/85[it is possible that the length of the classpath exceeds what the operating system supports] when invoking the CLI to build a native image.

If this happens, one option is to use a https://maven.apache.org/plugins/maven-shade-plugin[shaded jar] and use it instead of individual jars on classpath.
To avoid this, since release 0.9.10, the plugin will use an argument file to pass the arguments to the `native-image` tool, instead of passing them directly.

In case you are using a GraalVM version older than 21.3, you will however have to use a workaround, since the argument file wasn't supported.

One option is to use a https://maven.apache.org/plugins/maven-shade-plugin[shaded jar] and use it instead of individual jars on classpath.

First, you'll need to setup the https://maven.apache.org/plugins/maven-shade-plugin[Maven Shade plugin]:

Expand Down
7 changes: 4 additions & 3 deletions docs/src/docs/snippets/gradle/groovy/build.gradle
Expand Up @@ -98,15 +98,16 @@ graalvmNative {
}
// end::all-config-options[]

// tag::disable-fatjar[]
// tag::enable-fatjar[]
graalvmNative {
useArgFile = false // required for older GraalVM releases
binaries {
main {
useFatJar = false
useFatJar = true
}
}
}
// end::disable-fatjar[]
// end::enable-fatjar[]

def myFatJar = tasks.register("myFatJar", Jar)

Expand Down
7 changes: 4 additions & 3 deletions docs/src/docs/snippets/gradle/kotlin/build.gradle.kts
Expand Up @@ -99,15 +99,16 @@ graalvmNative {
}
// end::all-config-options[]

// tag::disable-fatjar[]
// tag::enable-fatjar[]
graalvmNative {
useFatJar.set(false) // required for older GraalVM releases
binaries {
named("main") {
useFatJar.set(false)
useFatJar.set(true)
}
}
}
// end::disable-fatjar[]
// end::enable-fatjar[]

val myFatJar = tasks.register<Jar>("myFatJar")

Expand Down
Expand Up @@ -171,6 +171,7 @@ public void apply(Project project) {

logger = GraalVMLogger.of(project.getLogger());
DefaultGraalVmExtension graalExtension = (DefaultGraalVmExtension) registerGraalVMExtension(project);
graalExtension.getUseArgFile().convention(true);
project.getPlugins()
.withType(JavaPlugin.class, javaPlugin -> configureJavaProject(project, nativeImageServiceProvider, graalExtension));
project.afterEvaluate(p -> {
Expand Down Expand Up @@ -253,6 +254,7 @@ private void configureAutomaticTaskCreation(Project project,
builder.setGroup(LifecycleBasePlugin.BUILD_GROUP);
builder.getOptions().convention(options);
builder.getAgentEnabled().set(agent);
builder.getUseArgFile().convention(graalExtension.getUseArgFile());
});
String runTaskName = deriveTaskName(binaryName, "native", "Run");
if ("main".equals(binaryName)) {
Expand Down
Expand Up @@ -90,6 +90,14 @@ public interface GraalVMExtension {
*/
Property<Boolean> getToolchainDetection();

/**
* Property driving the use of @-arg files when invoking native image.
* This is enabled by default. For older native-image versions, this
* needs to be disabled.
* @return the argument file property
*/
Property<Boolean> getUseArgFile();


interface TestBinaryConfig {
/**
Expand Down
Expand Up @@ -43,7 +43,6 @@

import org.graalvm.buildtools.gradle.dsl.NativeImageOptions;
import org.graalvm.buildtools.gradle.dsl.NativeResourcesOptions;
import org.graalvm.buildtools.utils.SharedConstants;
import org.gradle.api.Action;
import org.gradle.api.file.ConfigurableFileCollection;
import org.gradle.api.model.ObjectFactory;
Expand Down Expand Up @@ -215,7 +214,7 @@ public BaseNativeImageOptions(String name,
getAgent().getEnabled().convention(false);
getSharedLibrary().convention(false);
getImageName().convention(defaultImageName);
getUseFatJar().convention(SharedConstants.IS_WINDOWS);
getUseFatJar().convention(false);
}

private static Provider<Boolean> property(ProviderFactory providers, String name) {
Expand Down
Expand Up @@ -42,6 +42,7 @@
package org.graalvm.buildtools.gradle.internal;

import org.graalvm.buildtools.gradle.dsl.NativeImageOptions;
import org.graalvm.buildtools.utils.NativeImageUtils;
import org.gradle.api.Transformer;
import org.gradle.api.file.FileSystemLocation;
import org.gradle.api.file.RegularFile;
Expand All @@ -65,17 +66,20 @@ public class NativeImageCommandLineProvider implements CommandLineArgumentProvid
private final Provider<String> executableName;
private final Provider<String> outputDirectory;
private final Provider<RegularFile> classpathJar;
private final Provider<Boolean> useArgFile;

public NativeImageCommandLineProvider(Provider<NativeImageOptions> options,
Provider<Boolean> agentEnabled,
Provider<String> executableName,
Provider<String> outputDirectory,
Provider<RegularFile> classpathJar) {
Provider<RegularFile> classpathJar,
Provider<Boolean> useArgFile) {
this.options = options;
this.agentEnabled = agentEnabled;
this.executableName = executableName;
this.outputDirectory = outputDirectory;
this.classpathJar = classpathJar;
this.useArgFile = useArgFile;
}

@Nested
Expand Down Expand Up @@ -145,7 +149,11 @@ public List<String> asArguments() {
cliArgs.add("-H:Class=" + options.getMainClass().get());
}
cliArgs.addAll(options.getBuildArgs().get());
if (useArgFile.getOrElse(true)) {
return NativeImageUtils.convertToArgsFile(cliArgs);
}
return Collections.unmodifiableList(cliArgs);

}

/**
Expand Down
Expand Up @@ -133,6 +133,10 @@ public Provider<RegularFile> getOutputFile() {
@Optional
public abstract RegularFileProperty getClasspathJar();

@Input
@Optional
public abstract Property<Boolean> getUseArgFile();

public BuildNativeImageTask() {
DirectoryProperty buildDir = getProject().getLayout().getBuildDirectory();
Provider<Directory> outputDir = buildDir.dir("native/" + getName());
Expand All @@ -154,7 +158,8 @@ private List<String> buildActualCommandLineArgs() {
// Can't use getOutputDirectory().map(...) because Gradle would complain that we use
// a mapped value before the task was called, when we are actually calling it...
getProviders().provider(() -> getOutputDirectory().getAsFile().get().getAbsolutePath()),
getClasspathJar()).asArguments();
getClasspathJar(),
getUseArgFile()).asArguments();
}

// This property provides access to the service instance
Expand Down
Expand Up @@ -57,7 +57,7 @@ class JavaLibraryFunctionalTest extends AbstractGraalVMMavenFunctionalTest {
def library = file("target/java-library" + libExt)

when:
mvn '-Pnative', '-DskipTests', 'package'
mvn '-Pnative', '-DskipTests', 'package', '-DuseArgFile=false'

then:
buildSucceeded
Expand Down
Expand Up @@ -55,6 +55,7 @@
import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
import org.codehaus.plexus.util.xml.Xpp3Dom;
import org.graalvm.buildtools.Utils;
import org.graalvm.buildtools.utils.NativeImageUtils;

import java.io.File;
import java.io.IOException;
Expand Down Expand Up @@ -98,6 +99,9 @@ public class NativeBuildMojo extends AbstractNativeMojo {
@Parameter(property = "classpath")
private List<String> classpath;

@Parameter(property = "useArgFile", defaultValue = "true")
private boolean useArgFile;

private final List<Path> imageClasspath = new ArrayList<>();

private PluginParameterExpressionEvaluator evaluator;
Expand Down Expand Up @@ -128,8 +132,15 @@ public void execute() throws MojoExecutionException {
maybeAddGeneratedResourcesConfig(buildArgs);

try {
ProcessBuilder processBuilder = new ProcessBuilder(nativeImageExecutable.toString(), "-cp", classpathStr);
processBuilder.command().addAll(getBuildArgs());
List<String> cliArgs = new ArrayList<>();
cliArgs.add("-cp");
cliArgs.add(classpathStr);
cliArgs.addAll(getBuildArgs());
if (useArgFile) {
cliArgs = NativeImageUtils.convertToArgsFile(cliArgs);
}
ProcessBuilder processBuilder = new ProcessBuilder(nativeImageExecutable.toString());
processBuilder.command().addAll(cliArgs);
processBuilder.directory(getWorkingDirectory().toFile());
processBuilder.inheritIO();

Expand Down
1 change: 1 addition & 0 deletions samples/java-application-with-tests/pom.xml
Expand Up @@ -205,6 +205,7 @@
</executions>
<configuration>
<skip>false</skip>
<useArgFile>false</useArgFile>
<imageName>${imageName}</imageName>
<buildArgs>
<buildArg>--no-fallback</buildArg>
Expand Down
1 change: 1 addition & 0 deletions samples/java-application/pom.xml
Expand Up @@ -127,6 +127,7 @@
</executions>
<configuration>
<skip>false</skip>
<useArgFile>false</useArgFile>
<imageName>${imageName}</imageName>
<buildArgs>
<buildArg>--no-fallback</buildArg>
Expand Down