From 600350a019fad6e324d9cfd34e3d4a947d0f8338 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20W=C3=B6gerer?= Date: Thu, 7 Nov 2024 16:01:47 +0100 Subject: [PATCH] Implement LayerCreate subcommand `package` --- .../com/oracle/svm/core/SubstrateOptions.java | 13 ++- .../svm/driver/CmdLineOptionHandler.java | 23 +++++ .../com/oracle/svm/driver/NativeImage.java | 15 +++- .../oracle/svm/hosted/ModuleLayerFeature.java | 16 +--- .../hosted/NativeImageClassLoaderSupport.java | 83 ++++++++++++------- .../HostedImageLayerBuildingSupport.java | 57 ++++++------- .../imagelayer/LayerArchiveSupport.java | 3 +- .../com/oracle/svm/util/ModuleSupport.java | 11 +++ .../NILayerTests/build_native_image_layer.py | 11 ++- 9 files changed, 153 insertions(+), 79 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java index 33e3e3e347ab..3dfd1bb42106 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java @@ -130,11 +130,14 @@ protected void onValueUpdate(EconomicMap, Object> values, Boolean o } }); - // @APIOption(name = "layer-create")// + public static final String LAYER_OPTION_PREFIX = "-H:Layer"; // "--layer" + public static final String LAYER_CREATE_OPTION = LAYER_OPTION_PREFIX + "Create"; // "-create" + // @APIOption(name = LAYER_CREATE_OPTION) // use when non-experimental @Option(help = "Experimental: Build a Native Image layer.")// public static final HostedOptionKey LayerCreate = new HostedOptionKey<>(AccumulatingLocatableMultiOptionValue.Strings.build()); - // @APIOption(name = "layer-use")// + // public static final String LAYER_USE_OPTION = LAYER_OPTION_PREFIX + "-use"; + // @APIOption(name = LAYER_USE_OPTION) // use when non-experimental @Option(help = "Experimental: Build an image based on a Native Image layer.")// @BundleMember(role = Role.Input) // public static final HostedOptionKey LayerUse = new HostedOptionKey<>(AccumulatingLocatableMultiOptionValue.Paths.build()); @@ -1286,11 +1289,15 @@ public enum ReportingMode { @Option(help = "Include all classes, methods, fields, and resources from given paths", type = OptionType.Debug) // public static final HostedOptionKey IncludeAllFromPath = new HostedOptionKey<>(AccumulatingLocatableMultiOptionValue.Strings.build()); + @Option(help = "Include all classes, methods and fields from the given packages", type = OptionType.Debug) // + public static final HostedOptionKey IncludeAllFromPackage = new HostedOptionKey<>( + AccumulatingLocatableMultiOptionValue.Strings.buildWithCommaDelimiter()); + @Option(help = "Include all classes, methods, fields, and resources from the class path", type = OptionType.Debug) // public static final HostedOptionKey IncludeAllFromClassPath = new HostedOptionKey<>(false); public static boolean includeAll() { - return IncludeAllFromModule.hasBeenSet() || IncludeAllFromPath.hasBeenSet() || IncludeAllFromClassPath.hasBeenSet(); + return IncludeAllFromModule.hasBeenSet() || IncludeAllFromPath.hasBeenSet() || IncludeAllFromPackage.hasBeenSet() || IncludeAllFromClassPath.hasBeenSet(); } @Option(help = "Force include include all public types and methods that can be reached using normal Java access rules.")// diff --git a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/CmdLineOptionHandler.java b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/CmdLineOptionHandler.java index de407337f12f..0110eb07df67 100644 --- a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/CmdLineOptionHandler.java +++ b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/CmdLineOptionHandler.java @@ -31,10 +31,14 @@ import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; +import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.VM; import com.oracle.svm.core.option.OptionOrigin; import com.oracle.svm.core.util.ExitStatus; import com.oracle.svm.driver.NativeImage.ArgumentQueue; +import com.oracle.svm.hosted.imagelayer.LayerArchiveSupport; +import com.oracle.svm.hosted.imagelayer.LayerOptionsSupport.ExtendedOption; +import com.oracle.svm.hosted.imagelayer.LayerOptionsSupport.LayerOption; import com.oracle.svm.util.LogUtils; import jdk.graal.compiler.options.OptionType; @@ -138,6 +142,25 @@ private boolean consume(ArgumentQueue args, String headArg) { return true; } + if (headArg.startsWith(SubstrateOptions.LAYER_CREATE_OPTION)) { + String layerCreateValue = headArg.substring(SubstrateOptions.LAYER_CREATE_OPTION.length()); + if (!layerCreateValue.isEmpty()) { + LayerOption layerOption = LayerOption.parse(layerCreateValue); + for (ExtendedOption option : layerOption.extendedOptions()) { + switch (option.key()) { + case LayerArchiveSupport.PACKAGE_OPTION -> { + String packageName = option.value(); + String moduleName = nativeImage.systemPackagesToModules.get(packageName); + if (moduleName != null) { + nativeImage.addAddedModules(moduleName); + } + } + } + } + } + return false; + } + if (headArg.startsWith(DEBUG_ATTACH_OPTION)) { if (useDebugAttach) { throw NativeImage.showError("The " + DEBUG_ATTACH_OPTION + " option can only be used once."); diff --git a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java index 5760be4fad64..317babc88009 100644 --- a/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java +++ b/substratevm/src/com.oracle.svm.driver/src/com/oracle/svm/driver/NativeImage.java @@ -145,6 +145,19 @@ private static String flagsFileName(String versionTag) { static final Map graalCompilerFlags = getCompilerFlags(); + private static Map getSystemPackages() { + Map res = new HashMap<>(); + for (ModuleReference moduleRef : ModuleFinder.ofSystem().findAll()) { + ModuleDescriptor moduleDescriptor = moduleRef.descriptor(); + for (String packageName : moduleDescriptor.packages()) { + res.put(packageName, moduleDescriptor.name()); + } + } + return Map.copyOf(res); + } + + final Map systemPackagesToModules = getSystemPackages(); + static String getResource(String resourceName) { try (InputStream input = NativeImage.class.getResourceAsStream(resourceName)) { BufferedReader reader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8)); @@ -963,7 +976,7 @@ private void prepareImageBuildArgs() { /* * The presence of CDS and custom system class loaders disables the use of archived - * non-system class and and triggers a warning. + * non-system class and triggers a warning. */ addImageBuilderJavaArgs("-Xshare:off"); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ModuleLayerFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ModuleLayerFeature.java index ee22e75c7e62..b43e13fea40c 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ModuleLayerFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ModuleLayerFeature.java @@ -217,7 +217,7 @@ public void afterAnalysis(AfterAnalysisAccess access) { * Parse explicitly added modules via --add-modules. This is done early as this information * is required when filtering the analysis reachable module set. */ - Set extraModules = ModuleLayerFeatureUtils.parseModuleSetModifierProperty(ModuleSupport.PROPERTY_IMAGE_EXPLICITLY_ADDED_MODULES); + Set extraModules = ModuleSupport.parseModuleSetModifierProperty(ModuleSupport.PROPERTY_IMAGE_EXPLICITLY_ADDED_MODULES); extraModules.addAll(Resources.getIncludedResourcesModules()); extraModules.stream().filter(Predicate.not(ModuleSupport.nonExplicitModules::contains)).forEach(moduleName -> { Optional module = accessImpl.imageClassLoader.findModule(moduleName); @@ -282,7 +282,7 @@ private Set calculateRootModules(Collection addModules) { ModuleFinder upgradeModulePath = NativeImageClassLoaderSupport.finderFor("jdk.module.upgrade.path"); ModuleFinder appModulePath = moduleLayerFeatureUtils.getAppModuleFinder(); String mainModule = ModuleLayerFeatureUtils.getMainModuleName(); - Set limitModules = ModuleLayerFeatureUtils.parseModuleSetModifierProperty(ModuleSupport.PROPERTY_IMAGE_EXPLICITLY_LIMITED_MODULES); + Set limitModules = ModuleSupport.parseModuleSetModifierProperty(ModuleSupport.PROPERTY_IMAGE_EXPLICITLY_LIMITED_MODULES); Object systemModules = null; ModuleFinder systemModuleFinder; @@ -658,7 +658,8 @@ private static final class ModuleLayerFeatureUtils { ModuleLayerFeatureUtils(ImageClassLoader cl) { runtimeModules = new HashMap<>(); imageClassLoader = cl; - nativeAccessEnabled = NativeImageClassLoaderOptions.EnableNativeAccess.getValue().values().stream().flatMap(m -> Arrays.stream(SubstrateUtil.split(m, ","))) + nativeAccessEnabled = NativeImageClassLoaderOptions.EnableNativeAccess.getValue().values().stream() + .flatMap(m -> Arrays.stream(SubstrateUtil.split(m, ","))) .collect(Collectors.toSet()); Method classGetDeclaredMethods0Method = ReflectionUtil.lookupMethod(Class.class, "getDeclaredFields0", boolean.class); @@ -770,15 +771,6 @@ static String formatModule(Module module) { } } - static Set parseModuleSetModifierProperty(String prop) { - Set specifiedModules = new HashSet<>(); - String args = System.getProperty(prop, ""); - if (!args.isEmpty()) { - specifiedModules.addAll(Arrays.asList(SubstrateUtil.split(args, ","))); - } - return specifiedModules; - } - static int distanceFromBootModuleLayer(ModuleLayer layer) { if (layer == ModuleLayer.boot()) { return 0; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageClassLoaderSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageClassLoaderSupport.java index 3a23d5551afa..e21b23e82c76 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageClassLoaderSupport.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageClassLoaderSupport.java @@ -26,6 +26,7 @@ import static com.oracle.svm.core.SubstrateOptions.IncludeAllFromClassPath; import static com.oracle.svm.core.SubstrateOptions.IncludeAllFromModule; +import static com.oracle.svm.core.SubstrateOptions.IncludeAllFromPackage; import static com.oracle.svm.core.SubstrateOptions.IncludeAllFromPath; import static com.oracle.svm.core.util.VMError.guarantee; import static com.oracle.svm.core.util.VMError.shouldNotReachHere; @@ -74,7 +75,6 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import com.oracle.svm.core.SubstrateUtil; import org.graalvm.collections.EconomicMap; import org.graalvm.collections.EconomicSet; import org.graalvm.collections.MapCursor; @@ -82,6 +82,7 @@ import com.oracle.svm.core.NativeImageClassLoaderOptions; import com.oracle.svm.core.SubstrateOptions; +import com.oracle.svm.core.SubstrateUtil; import com.oracle.svm.core.option.AccumulatingLocatableMultiOptionValue; import com.oracle.svm.core.option.HostedOptionKey; import com.oracle.svm.core.option.LocatableMultiOptionValue.ValueWithOrigin; @@ -129,13 +130,15 @@ public final class NativeImageClassLoaderSupport { public final AnnotationExtractor annotationExtractor; private Set javaModuleNamesToInclude; + private Set javaPackagesToInclude; private Set javaPathsToInclude; private boolean includeAllFromClassPath; private Optional libGraalLoader; private List classLoaders; - private final Set> classesToIncludeUnconditionally = Collections.newSetFromMap(new ConcurrentHashMap<>()); + private final Set> classesToIncludeUnconditionally = ConcurrentHashMap.newKeySet(); + private final Set includedJavaPackages = ConcurrentHashMap.newKeySet(); private final Method implAddReadsAllUnnamed = ReflectionUtil.lookupMethod(Module.class, "implAddReadsAllUnnamed"); private final Method implAddEnableNativeAccess = ReflectionUtil.lookupMethod(Module.class, "implAddEnableNativeAccess"); @@ -244,7 +247,7 @@ private static Path stringToPath(String path) { } public void loadAllClasses(ForkJoinPool executor, ImageClassLoader imageClassLoader) { - guarantee(javaModuleNamesToInclude == null, "This method should be executed only once."); + guarantee(javaModuleNamesToInclude == null && javaPackagesToInclude == null, "This method should be executed only once."); javaModuleNamesToInclude = Collections.unmodifiableSet(new HashSet<>(IncludeAllFromModule.getValue(parsedHostedOptions).values())); /* Verify all modules are present */ final Set allModules = Stream.concat(modulepathModuleFinder.findAll().stream(), upgradeAndSystemModuleFinder.findAll().stream()) @@ -254,6 +257,8 @@ public void loadAllClasses(ForkJoinPool executor, ImageClassLoader imageClassLoa .filter(m -> !allModules.contains(m)) .findAny().ifPresent(m -> missingFromSetOfEntriesError(m, allModules, "module-path", IncludeAllFromModule)); + javaPackagesToInclude = Set.copyOf(IncludeAllFromPackage.getValue(parsedHostedOptions).values()); + javaPathsToInclude = IncludeAllFromPath.getValue(parsedHostedOptions).values().stream() .map(NativeImageClassLoaderSupport::stringToPath) .map(Path::toAbsolutePath) @@ -722,32 +727,44 @@ private void run() { System.out.println("Total processed entries: " + entriesProcessed.longValue() + ", current entry: " + currentlyProcessedEntry); }, 5, 1, TimeUnit.MINUTES); - List requiresInit = new ArrayList<>(Arrays.asList( - "jdk.internal.vm.ci", "jdk.graal.compiler", "com.oracle.graal.graal_enterprise", + var requiresInit = new HashSet<>(List.of("jdk.internal.vm.ci", "jdk.graal.compiler", "com.oracle.graal.graal_enterprise", "org.graalvm.nativeimage", "org.graalvm.truffle", "org.graalvm.truffle.runtime", "org.graalvm.truffle.compiler", "com.oracle.truffle.enterprise", "org.graalvm.jniutils", "org.graalvm.nativebridge")); - Set additionalSystemModules = upgradeAndSystemModuleFinder.findAll().stream().map(v -> v.descriptor().name()).collect(Collectors.toSet()); + Set additionalSystemModules = upgradeAndSystemModuleFinder.findAll().stream() + .map(v -> v.descriptor().name()) + .collect(Collectors.toSet()); additionalSystemModules.retainAll(getJavaModuleNamesToInclude()); requiresInit.addAll(additionalSystemModules); + Set explicitlyAddedModules = ModuleSupport.parseModuleSetModifierProperty(ModuleSupport.PROPERTY_IMAGE_EXPLICITLY_ADDED_MODULES); + for (ModuleReference moduleReference : upgradeAndSystemModuleFinder.findAll()) { - if (requiresInit.contains(moduleReference.descriptor().name())) { - initModule(moduleReference); + String moduleName = moduleReference.descriptor().name(); + boolean moduleRequiresInit = requiresInit.contains(moduleName); + if (moduleRequiresInit || explicitlyAddedModules.contains(moduleName)) { + initModule(moduleReference, moduleRequiresInit); } } for (ModuleReference moduleReference : modulepathModuleFinder.findAll()) { - initModule(moduleReference); + initModule(moduleReference, true); } classpath().parallelStream().forEach(this::loadClassesFromPath); } finally { scheduledExecutor.shutdown(); } + + /* Verify all package inclusion requests were successful */ + for (String packageName : javaPackagesToInclude) { + if (!includedJavaPackages.contains(packageName)) { + missingFromSetOfEntriesError(packageName, includedJavaPackages, "package", IncludeAllFromPackage); + } + } } - private void initModule(ModuleReference moduleReference) { + private void initModule(ModuleReference moduleReference, boolean moduleRequiresInit) { String moduleReferenceLocation = moduleReference.location().map(URI::toString).orElse("UnknownModuleReferenceLocation"); currentlyProcessedEntry = moduleReferenceLocation; Optional optionalModule = findModule(moduleReference.descriptor().name()); @@ -766,7 +783,7 @@ private void initModule(ModuleReference moduleReference) { String className = extractClassName(moduleResource, fileSystemSeparatorChar); if (className != null) { currentlyProcessedEntry = moduleReferenceLocation + fileSystemSeparatorChar + moduleResource; - executor.execute(() -> handleClassFileName(container, module, className, includeUnconditionally)); + executor.execute(() -> handleClassFileName(container, module, className, includeUnconditionally, moduleRequiresInit)); } entriesProcessed.increment(); }); @@ -832,7 +849,7 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { String className = extractClassName(fileName, fileSystemSeparatorChar); if (className != null) { currentlyProcessedEntry = file.toUri().toString(); - executor.execute(() -> handleClassFileName(container, null, className, includeUnconditionally)); + executor.execute(() -> handleClassFileName(container, null, className, includeUnconditionally, true)); } entriesProcessed.increment(); return FileVisitResult.CONTINUE; @@ -916,24 +933,26 @@ private String extractClassName(String fileName, char fileSystemSeparatorChar) { return strippedClassFileName.equals("module-info") ? null : strippedClassFileName.replace(fileSystemSeparatorChar, '.'); } - private void handleClassFileName(URI container, Module module, String className, boolean includeUnconditionally) { - synchronized (classes) { - EconomicSet classNames = classes.get(container); - if (classNames == null) { - classNames = EconomicSet.create(); - classes.put(container, classNames); + private void handleClassFileName(URI container, Module module, String className, boolean includeUnconditionally, boolean classRequiresInit) { + if (classRequiresInit) { + synchronized (classes) { + EconomicSet classNames = classes.get(container); + if (classNames == null) { + classNames = EconomicSet.create(); + classes.put(container, classNames); + } + classNames.add(className); } - classNames.add(className); - } - int packageSep = className.lastIndexOf('.'); - String packageName = packageSep > 0 ? className.substring(0, packageSep) : ""; - synchronized (packages) { - EconomicSet packageNames = packages.get(container); - if (packageNames == null) { - packageNames = EconomicSet.create(); - packages.put(container, packageNames); + int packageSep = className.lastIndexOf('.'); + String packageName = packageSep > 0 ? className.substring(0, packageSep) : ""; + synchronized (packages) { + EconomicSet packageNames = packages.get(container); + if (packageNames == null) { + packageNames = EconomicSet.create(); + packages.put(container, packageNames); + } + packageNames.add(packageName); } - packageNames.add(packageName); } Class clazz = null; @@ -945,10 +964,14 @@ private void handleClassFileName(URI container, Module module, String className, ImageClassLoader.handleClassLoadingError(t); } if (clazz != null) { - if (includeUnconditionally) { + String packageName = clazz.getPackageName(); + includedJavaPackages.add(packageName); + if (includeUnconditionally || javaPackagesToInclude.contains(packageName)) { classesToIncludeUnconditionally.add(clazz); } - imageClassLoader.handleClass(clazz); + if (classRequiresInit) { + imageClassLoader.handleClass(clazz); + } } imageClassLoader.watchdog.recordActivity(); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/HostedImageLayerBuildingSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/HostedImageLayerBuildingSupport.java index 9692e4824cde..0942ce8aa715 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/HostedImageLayerBuildingSupport.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/HostedImageLayerBuildingSupport.java @@ -24,18 +24,8 @@ */ package com.oracle.svm.hosted.imagelayer; -import static com.oracle.svm.core.SubstrateOptions.IncludeAllFromModule; -import static com.oracle.svm.core.SubstrateOptions.IncludeAllFromPath; -import static com.oracle.svm.core.SubstrateOptions.LayerCreate; -import static com.oracle.svm.core.SubstrateOptions.LayerUse; -import static com.oracle.svm.core.SubstrateOptions.imageLayerCreateEnabledHandler; -import static com.oracle.svm.core.SubstrateOptions.imageLayerEnabledHandler; -import static com.oracle.svm.hosted.imagelayer.LayerArchiveSupport.MODULE_OPTION; -import static com.oracle.svm.hosted.imagelayer.LayerArchiveSupport.PACKAGE_OPTION; - import java.io.File; import java.nio.file.Path; -import java.util.Arrays; import java.util.List; import org.graalvm.collections.EconomicMap; @@ -58,6 +48,7 @@ import com.oracle.svm.hosted.c.NativeLibraries; import com.oracle.svm.hosted.heap.SVMImageLayerLoader; import com.oracle.svm.hosted.heap.SVMImageLayerWriter; +import com.oracle.svm.hosted.imagelayer.LayerOptionsSupport.ExtendedOption; import com.oracle.svm.hosted.imagelayer.LayerOptionsSupport.LayerOption; import jdk.graal.compiler.core.common.SuppressFBWarnings; @@ -108,50 +99,54 @@ public void archiveLayer(String imageName) { */ public static void processLayerOptions(EconomicMap, Object> values) { OptionValues hostedOptions = new OptionValues(values); - if (LayerCreate.hasBeenSet(hostedOptions)) { + if (SubstrateOptions.LayerCreate.hasBeenSet(hostedOptions)) { /* The last value wins, GR-55565 will warn about the overwritten values. */ - String layerCreateValue = LayerCreate.getValue(hostedOptions).lastValue().orElseThrow(); + String layerCreateValue = SubstrateOptions.LayerCreate.getValue(hostedOptions).lastValue().orElseThrow(); if (layerCreateValue.isEmpty()) { /* Nothing to do, an empty --layer-create= disables the layer creation. */ } else { LayerOption layerOption = LayerOption.parse(layerCreateValue); - String buildLayer = SubstrateOptionsParser.commandArgument(LayerCreate, ""); - Arrays.stream(layerOption.extendedOptions()).forEach(option -> { + String buildLayer = SubstrateOptionsParser.commandArgument(SubstrateOptions.LayerCreate, ""); + for (ExtendedOption option : layerOption.extendedOptions()) { switch (option.key()) { - case MODULE_OPTION -> { + case LayerArchiveSupport.MODULE_OPTION -> { UserError.guarantee(option.value() != null, "Option %s of %s requires a module name argument, e.g., %s=module-name.", option.key(), buildLayer, option.key()); - IncludeAllFromModule.update(values, option.value()); + SubstrateOptions.IncludeAllFromModule.update(values, option.value()); } - case PACKAGE_OPTION -> { + case LayerArchiveSupport.PACKAGE_OPTION -> { UserError.guarantee(option.value() != null, "Option %s of %s requires a package name argument, e.g., %s=package-name.", option.key(), buildLayer, option.key()); - IncludeAllFromPath.update(values, option.value()); + SubstrateOptions.IncludeAllFromPackage.update(values, option.value()); + } + case LayerArchiveSupport.PATH_OPTION -> { + UserError.guarantee(option.value() != null, "Option %s of %s requires a class-path entry, e.g., %s=path/to/cp-entry.", option.key(), buildLayer, option.key()); + SubstrateOptions.IncludeAllFromPath.update(values, option.value()); } default -> throw UserError.abort("Unknown option %s of %s. Use --help-extra for usage instructions.", option.key(), buildLayer); } - }); + } SubstrateOptions.UseBaseLayerInclusionPolicy.update(values, true); SubstrateOptions.ClosedTypeWorld.update(values, false); - if (imageLayerEnabledHandler != null) { - imageLayerEnabledHandler.onOptionEnabled(values); + if (SubstrateOptions.imageLayerEnabledHandler != null) { + SubstrateOptions.imageLayerEnabledHandler.onOptionEnabled(values); } - if (imageLayerCreateEnabledHandler != null) { - imageLayerCreateEnabledHandler.onOptionEnabled(values); + if (SubstrateOptions.imageLayerCreateEnabledHandler != null) { + SubstrateOptions.imageLayerCreateEnabledHandler.onOptionEnabled(values); } SubstrateOptions.UseContainerSupport.update(values, false); } } - if (LayerUse.hasBeenSet(hostedOptions)) { + if (SubstrateOptions.LayerUse.hasBeenSet(hostedOptions)) { /* The last value wins, GR-55565 will warn about the overwritten values. */ - Path layerUseValue = LayerUse.getValue(hostedOptions).lastValue().orElseThrow(); + Path layerUseValue = SubstrateOptions.LayerUse.getValue(hostedOptions).lastValue().orElseThrow(); if (layerUseValue.toString().isEmpty()) { /* Nothing to do, an empty --layer-use= disables the layer application. */ } else { SubstrateOptions.ClosedTypeWorldHubLayout.update(values, false); SubstrateOptions.ParseRuntimeOptions.update(values, false); - if (imageLayerEnabledHandler != null) { - imageLayerEnabledHandler.onOptionEnabled(values); + if (SubstrateOptions.imageLayerEnabledHandler != null) { + SubstrateOptions.imageLayerEnabledHandler.onOptionEnabled(values); } } } @@ -166,8 +161,8 @@ private static boolean isLayerOptionEnabled(HostedOptionKey parseModuleSetModifierProperty(String prop) { + Set specifiedModules = new HashSet<>(); + String args = System.getProperty(prop, ""); + if (!args.isEmpty()) { + specifiedModules.addAll(Arrays.asList(args.split(","))); + } + return specifiedModules; + } + @Platforms(Platform.HOSTED_ONLY.class) public enum Access { OPEN { diff --git a/vm/tests/gh_workflows/NILayerTests/build_native_image_layer.py b/vm/tests/gh_workflows/NILayerTests/build_native_image_layer.py index 75dba900132e..c7848caa6e4d 100644 --- a/vm/tests/gh_workflows/NILayerTests/build_native_image_layer.py +++ b/vm/tests/gh_workflows/NILayerTests/build_native_image_layer.py @@ -109,7 +109,16 @@ def build_layers(native_image_path, coordinates, delimiter): os.chdir(library_path) dependency_path = subprocess.check_output(['mvn', '-q', 'exec:exec', '-Dexec.executable=echo', '-Dexec.args=%classpath']).decode('utf-8').rstrip() os.chdir(image_path) - command = [native_image_path, '-J-ea', '-J-esa', '-H:+UnlockExperimentalVMOptions', '-cp' ,f'{jar_path}:{dependency_path}', f'-H:LayerCreate=layer.nil,package={jar_path}', '-H:+ReportExceptionStackTraces', '--no-fallback' , '-o', f'{artifact_id}-{version}'] + command = [ + native_image_path, + '-J-ea', '-J-esa', + '--no-fallback', + '-cp' ,f'{jar_path}:{dependency_path}', + '-o', f'{artifact_id}-{version}' + '-H:+UnlockExperimentalVMOptions', + f'-H:LayerCreate=layer.nil,path={jar_path}', + '-H:+ReportExceptionStackTraces', + ] print(f'Command: {' '.join(command)}') subprocess.run(command, check=True) os.chdir('..')