Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ enum ArtifactType {
EXECUTABLE("executables"),
/* Native image layer. */
IMAGE_LAYER("image_layer"),
/* Native image layer bundle. */
IMAGE_LAYER_BUNDLE("image_layer_bundle"),
/* For all shared libraries that are not JDK-related and needed at run-time. */
SHARED_LIBRARY("shared_libraries"),

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@

import java.nio.file.InvalidPathException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.UUID;
import java.util.function.Predicate;
Expand All @@ -44,6 +43,7 @@
import org.graalvm.nativeimage.ImageInfo;
import org.graalvm.nativeimage.ImageSingletons;
import org.graalvm.nativeimage.Platform;
import org.graalvm.nativeimage.Platform.HOSTED_ONLY;
import org.graalvm.nativeimage.Platforms;

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

@OptionMigrationMessage("Use the '-o' option instead.")//
@Option(help = "Directory of the image file to be generated", type = OptionType.User)//
public static final HostedOptionKey<String> Path = new HostedOptionKey<>(null);
@Platforms(HOSTED_ONLY.class)
public static Path getImagePath(OptionValues optionValues) {
VMError.guarantee(optionValues != null);
if (!ConcealedOptions.Path.hasBeenSet(optionValues)) {
VMError.shouldNotReachHere("Image builder requires %s", SubstrateOptionsParser.commandArgument(ConcealedOptions.Path, "<builder output directory>"));
}
return Path.of(ConcealedOptions.Path.getValue(optionValues));
}

@Platforms(HOSTED_ONLY.class)
public static Path getImagePath() {
return getImagePath(HostedOptionValues.singleton());
}

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

@Platforms(HOSTED_ONLY.class)
public static Path getDebugInfoSourceCacheRoot() {
try {
return Paths.get(Path.getValue()).resolve(DebugInfoSourceCacheRoot.getValue());
return SubstrateOptions.getImagePath().resolve(DebugInfoSourceCacheRoot.getValue());
} catch (InvalidPathException ipe) {
throw UserError.invalidOptionValue(DebugInfoSourceCacheRoot, DebugInfoSourceCacheRoot.getValue(), "The path is invalid");
}
Expand Down Expand Up @@ -1144,6 +1156,10 @@ protected void onValueUpdate(EconomicMap<OptionKey<?>, Object> values, Integer o
/** Use {@link SubstrateOptions#codeAlignment()} instead. */
@Option(help = "Alignment of AOT and JIT compiled code in bytes. The default of 0 automatically selects a suitable value.")//
public static final HostedOptionKey<Integer> CodeAlignment = new HostedOptionKey<>(0);

@OptionMigrationMessage("Use the '-o' option instead.")//
@Option(help = "Directory of the image file to be generated", type = OptionType.User)//
public static final HostedOptionKey<String> Path = new HostedOptionKey<>(null);
}

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

@Platforms(HOSTED_ONLY.class)
public static String reportsPath() {
Path reportsPath = ImageSingletons.lookup(ReportingSupport.class).reportsPath;
if (reportsPath.isAbsolute()) {
return reportsPath.toString();
}
return Paths.get(Path.getValue()).resolve(reportsPath).toString();
return getImagePath().resolve(reportsPath).toString();
}

public static class ReportingSupport {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,11 @@ base-layer.so # initial layer (includes VM/JDK code)

To create and use layers `native-image` accepts two options: `--layer-create` and `--layer-use`.

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

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

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

Second, `--layer-use` consumes a shared layer, and can extend it or create a final executable:
#### `--layer-create` suboptions

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.
Within a `--layer-create` option argument, these suboption arguments can be specified multiple times, for example:
```
--layer-create=base-layer.nil,package=ch.qos.logback.core.hook,package=ch.qos.logback.core.html,...
```

##### `--layer-create` suboption `module=<module-name>`

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.
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.

##### `--layer-create` suboption `package=<package-name>`

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.
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).

##### `--layer-create` suboption `path=<classpath entry>`

This is a convenience suboption that requires a `classpath entry`.
If the provided entry is not also specified in the classpath of the given `native-image` invocation, an error message is shown.
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.

#### `--layer-create` option argument file

For complex use-cases, the `--layer-create` option argument can become very large.
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.

This currently only works if the `--layer-create` option is specified from a `native-image.properties` file in a `META-INF/native-image` subdirectory.
If this requirement is met, the following can be used:
```properties
Args = [email protected]
```
The `layer-create.args` file-path is relative to the directory that contains the `native-image.properties` file and might look like this:
```
base-layer.nil
module=java.base
# micronaut and dependencies
package=io.micronaut.*
package=io.netty.*
package=jakarta.*
package=com.fasterxml.jackson.*
package=org.slf4j.*
# io.projectreactor:reactor-core and dependencies
package=reactor.*
package=org.reactivestreams.*
```
Each line corresponds to one entry in the list of comma-separated entries that can usually be found in a regular `--layer-create` argument.
Lines starting with `#` are ignored and can therefore be used to provide comments in such an option argument file.

### Option `--layer-use` consumes a shared layer, and can extend it or create a final executable:

```
--layer-use=layer-file.nil
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ private static <T> String oR(OptionKey<T> option) {
final String oHModule = oH(SubstrateOptions.Module);
final String oHClass = oH(SubstrateOptions.Class);
final String oHName = oH(SubstrateOptions.Name);
final String oHPath = oH(SubstrateOptions.Path);
final String oHPath = oH(SubstrateOptions.ConcealedOptions.Path);
final String oHUseLibC = oH(SubstrateOptions.UseLibC);
final String oHEnableStaticExecutable = oHEnabled(SubstrateOptions.StaticExecutable);
final String oHEnableSharedLibraryFlagPrefix = oHEnabled + SubstrateOptions.SharedLibrary.getName();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
Expand Down Expand Up @@ -1877,8 +1876,7 @@ public static Path getOutputDirectory() {
}

public static Path generatedFiles(OptionValues optionValues) {
String pathName = SubstrateOptions.Path.getValue(optionValues);
Path path = FileSystems.getDefault().getPath(pathName);
Path path = SubstrateOptions.getImagePath(optionValues);
if (!Files.exists(path)) {
try {
Files.createDirectories(path);
Expand All @@ -1887,7 +1885,7 @@ public static Path generatedFiles(OptionValues optionValues) {
}
}
if (!Files.isDirectory(path)) {
throw VMError.shouldNotReachHere("Output path is not a directory: " + pathName);
throw VMError.shouldNotReachHere("Output path is not a directory: " + path);
}
return path.toAbsolutePath();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
import com.oracle.svm.core.util.VMError;
import com.oracle.svm.hosted.code.CEntryPointData;
import com.oracle.svm.hosted.image.AbstractImage.NativeImageKind;
import com.oracle.svm.hosted.imagelayer.HostedImageLayerBuildingSupport;
import com.oracle.svm.hosted.option.HostedOptionParser;
import com.oracle.svm.util.ClassUtil;
import com.oracle.svm.util.LogUtils;
Expand Down Expand Up @@ -410,16 +411,16 @@ private int buildImage(ImageClassLoader classLoader) {
NativeImageKind imageKind = null;
boolean isStaticExecutable = SubstrateOptions.StaticExecutable.getValue(parsedHostedOptions);
boolean isSharedLibrary = SubstrateOptions.SharedLibrary.getValue(parsedHostedOptions);
boolean isImageLayer = SubstrateOptions.LayerCreate.hasBeenSet(parsedHostedOptions);
boolean layerCreateOptionEnabled = HostedImageLayerBuildingSupport.isLayerCreateOptionEnabled(parsedHostedOptions);
if (isStaticExecutable && isSharedLibrary) {
reportConflictingOptions(SubstrateOptions.SharedLibrary, SubstrateOptions.StaticExecutable);
} else if (isStaticExecutable && isImageLayer) {
} else if (isStaticExecutable && layerCreateOptionEnabled) {
reportConflictingOptions(SubstrateOptions.StaticExecutable, SubstrateOptions.LayerCreate);
} else if (isSharedLibrary && isImageLayer) {
} else if (isSharedLibrary && layerCreateOptionEnabled) {
reportConflictingOptions(SubstrateOptions.SharedLibrary, SubstrateOptions.LayerCreate);
} else if (isSharedLibrary) {
imageKind = NativeImageKind.SHARED_LIBRARY;
} else if (isImageLayer) {
} else if (layerCreateOptionEnabled) {
imageKind = NativeImageKind.IMAGE_LAYER;
} else if (isStaticExecutable) {
imageKind = NativeImageKind.STATIC_EXECUTABLE;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,27 +27,26 @@
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import jdk.graal.compiler.options.Option;

import com.oracle.graal.pointsto.reports.ReportUtils;
import com.oracle.svm.core.SubstrateOptions;
import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
import com.oracle.svm.core.feature.InternalFeature;
import com.oracle.svm.core.option.HostedOptionKey;
import com.oracle.svm.core.option.AccumulatingLocatableMultiOptionValue;
import com.oracle.svm.core.option.HostedOptionKey;
import com.oracle.svm.core.option.SubstrateOptionsParser;
import com.oracle.svm.core.util.UserError;
import com.oracle.svm.hosted.FeatureImpl.DuringSetupAccessImpl;
import com.oracle.svm.util.StringUtil;

import jdk.graal.compiler.options.Option;

@AutomaticallyRegisteredFeature
public class HostedHeapDumpFeature implements InternalFeature {

Expand Down Expand Up @@ -150,7 +149,7 @@ private void dumpHeap(String reason) {

private static Path getDumpLocation() {
try {
Path folder = Paths.get(Paths.get(SubstrateOptions.Path.getValue()).toString(), "dumps").toAbsolutePath();
Path folder = SubstrateOptions.getImagePath().resolve("dumps").toAbsolutePath();
return Files.createDirectories(folder);
} catch (IOException e) {
throw new Error("Cannot create heap dumps directory.", e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@

import com.oracle.svm.core.SubstrateUtil;
import com.oracle.svm.core.util.VMError;
import com.oracle.svm.hosted.imagelayer.LayerArchiveSupport;

public class LayerOptionsSupport extends IncludeOptionsSupport {

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

public static LayerOption parse(List<String> options) {
VMError.guarantee(!options.isEmpty());
// Check for the optional file name
Path fileName = null;
int skip = 0;
if (options.getFirst().endsWith(LayerArchiveSupport.LAYER_FILE_EXTENSION)) {
fileName = Path.of(options.getFirst());
skip = 1;
}
ExtendedOption[] extendedOptions = options.stream().skip(skip).map(ExtendedOption::parse).toArray(ExtendedOption[]::new);
return new LayerOption(fileName, extendedOptions);
ExtendedOption[] extendedOptions = options.stream().skip(1).map(ExtendedOption::parse).toArray(ExtendedOption[]::new);
return new LayerOption(Path.of(options.getFirst()), extendedOptions);
}
}

}
Loading
Loading