Compare commits

...

4 commits

Author SHA1 Message Date
Dan Fox
c2db9f6076 Restore method 2018-10-08 12:16:37 +01:00
Dan Fox
a5f4803777 Move configuration to top level GradleGraalPlugin 2018-10-07 21:14:53 -04:00
Dan Fox
1a7ea17eb4 ReflectionConfigTask creates JSON files 2018-10-07 21:07:04 -04:00
Dan Fox
3f6aae13a8 Options work 2018-10-07 21:02:46 -04:00
5 changed files with 220 additions and 8 deletions

View file

@ -76,6 +76,17 @@ public class GradleGraalPlugin implements Plugin<Project> {
task.dependsOn(downloadGraal);
});
TaskProvider<ReflectionConfigTask> reflectionConfig = project.getTasks().register(
"reflectionConfig",
ReflectionConfigTask.class,
task -> {
task.add("java.util.ArrayList");
task.add("java.util.Optional");
task.setFile(project.getLayout().getBuildDirectory()
.dir("graal")
.map(d -> d.file("reflectconfig.json")));
});
TaskProvider<Jar> jar = project.getTasks().withType(Jar.class).named("jar");
project.getTasks().register(
"nativeImage",
@ -87,8 +98,12 @@ public class GradleGraalPlugin implements Plugin<Project> {
task.setJarFile(jar.map(j -> j.getOutputs().getFiles().getSingleFile()));
task.setClasspath(project.getConfigurations().named("runtimeClasspath"));
task.setCacheDir(cacheDir);
task.option(reflectionConfig.get().getOutputJsonFile()
.map(file -> "-H:ReflectionConfigurationFiles=" + file));
task.dependsOn(extractGraal);
task.dependsOn(jar);
task.dependsOn(reflectionConfig);
});
}
}

View file

@ -0,0 +1,71 @@
/*
* (c) Copyright 2018 Palantir Technologies Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.palantir.gradle.graal;
import static java.util.stream.Collectors.toList;
import java.io.Serializable;
import java.util.List;
import java.util.stream.Stream;
import org.gradle.api.Project;
import org.gradle.api.provider.ListProperty;
import org.gradle.api.provider.Provider;
/**
* See substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java in
* https://github.com/oracle/graal/.
*/
public final class NativeImageOptions implements Serializable {
private static final long serialVersionUID = 9307652985066589L;
// using Object to represent String | Provider<String>
private final ListProperty<Object> list;
public NativeImageOptions(Project project) {
list = project.getObjects().listProperty(Object.class);
}
public List<String> get() {
return getProvider().get();
}
public void set(String option) {
list.add(option);
}
public void set(Provider<String> option) {
list.add(option);
}
// TODO(dfox): make the incremental behaviour here understand when a file has changed or not
public Provider<List<String>> getProvider() {
return list.map(providers -> providers.stream().flatMap(object -> {
if (object instanceof Provider) {
Provider provider = (Provider) object;
return provider.isPresent() ? Stream.of((String) provider.get()) : Stream.empty();
}
if (object instanceof String) {
return Stream.of((String) object);
}
throw new IllegalStateException("list elements must be either String or Provider<String>, was: " + object);
}).collect(toList()));
}
}

View file

@ -49,6 +49,8 @@ public class NativeImageTask extends DefaultTask {
private final RegularFileProperty jarFile = newInputFile();
private final RegularFileProperty outputFile = newOutputFile();
private final Property<Path> cacheDir = getProject().getObjects().property(Path.class);
private final NativeImageOptions options = new NativeImageOptions(getProject());
public NativeImageTask() {
setGroup(GradleGraalPlugin.TASK_GROUP);
@ -58,6 +60,9 @@ public class NativeImageTask extends DefaultTask {
.dir("graal")
.map(d -> d.file(outputName.get())));
options.set(outputName.map(string -> "-H:Name=" + string));
options.set(maybeCreateOutputDirectory(outputFile).map(string -> "-H:Path=" + string));
doLast(t -> {
getLogger().warn("native-image available at {} ({}MB)",
getProject().relativePath(outputFile.get().getAsFile()),
@ -70,10 +75,7 @@ public class NativeImageTask extends DefaultTask {
List<String> args = new ArrayList<>();
args.add("-cp");
args.add(generateClasspathArgument());
args.add("-H:Path=" + maybeCreateOutputDirectory().getAbsolutePath());
if (outputName.isPresent()) {
args.add("-H:Name=" + outputName.get());
}
args.addAll(options.get());
args.add(mainClass.get());
getProject().exec(spec -> {
@ -82,10 +84,17 @@ public class NativeImageTask extends DefaultTask {
});
}
private File maybeCreateOutputDirectory() throws IOException {
File directory = getOutputFile().get().getAsFile().getParentFile();
private static Provider<String> maybeCreateOutputDirectory(Provider<RegularFile> output) {
return output.map(o -> {
try {
File directory = o.getAsFile().getParentFile();
Files.createDirectories(directory.toPath());
return directory;
String absolutePath = directory.getAbsolutePath();
return absolutePath;
} catch (Exception e) {
throw new RuntimeException(e);
}
});
}
private String getExecutable() {
@ -164,6 +173,19 @@ public class NativeImageTask extends DefaultTask {
jarFile.set(getProject().getLayout().file(provider));
}
@Input
public final Provider<List<String>> getOptions() {
return options.getProvider();
}
public final void option(String string) {
this.options.set(string);
}
public final void option(Provider<String> string) {
this.options.set(string);
}
@OutputFile
public final Provider<RegularFile> getOutputFile() {
return outputFile;

View file

@ -0,0 +1,100 @@
/*
* (c) Copyright 2018 Palantir Technologies Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.palantir.gradle.graal;
import static java.util.stream.Collectors.toList;
import groovy.json.JsonOutput;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.gradle.api.DefaultTask;
import org.gradle.api.file.RegularFile;
import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.provider.ListProperty;
import org.gradle.api.provider.Provider;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.OutputFile;
import org.gradle.api.tasks.TaskAction;
// TODO(dfox): make this read files containing class names
public class ReflectionConfigTask extends DefaultTask {
private final RegularFileProperty file = newOutputFile();
private final ListProperty<String> classes = getProject().getObjects().listProperty(String.class);
public ReflectionConfigTask() {
setGroup(GradleGraalPlugin.TASK_GROUP);
setDescription("Generates a reflectconfig.json file based on supplied class names");
onlyIf(t -> classes.isPresent() && !classes.get().isEmpty());
}
@TaskAction
public final void generateFile() throws IOException {
List<Map<String, Object>> json = classes.get().stream()
.map(clazz -> {
Map<String, Object> map = new LinkedHashMap<>();
map.put("name", clazz);
map.put("allDeclaredConstructors", true);
map.put("allPublicConstructors", true);
map.put("allDeclaredMethods", true);
map.put("allPublicMethods", true);
map.put("allDeclaredFields", true);
map.put("allPublicFields", true);
return map;
})
.collect(toList());
String string = JsonOutput.prettyPrint(JsonOutput.toJson(json));
Files.write(file.get().getAsFile().toPath(), string.getBytes(StandardCharsets.UTF_8));
}
@Input
public final Provider<List<String>> getClasses() {
return classes;
}
@OutputFile
public final RegularFileProperty getOutputJsonFile() {
return file;
}
public final void setFile(File value) {
file.set(value);
}
public final void setFile(Provider<RegularFile> regularFileProvider) {
file.set(regularFileProvider);
}
public final void add(String string) {
classes.add(string);
}
public final void add(Provider<String> value) {
classes.add(value);
}
public final void addAll(String... strings) {
classes.addAll(strings);
}
}

View file

@ -42,6 +42,10 @@ class GradleGraalEndToEndSpec extends IntegrationSpec {
outputName 'hello-world'
graalVersion '1.0.0-rc5'
}
nativeImage {
option '-H:Optimize=1'
}
'''
when: