From 9ccfbd284034268d08feee53d7d182b9ed267523 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20W=C3=B6gerer?= Date: Wed, 16 Jul 2025 16:45:47 +0200 Subject: [PATCH 1/2] Fail fast when trying to build layered image on unsupported platform --- .../HostedImageLayerBuildingSupport.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) 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 b7f7c4839123..f0b4ae36f682 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 @@ -35,6 +35,8 @@ import org.graalvm.collections.EconomicMap; import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platform.LINUX_AMD64; import com.oracle.graal.pointsto.api.PointstoOptions; import com.oracle.graal.pointsto.util.AnalysisError; @@ -270,10 +272,26 @@ private static boolean isLayerUseOptionEnabled(OptionValues values) { return false; } + private static boolean supportedPlatform(Platform platform) { + boolean supported = platform instanceof LINUX_AMD64; + return supported; + } + public static HostedImageLayerBuildingSupport initialize(HostedOptionValues values, ImageClassLoader imageClassLoader, Path builderTempDir) { boolean buildingSharedLayer = isLayerCreateOptionEnabled(values); boolean buildingExtensionLayer = isLayerUseOptionEnabled(values); + if (buildingSharedLayer) { + Platform platform = imageClassLoader.platform; + if (!supportedPlatform(platform)) { + ValueWithOrigin valueWithOrigin = getLayerCreateValueWithOrigin(values); + String layerCreateValue = getLayerCreateValue(valueWithOrigin); + String layerCreateArg = SubstrateOptionsParser.commandArgument(SubstrateOptions.LayerCreate, layerCreateValue); + throw UserError.abort("Layer creation option '%s' from %s is not supported when building for platform %s/%s.", + layerCreateArg, valueWithOrigin.origin(), platform.getOS(), platform.getArchitecture()); + } + } + boolean buildingImageLayer = buildingSharedLayer || buildingExtensionLayer; boolean buildingInitialLayer = buildingImageLayer && !buildingExtensionLayer; boolean buildingFinalLayer = buildingImageLayer && !buildingSharedLayer; From ba695fca08e9f40fff4e9de22093e656ab5f40a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20W=C3=B6gerer?= Date: Thu, 17 Jul 2025 11:37:36 +0200 Subject: [PATCH 2/2] Use org.graalvm.nativeimage.Platform in LayerArchiveSupport --- .../HostedImageLayerBuildingSupport.java | 4 ++-- .../imagelayer/LayerArchiveSupport.java | 23 ++++++++++--------- .../imagelayer/LoadLayerArchiveSupport.java | 6 +++-- .../imagelayer/WriteLayerArchiveSupport.java | 6 +++-- 4 files changed, 22 insertions(+), 17 deletions(-) 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 f0b4ae36f682..7f497d0b8c6c 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 @@ -135,7 +135,7 @@ public WriteLayerArchiveSupport getWriteLayerArchiveSupport() { public void archiveLayer() { writer.dumpFiles(); - writeLayerArchiveSupport.write(); + writeLayerArchiveSupport.write(imageClassLoader.platform); } public SharedLayerSnapshot.Reader getSnapshot() { @@ -311,7 +311,7 @@ public static HostedImageLayerBuildingSupport initialize(HostedOptionValues valu List graphs = List.of(); if (buildingExtensionLayer) { Path layerFileName = getLayerUseValue(values); - loadLayerArchiveSupport = new LoadLayerArchiveSupport(layerName, layerFileName, builderTempDir, archiveSupport); + loadLayerArchiveSupport = new LoadLayerArchiveSupport(layerName, layerFileName, builderTempDir, archiveSupport, imageClassLoader.platform); boolean strict = SubstrateOptions.LayerOptionVerification.getValue(values); boolean verbose = SubstrateOptions.LayerOptionVerificationVerbose.getValue(values); loadLayerArchiveSupport.verifyCompatibility(imageClassLoader.classLoaderSupport, collectLayerVerifications(imageClassLoader), strict, verbose); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/LayerArchiveSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/LayerArchiveSupport.java index 50c8a3518a17..cb23f4560965 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/LayerArchiveSupport.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/LayerArchiveSupport.java @@ -38,9 +38,9 @@ import java.util.Objects; import java.util.Properties; -import com.oracle.svm.core.OS; +import org.graalvm.nativeimage.Platform; + import com.oracle.svm.core.SharedConstants; -import com.oracle.svm.core.SubstrateUtil; import com.oracle.svm.core.util.ArchiveSupport; import com.oracle.svm.core.util.UserError; import com.oracle.svm.core.util.VMError; @@ -184,7 +184,7 @@ public String toString() { } } - void loadAndVerify() { + void loadAndVerify(Platform current) { Path layerFileName = layerFile.getFileName(); Path layerPropertiesFile = getLayerPropertiesFile(); @@ -204,17 +204,18 @@ void loadAndVerify() { throw UserError.abort(message); } - String niPlatform = properties.getOrDefault(PROPERTY_KEY_LAYER_BUILDER_VM_PLATFORM, "unknown"); - if (!niPlatform.equals(platform())) { + String archivePlatform = properties.getOrDefault(PROPERTY_KEY_LAYER_BUILDER_VM_PLATFORM, "unknown"); + String currentPlatform = asString(current); + if (!archivePlatform.equals(currentPlatform)) { String message = String.format("The given layer file '%s' was created on platform '%s'. The current platform is '%s'." + " The given layer file can only be used with an image builder running on that same platform.", - layerFileName, niPlatform, platform()); + layerFileName, archivePlatform, currentPlatform); throw UserError.abort(message); } String layerCreationTimestamp = properties.getOrDefault(PROPERTY_KEY_LAYER_FILE_CREATION_TIMESTAMP, ""); info("Layer created at '%s'", ArchiveSupport.parseTimestamp(layerCreationTimestamp)); - info("Using version: %s on platform: '%s'", layerBuilderVMIdentifier, niPlatform); + info("Using version: %s on platform: '%s'", layerBuilderVMIdentifier, archivePlatform); } private void verifyLayerFileVersion(Path layerFileName) { @@ -237,9 +238,9 @@ private void verifyLayerFileVersion(Path layerFileName) { } } - void write() { + void write(Platform current) { properties.put(PROPERTY_KEY_LAYER_FILE_CREATION_TIMESTAMP, ArchiveSupport.currentTime()); - properties.put(PROPERTY_KEY_LAYER_BUILDER_VM_PLATFORM, platform()); + properties.put(PROPERTY_KEY_LAYER_BUILDER_VM_PLATFORM, asString(current)); BuilderVMIdentifier.system().store(properties); Path layerPropertiesFile = getLayerPropertiesFile(); Path parent = layerPropertiesFile.getParent(); @@ -261,8 +262,8 @@ public String layerName() { } } - private static String platform() { - return (OS.getCurrent().className + "-" + SubstrateUtil.getArchitectureName()).toLowerCase(Locale.ROOT); + private static String asString(Platform val) { + return (val.getOS() + "-" + val.getArchitecture()).toLowerCase(Locale.ROOT); } protected static void info(String format, Object... args) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/LoadLayerArchiveSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/LoadLayerArchiveSupport.java index f8ef09680ce8..855135c05c9b 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/LoadLayerArchiveSupport.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/LoadLayerArchiveSupport.java @@ -39,6 +39,8 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import org.graalvm.nativeimage.Platform; + import com.oracle.svm.core.option.LayerVerifiedOption; import com.oracle.svm.core.option.LayerVerifiedOption.Kind; import com.oracle.svm.core.option.LayerVerifiedOption.Severity; @@ -58,10 +60,10 @@ public class LoadLayerArchiveSupport extends LayerArchiveSupport { @SuppressWarnings("this-escape") - public LoadLayerArchiveSupport(String layerName, Path layerFile, Path tempDir, ArchiveSupport archiveSupport) { + public LoadLayerArchiveSupport(String layerName, Path layerFile, Path tempDir, ArchiveSupport archiveSupport, Platform current) { super(layerName, layerFile, tempDir.resolve(LAYER_TEMP_DIR_PREFIX + "load"), archiveSupport); this.archiveSupport.expandJarToDir(layerFile, layerDir); - layerProperties.loadAndVerify(); + layerProperties.loadAndVerify(current); loadBuilderArgumentsFile(); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/WriteLayerArchiveSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/WriteLayerArchiveSupport.java index c211547b2781..9a3d266464a8 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/WriteLayerArchiveSupport.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/WriteLayerArchiveSupport.java @@ -31,6 +31,8 @@ import java.nio.file.Path; import java.util.jar.JarOutputStream; +import org.graalvm.nativeimage.Platform; + import com.oracle.svm.core.BuildArtifacts; import com.oracle.svm.core.BuildArtifacts.ArtifactType; import com.oracle.svm.core.SubstrateOptions; @@ -86,7 +88,7 @@ private void writeEnvVariablesFile() { } } - public void write() { + public void write(Platform current) { try (JarOutputStream jarOutStream = new JarOutputStream(Files.newOutputStream(layerFile), archiveSupport.createManifest())) { // disable compression for significant (un)archiving speedup at the cost of file size jarOutStream.setLevel(0); @@ -103,7 +105,7 @@ public void write() { Path sharedLibFile = BuildArtifacts.singleton().get(BuildArtifacts.ArtifactType.IMAGE_LAYER).getFirst(); archiveSupport.addFileToJar(NativeImageGenerator.getOutputDirectory(), sharedLibFile, layerFile, jarOutStream); // write properties file and add to jar - layerProperties.write(); + layerProperties.write(current); archiveSupport.addFileToJar(layerDir, getLayerPropertiesFile(), layerFile, jarOutStream); BuildArtifacts.singleton().add(ArtifactType.IMAGE_LAYER_BUNDLE, layerFile); } catch (IOException e) {