Skip to content

Commit 90cbfe3

Browse files
committed
[GR-64145] Various Layer{Create,Use} option fixes.
PullRequest: graal/20529
2 parents 72c4ce0 + dc241e9 commit 90cbfe3

File tree

11 files changed

+160
-85
lines changed

11 files changed

+160
-85
lines changed

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/BuildArtifacts.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ enum ArtifactType {
4444
EXECUTABLE("executables"),
4545
/* Native image layer. */
4646
IMAGE_LAYER("image_layer"),
47+
/* Native image layer bundle. */
48+
IMAGE_LAYER_BUNDLE("image_layer_bundle"),
4749
/* For all shared libraries that are not JDK-related and needed at run-time. */
4850
SHARED_LIBRARY("shared_libraries"),
4951

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434

3535
import java.nio.file.InvalidPathException;
3636
import java.nio.file.Path;
37-
import java.nio.file.Paths;
3837
import java.util.List;
3938
import java.util.UUID;
4039
import java.util.function.Predicate;
@@ -44,6 +43,7 @@
4443
import org.graalvm.nativeimage.ImageInfo;
4544
import org.graalvm.nativeimage.ImageSingletons;
4645
import org.graalvm.nativeimage.Platform;
46+
import org.graalvm.nativeimage.Platform.HOSTED_ONLY;
4747
import org.graalvm.nativeimage.Platforms;
4848

4949
import com.oracle.svm.core.c.libc.LibCBase;
@@ -64,6 +64,7 @@
6464
import com.oracle.svm.core.option.SubstrateOptionsParser;
6565
import com.oracle.svm.core.thread.VMOperationControl;
6666
import com.oracle.svm.core.util.UserError;
67+
import com.oracle.svm.core.util.VMError;
6768
import com.oracle.svm.util.LogUtils;
6869
import com.oracle.svm.util.ModuleSupport;
6970
import com.oracle.svm.util.ReflectionUtil;
@@ -493,9 +494,19 @@ public static void setImageLayerCreateEnabledHandler(OptionEnabledHandler<Boolea
493494
@Option(help = "Path passed to the linker as the -rpath (list of comma-separated directories)")//
494495
public static final HostedOptionKey<AccumulatingLocatableMultiOptionValue.Strings> LinkerRPath = new HostedOptionKey<>(AccumulatingLocatableMultiOptionValue.Strings.buildWithCommaDelimiter());
495496

496-
@OptionMigrationMessage("Use the '-o' option instead.")//
497-
@Option(help = "Directory of the image file to be generated", type = OptionType.User)//
498-
public static final HostedOptionKey<String> Path = new HostedOptionKey<>(null);
497+
@Platforms(HOSTED_ONLY.class)
498+
public static Path getImagePath(OptionValues optionValues) {
499+
VMError.guarantee(optionValues != null);
500+
if (!ConcealedOptions.Path.hasBeenSet(optionValues)) {
501+
VMError.shouldNotReachHere("Image builder requires %s", SubstrateOptionsParser.commandArgument(ConcealedOptions.Path, "<builder output directory>"));
502+
}
503+
return Path.of(ConcealedOptions.Path.getValue(optionValues));
504+
}
505+
506+
@Platforms(HOSTED_ONLY.class)
507+
public static Path getImagePath() {
508+
return getImagePath(HostedOptionValues.singleton());
509+
}
499510

500511
public static final class GCGroup implements APIOptionGroup {
501512
@Override
@@ -1025,9 +1036,10 @@ public static boolean useDebugInfoGeneration() {
10251036
@Option(help = "Temporary option to disable checking of image builder module dependencies or increasing its verbosity", type = OptionType.Debug)//
10261037
public static final HostedOptionKey<Integer> CheckBootModuleDependencies = new HostedOptionKey<>(ModuleSupport.modulePathBuild ? 1 : 0);
10271038

1039+
@Platforms(HOSTED_ONLY.class)
10281040
public static Path getDebugInfoSourceCacheRoot() {
10291041
try {
1030-
return Paths.get(Path.getValue()).resolve(DebugInfoSourceCacheRoot.getValue());
1042+
return SubstrateOptions.getImagePath().resolve(DebugInfoSourceCacheRoot.getValue());
10311043
} catch (InvalidPathException ipe) {
10321044
throw UserError.invalidOptionValue(DebugInfoSourceCacheRoot, DebugInfoSourceCacheRoot.getValue(), "The path is invalid");
10331045
}
@@ -1144,6 +1156,10 @@ protected void onValueUpdate(EconomicMap<OptionKey<?>, Object> values, Integer o
11441156
/** Use {@link SubstrateOptions#codeAlignment()} instead. */
11451157
@Option(help = "Alignment of AOT and JIT compiled code in bytes. The default of 0 automatically selects a suitable value.")//
11461158
public static final HostedOptionKey<Integer> CodeAlignment = new HostedOptionKey<>(0);
1159+
1160+
@OptionMigrationMessage("Use the '-o' option instead.")//
1161+
@Option(help = "Directory of the image file to be generated", type = OptionType.User)//
1162+
public static final HostedOptionKey<String> Path = new HostedOptionKey<>(null);
11471163
}
11481164

11491165
@Fold
@@ -1205,12 +1221,13 @@ public Boolean getValue(OptionValues values) {
12051221
@Option(help = "file:doc-files/FlightRecorderOptionsHelp.txt")//
12061222
public static final RuntimeOptionKey<String> FlightRecorderOptions = new RuntimeOptionKey<>("", Immutable);
12071223

1224+
@Platforms(HOSTED_ONLY.class)
12081225
public static String reportsPath() {
12091226
Path reportsPath = ImageSingletons.lookup(ReportingSupport.class).reportsPath;
12101227
if (reportsPath.isAbsolute()) {
12111228
return reportsPath.toString();
12121229
}
1213-
return Paths.get(Path.getValue()).resolve(reportsPath).toString();
1230+
return getImagePath().resolve(reportsPath).toString();
12141231
}
12151232

12161233
public static class ReportingSupport {

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/imagelayer/NativeImageLayers.md

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,11 @@ base-layer.so # initial layer (includes VM/JDK code)
6363
6464
To create and use layers `native-image` accepts two options: `--layer-create` and `--layer-use`.
6565

66-
First, `--layer-create` builds an image layer archive from code available on the class or module path:
66+
### Option `--layer-create` builds an image layer archive from code available on the class or module path:
6767

6868
```
69-
--layer-create=[layer-file.nil][,module=<module-name>][,package=<package-name>]
70-
builds an image layer file from the modules and packages specified by "module" and "package".
69+
--layer-create=[layer-file.nil][,module=<module-name>][,package=<package-name>][,path=<classpath-entry>]
70+
builds an image layer file from the modules and packages specified by "module" and "package" or "path".
7171
The file name, if specified, must be a simple file name, i.e., not contain any path separators,
7272
and have the *.nil extension. Otherwise, the layer-file name is derived from the image name.
7373
This will generate a Native Image Layer archive file containing metadata required to build
@@ -78,7 +78,58 @@ First, `--layer-create` builds an image layer archive from code available on the
7878

7979
A layer archive file has a _.nil_ extension, acronym for **N**ative **I**mage **L**ayer.
8080

81-
Second, `--layer-use` consumes a shared layer, and can extend it or create a final executable:
81+
#### `--layer-create` suboptions
82+
83+
The **module** and **package** and **path** suboptions of `--layer-create` are used to specify the classes and resources that should be included in the layer.
84+
Within a `--layer-create` option argument, these suboption arguments can be specified multiple times, for example:
85+
```
86+
--layer-create=base-layer.nil,package=ch.qos.logback.core.hook,package=ch.qos.logback.core.html,...
87+
```
88+
89+
##### `--layer-create` suboption `module=<module-name>`
90+
91+
With this suboption, layer creation is instructed to make all packages and all resources that are part of the given module included in the layer.
92+
In the future we will eventually provide a solution to refine the resource inclusion for the module suboption to allow fine-grained control over the included resources.
93+
94+
##### `--layer-create` suboption `package=<package-name>`
95+
96+
Suboption `package` allows the inclusion of individual Java packages. For this kind of inclusion it does not matter if the specified package is from a classpath-entry or part of a module, both are supported.
97+
Contrary to the `module` suboption, resources are not also automatically included. If resource inclusion is needed, the usual ways can be used (`resource-config.json`, `reachability-metadata.json` or resource related Feature API).
98+
99+
##### `--layer-create` suboption `path=<classpath entry>`
100+
101+
This is a convenience suboption that requires a `classpath entry`.
102+
If the provided entry is not also specified in the classpath of the given `native-image` invocation, an error message is shown.
103+
All classes and all resources from the given classpath entry are included in the layer. Note that using this suboption might lead to larger than necessary layers. Only use this suboption for uses-cases where this is not an issue.
104+
105+
#### `--layer-create` option argument file
106+
107+
For complex use-cases, the `--layer-create` option argument can become very large.
108+
To make this more manageable it is possible to have the `--layer-create` option argument specified via a separate file where each line corresponds to an entry of the option argument.
109+
110+
This currently only works if the `--layer-create` option is specified from a `native-image.properties` file in a `META-INF/native-image` subdirectory.
111+
If this requirement is met, the following can be used:
112+
```properties
113+
Args = --layer-create[email protected]
114+
```
115+
The `layer-create.args` file-path is relative to the directory that contains the `native-image.properties` file and might look like this:
116+
```
117+
base-layer.nil
118+
module=java.base
119+
# micronaut and dependencies
120+
package=io.micronaut.*
121+
package=io.netty.*
122+
package=jakarta.*
123+
package=com.fasterxml.jackson.*
124+
package=org.slf4j.*
125+
# io.projectreactor:reactor-core and dependencies
126+
package=reactor.*
127+
package=org.reactivestreams.*
128+
```
129+
Each line corresponds to one entry in the list of comma-separated entries that can usually be found in a regular `--layer-create` argument.
130+
Lines starting with `#` are ignored and can therefore be used to provide comments in such an option argument file.
131+
132+
### Option `--layer-use` consumes a shared layer, and can extend it or create a final executable:
82133

83134
```
84135
--layer-use=layer-file.nil

substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ private static <T> String oR(OptionKey<T> option) {
267267
final String oHModule = oH(SubstrateOptions.Module);
268268
final String oHClass = oH(SubstrateOptions.Class);
269269
final String oHName = oH(SubstrateOptions.Name);
270-
final String oHPath = oH(SubstrateOptions.Path);
270+
final String oHPath = oH(SubstrateOptions.ConcealedOptions.Path);
271271
final String oHUseLibC = oH(SubstrateOptions.UseLibC);
272272
final String oHEnableStaticExecutable = oHEnabled(SubstrateOptions.StaticExecutable);
273273
final String oHEnableSharedLibraryFlagPrefix = oHEnabled + SubstrateOptions.SharedLibrary.getName();

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535
import java.lang.reflect.Field;
3636
import java.lang.reflect.Method;
3737
import java.lang.reflect.Modifier;
38-
import java.nio.file.FileSystems;
3938
import java.nio.file.Files;
4039
import java.nio.file.Path;
4140
import java.util.ArrayList;
@@ -1877,8 +1876,7 @@ public static Path getOutputDirectory() {
18771876
}
18781877

18791878
public static Path generatedFiles(OptionValues optionValues) {
1880-
String pathName = SubstrateOptions.Path.getValue(optionValues);
1881-
Path path = FileSystems.getDefault().getPath(pathName);
1879+
Path path = SubstrateOptions.getImagePath(optionValues);
18821880
if (!Files.exists(path)) {
18831881
try {
18841882
Files.createDirectories(path);
@@ -1887,7 +1885,7 @@ public static Path generatedFiles(OptionValues optionValues) {
18871885
}
18881886
}
18891887
if (!Files.isDirectory(path)) {
1890-
throw VMError.shouldNotReachHere("Output path is not a directory: " + pathName);
1888+
throw VMError.shouldNotReachHere("Output path is not a directory: " + path);
18911889
}
18921890
return path.toAbsolutePath();
18931891
}

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
import com.oracle.svm.core.util.VMError;
7272
import com.oracle.svm.hosted.code.CEntryPointData;
7373
import com.oracle.svm.hosted.image.AbstractImage.NativeImageKind;
74+
import com.oracle.svm.hosted.imagelayer.HostedImageLayerBuildingSupport;
7475
import com.oracle.svm.hosted.option.HostedOptionParser;
7576
import com.oracle.svm.util.ClassUtil;
7677
import com.oracle.svm.util.LogUtils;
@@ -410,16 +411,16 @@ private int buildImage(ImageClassLoader classLoader) {
410411
NativeImageKind imageKind = null;
411412
boolean isStaticExecutable = SubstrateOptions.StaticExecutable.getValue(parsedHostedOptions);
412413
boolean isSharedLibrary = SubstrateOptions.SharedLibrary.getValue(parsedHostedOptions);
413-
boolean isImageLayer = SubstrateOptions.LayerCreate.hasBeenSet(parsedHostedOptions);
414+
boolean layerCreateOptionEnabled = HostedImageLayerBuildingSupport.isLayerCreateOptionEnabled(parsedHostedOptions);
414415
if (isStaticExecutable && isSharedLibrary) {
415416
reportConflictingOptions(SubstrateOptions.SharedLibrary, SubstrateOptions.StaticExecutable);
416-
} else if (isStaticExecutable && isImageLayer) {
417+
} else if (isStaticExecutable && layerCreateOptionEnabled) {
417418
reportConflictingOptions(SubstrateOptions.StaticExecutable, SubstrateOptions.LayerCreate);
418-
} else if (isSharedLibrary && isImageLayer) {
419+
} else if (isSharedLibrary && layerCreateOptionEnabled) {
419420
reportConflictingOptions(SubstrateOptions.SharedLibrary, SubstrateOptions.LayerCreate);
420421
} else if (isSharedLibrary) {
421422
imageKind = NativeImageKind.SHARED_LIBRARY;
422-
} else if (isImageLayer) {
423+
} else if (layerCreateOptionEnabled) {
423424
imageKind = NativeImageKind.IMAGE_LAYER;
424425
} else if (isStaticExecutable) {
425426
imageKind = NativeImageKind.STATIC_EXECUTABLE;

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/diagnostic/HostedHeapDumpFeature.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,27 +27,26 @@
2727
import java.io.IOException;
2828
import java.nio.file.Files;
2929
import java.nio.file.Path;
30-
import java.nio.file.Paths;
3130
import java.time.LocalDateTime;
3231
import java.time.format.DateTimeFormatter;
3332
import java.util.ArrayList;
3433
import java.util.List;
3534
import java.util.stream.Collectors;
3635
import java.util.stream.Stream;
3736

38-
import jdk.graal.compiler.options.Option;
39-
4037
import com.oracle.graal.pointsto.reports.ReportUtils;
4138
import com.oracle.svm.core.SubstrateOptions;
4239
import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
4340
import com.oracle.svm.core.feature.InternalFeature;
44-
import com.oracle.svm.core.option.HostedOptionKey;
4541
import com.oracle.svm.core.option.AccumulatingLocatableMultiOptionValue;
42+
import com.oracle.svm.core.option.HostedOptionKey;
4643
import com.oracle.svm.core.option.SubstrateOptionsParser;
4744
import com.oracle.svm.core.util.UserError;
4845
import com.oracle.svm.hosted.FeatureImpl.DuringSetupAccessImpl;
4946
import com.oracle.svm.util.StringUtil;
5047

48+
import jdk.graal.compiler.options.Option;
49+
5150
@AutomaticallyRegisteredFeature
5251
public class HostedHeapDumpFeature implements InternalFeature {
5352

@@ -150,7 +149,7 @@ private void dumpHeap(String reason) {
150149

151150
private static Path getDumpLocation() {
152151
try {
153-
Path folder = Paths.get(Paths.get(SubstrateOptions.Path.getValue()).toString(), "dumps").toAbsolutePath();
152+
Path folder = SubstrateOptions.getImagePath().resolve("dumps").toAbsolutePath();
154153
return Files.createDirectories(folder);
155154
} catch (IOException e) {
156155
throw new Error("Cannot create heap dumps directory.", e);

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/driver/LayerOptionsSupport.java

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929

3030
import com.oracle.svm.core.SubstrateUtil;
3131
import com.oracle.svm.core.util.VMError;
32-
import com.oracle.svm.hosted.imagelayer.LayerArchiveSupport;
3332

3433
public class LayerOptionsSupport extends IncludeOptionsSupport {
3534

@@ -44,16 +43,8 @@ public static LayerOption parse(String layerOptionValue) {
4443

4544
public static LayerOption parse(List<String> options) {
4645
VMError.guarantee(!options.isEmpty());
47-
// Check for the optional file name
48-
Path fileName = null;
49-
int skip = 0;
50-
if (options.getFirst().endsWith(LayerArchiveSupport.LAYER_FILE_EXTENSION)) {
51-
fileName = Path.of(options.getFirst());
52-
skip = 1;
53-
}
54-
ExtendedOption[] extendedOptions = options.stream().skip(skip).map(ExtendedOption::parse).toArray(ExtendedOption[]::new);
55-
return new LayerOption(fileName, extendedOptions);
46+
ExtendedOption[] extendedOptions = options.stream().skip(1).map(ExtendedOption::parse).toArray(ExtendedOption[]::new);
47+
return new LayerOption(Path.of(options.getFirst()), extendedOptions);
5648
}
5749
}
58-
5950
}

0 commit comments

Comments
 (0)