diff --git a/java-benchmarks/mx.java-benchmarks/mx_java_benchmarks.py b/java-benchmarks/mx.java-benchmarks/mx_java_benchmarks.py index a5ffcf16a7b1..954ec4d9db6b 100644 --- a/java-benchmarks/mx.java-benchmarks/mx_java_benchmarks.py +++ b/java-benchmarks/mx.java-benchmarks/mx_java_benchmarks.py @@ -535,11 +535,11 @@ def extra_image_build_argument(self, benchmark, args): '-J--add-exports=org.graalvm.nativeimage/org.graalvm.nativeimage.impl=ALL-UNNAMED', '-J--add-exports=org.graalvm.nativeimage.builder/com.oracle.svm.core.jdk=ALL-UNNAMED', '--exclude-config' , - 'io\.netty\.netty-codec', - '/META-INF/native-image/io\.netty/netty-codec/generated/handlers/reflect-config\.json', + 'io\\.netty\\.netty-codec', + '/META-INF/native-image/io\\.netty/netty-codec/generated/handlers/reflect-config\\.json', '--exclude-config', - 'io\.netty\.netty-handler', - '/META-INF/native-image/io\.netty/netty-handler/generated/handlers/reflect-config\.json', + 'io\\.netty\\.netty-handler', + '/META-INF/native-image/io\\.netty/netty-handler/generated/handlers/reflect-config\\.json', '-H:-AddAllCharsets', '-H:+ReportExceptionStackTraces', ] + mx_sdk_vm_impl.svm_experimental_options([ diff --git a/substratevm/CHANGELOG.md b/substratevm/CHANGELOG.md index a925c670defb..e7a6a40047b0 100644 --- a/substratevm/CHANGELOG.md +++ b/substratevm/CHANGELOG.md @@ -6,6 +6,7 @@ This changelog summarizes major changes to GraalVM Native Image. * (GR-48304) Red Hat added support for the JFR event ThreadAllocationStatistics. * (GR-48343) Red Hat added support for the JFR events AllocationRequiringGC and SystemGC. * (GR-48612) Enable `--strict-image-heap` by default. The option is now deprecated and can be removed from your argument list. A blog post with more information will follow shortly. +* (GR-48354) Remove native-image-agent legacy `build`-option ## GraalVM for JDK 21 (Internal Version 23.1.0) * (GR-35746) Lower the default aligned chunk size from 1 MB to 512 KB for the serial and epsilon GCs, reducing memory usage and image size in many cases. diff --git a/substratevm/mx.substratevm/mx_substratevm.py b/substratevm/mx.substratevm/mx_substratevm.py index 9d118dd13a28..87e35f107020 100644 --- a/substratevm/mx.substratevm/mx_substratevm.py +++ b/substratevm/mx.substratevm/mx_substratevm.py @@ -26,8 +26,6 @@ # # ---------------------------------------------------------------------------------------------------- -from __future__ import print_function - import os import re import tempfile @@ -38,6 +36,7 @@ from argparse import ArgumentParser import fnmatch import collections +from io import StringIO import mx import mx_compiler @@ -56,10 +55,6 @@ import sys -if sys.version_info[0] < 3: - from StringIO import StringIO -else: - from io import StringIO suite = mx.suite('substratevm') svmSuites = [suite] @@ -1016,7 +1011,10 @@ def _native_image_launcher_extra_jvm_args(): '--features=com.oracle.svm.driver.APIOptionFeature', '--initialize-at-build-time=com.oracle.svm.driver', '--link-at-build-time=com.oracle.svm.driver,com.oracle.svm.driver.metainf', -] + svm_experimental_options([ +] + +driver_exe_build_args = driver_build_args + svm_experimental_options([ + '-H:+AllowJRTFileSystem', '-H:IncludeResources=com/oracle/svm/driver/launcher/.*', '-H:-ParseRuntimeOptions', f'-R:MaxHeapSize={256 * 1024 * 1024}', @@ -1058,7 +1056,7 @@ def _native_image_launcher_extra_jvm_args(): destination="bin/", jar_distributions=["substratevm:SVM_DRIVER"], main_class=_native_image_launcher_main_class(), - build_args=driver_build_args, + build_args=driver_exe_build_args, extra_jvm_args=_native_image_launcher_extra_jvm_args(), home_finder=False, ), diff --git a/substratevm/mx.substratevm/suite.py b/substratevm/mx.substratevm/suite.py index c2bd3225190b..98b8deb1e711 100644 --- a/substratevm/mx.substratevm/suite.py +++ b/substratevm/mx.substratevm/suite.py @@ -853,6 +853,11 @@ "requires" : [ "jdk.management", ], + "requiresConcealed" : { + "java.base" : [ + "jdk.internal.jimage", + ], + }, "checkstyle": "com.oracle.svm.hosted", "workingSets": "SVM", "annotationProcessors": [ diff --git a/substratevm/src/com.oracle.svm.agent/src/com/oracle/svm/agent/NativeImageAgent.java b/substratevm/src/com.oracle.svm.agent/src/com/oracle/svm/agent/NativeImageAgent.java index 19bbbb5e4d89..1de088372e64 100644 --- a/substratevm/src/com.oracle.svm.agent/src/com/oracle/svm/agent/NativeImageAgent.java +++ b/substratevm/src/com.oracle.svm.agent/src/com/oracle/svm/agent/NativeImageAgent.java @@ -38,7 +38,6 @@ import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; -import java.util.Arrays; import java.util.ConcurrentModificationException; import java.util.Date; import java.util.List; @@ -76,12 +75,10 @@ import com.oracle.svm.configure.filters.HierarchyFilterNode; import com.oracle.svm.configure.trace.AccessAdvisor; import com.oracle.svm.configure.trace.TraceProcessor; -import com.oracle.svm.core.SubstrateUtil; import com.oracle.svm.core.configure.ConfigurationFile; import com.oracle.svm.core.jni.headers.JNIEnvironment; import com.oracle.svm.core.jni.headers.JNIJavaVM; import com.oracle.svm.core.jni.headers.JNIObjectHandle; -import com.oracle.svm.driver.NativeImage; import com.oracle.svm.driver.metainf.NativeImageMetaInfWalker; import com.oracle.svm.jvmtiagentbase.JNIHandleSet; import com.oracle.svm.jvmtiagentbase.JvmtiAgentBase; @@ -143,7 +140,6 @@ protected int onLoadCallback(JNIJavaVM vm, JvmtiEnv jvmti, JvmtiEventCallbacks c boolean experimentalClassDefineSupport = false; boolean experimentalUnsafeAllocationSupport = false; boolean experimentalOmitClasspathConfig = false; - boolean build = false; boolean configurationWithOrigins = false; List conditionalConfigUserPackageFilterFiles = new ArrayList<>(); List conditionalConfigClassNameFilterFiles = new ArrayList<>(); @@ -206,8 +202,6 @@ protected int onLoadCallback(JNIJavaVM vm, JvmtiEnv jvmti, JvmtiEventCallbacks c if (configWritePeriodInitialDelay < 0) { return usage(1, "config-write-initial-delay-secs must be an integer greater or equal to 0"); } - } else if (isBooleanOption(token, "build")) { - build = getBooleanTokenValue(token); } else if (isBooleanOption(token, "experimental-configuration-with-origins")) { configurationWithOrigins = getBooleanTokenValue(token); } else if (token.startsWith("experimental-conditional-config-filter-file=")) { @@ -223,9 +217,9 @@ protected int onLoadCallback(JNIJavaVM vm, JvmtiEnv jvmti, JvmtiEventCallbacks c } } - if (traceOutputFile == null && configOutputDir == null && !build) { + if (traceOutputFile == null && configOutputDir == null) { configOutputDir = transformPath(AGENT_NAME + "_config-pid{pid}-{datetime}/"); - inform("no output/build options provided, tracking dynamic accesses and writing configuration to directory: " + configOutputDir); + inform("no output options provided, tracking dynamic accesses and writing configuration to directory: " + configOutputDir); } if (configurationWithOrigins && !conditionalConfigUserPackageFilterFiles.isEmpty()) { @@ -377,14 +371,6 @@ protected int onLoadCallback(JNIJavaVM vm, JvmtiEnv jvmti, JvmtiEventCallbacks c } } - if (build) { - int status = buildImage(jvmti); - if (status == 0) { - System.exit(status); - } - return status; - } - try { BreakpointInterceptor.onLoad(jvmti, callbacks, tracer, this, interceptedStateSupplier, experimentalClassLoaderSupport, experimentalClassDefineSupport, experimentalUnsafeAllocationSupport, trackReflectionMetadata); @@ -504,46 +490,6 @@ private static void ignoreConfigFromClasspath(JvmtiEnv jvmti, ConfigurationFileC private static final Pattern propertyBlacklist = Pattern.compile("(java\\..*)|(sun\\..*)|(jvmci\\..*)"); private static final Pattern propertyWhitelist = Pattern.compile("(java\\.library\\.path)|(java\\.io\\.tmpdir)"); - private static int buildImage(JvmtiEnv jvmti) { - System.out.println("Building native image ..."); - String classpath = Support.getSystemProperty(jvmti, "java.class.path"); - if (classpath == null) { - return usage(1, "Build mode could not determine classpath."); - } - String javaCommand = Support.getSystemProperty(jvmti, "sun.java.command"); - String mainClassMissing = "Build mode could not determine main class."; - if (javaCommand == null) { - return usage(1, mainClassMissing); - } - String mainClass = SubstrateUtil.split(javaCommand, " ")[0]; - if (mainClass.isEmpty()) { - return usage(1, mainClassMissing); - } - List buildArgs = new ArrayList<>(); - // buildArgs.add("--verbose"); - String[] keys = Support.getSystemProperties(jvmti); - for (String key : keys) { - boolean whitelisted = propertyWhitelist.matcher(key).matches(); - boolean blacklisted = !whitelisted && propertyBlacklist.matcher(key).matches(); - if (blacklisted) { - continue; - } - buildArgs.add("-D" + key + "=" + Support.getSystemProperty(jvmti, key)); - } - if (mainClass.toLowerCase().endsWith(".jar")) { - buildArgs.add("-jar"); - } else { - buildArgs.addAll(Arrays.asList("-cp", classpath)); - } - buildArgs.add(mainClass); - buildArgs.add(AGENT_NAME + ".build"); - // System.out.println(String.join("\n", buildArgs)); - Path javaHome = Paths.get(Support.getSystemProperty(jvmti, "java.home")); - String userDirStr = Support.getSystemProperty(jvmti, "user.dir"); - NativeImage.agentBuild(javaHome, userDirStr == null ? null : Paths.get(userDirStr), buildArgs); - return 0; - } - private static String transformPath(String path) { String result = path; if (result.contains("{pid}")) { 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 a9dd1be14e2a..ea509ef9291f 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 @@ -154,13 +154,10 @@ protected void onValueUpdate(EconomicMap, Object> values, String ol }; @Option(help = "Builds a statically linked executable with libc dynamically linked", type = Expert, stability = OptionStability.EXPERIMENTAL)// - public static final HostedOptionKey StaticExecutableWithDynamicLibC = new HostedOptionKey<>(false) { - @Override - protected void onValueUpdate(EconomicMap, Object> values, Boolean oldValue, Boolean newValue) { - StaticExecutable.update(values, true); - super.onValueUpdate(values, oldValue, newValue); - } - }; + public static final HostedOptionKey StaticExecutableWithDynamicLibC = new HostedOptionKey<>(false); + + @Option(help = "Builds image with libstdc++ statically linked into the image (if needed)", type = Expert, stability = OptionStability.EXPERIMENTAL)// + public static final HostedOptionKey StaticLibStdCpp = new HostedOptionKey<>(false); public static final int ForceFallback = 10; public static final int Automatic = 5; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JRTSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JRTSupport.java index 795cd42e1cd9..a17bbd2e0abd 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JRTSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JRTSupport.java @@ -28,6 +28,7 @@ import java.io.IOException; import java.net.URL; import java.net.URLConnection; +import java.nio.ByteBuffer; import java.nio.file.Path; import java.util.Arrays; import java.util.HashMap; @@ -115,7 +116,7 @@ final class Target_jdk_internal_module_SystemModuleFinders_SystemImage_JRTEnable static volatile Target_jdk_internal_jimage_ImageReader_JRTEnabled READER; @Substitute - static Object reader() { + static Target_jdk_internal_jimage_ImageReader_JRTEnabled reader() { Target_jdk_internal_jimage_ImageReader_JRTEnabled localRef = READER; if (localRef == null) { synchronized (Target_jdk_internal_module_SystemModuleFinders_SystemImage_JRTEnabled.class) { @@ -178,3 +179,22 @@ final class Target_jdk_internal_jrtfs_JrtFileSystemProvider_JRTDisabled { } // endregion Disable jimage/jrtfs + +@TargetClass(className = "jdk.internal.jimage.BasicImageReader") +final class Target_jdk_internal_jimage_BasicImageReader { + /* Ensure NativeImageBuffer never gets used as part of using BasicImageReader */ + @Alias // + @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.FromAlias, isFinal = true) // + // Checkstyle: stop + static boolean USE_JVM_MAP = false; + // Checkstyle: resume +} + +@TargetClass(className = "jdk.internal.jimage.NativeImageBuffer") +@Substitute +final class Target_jdk_internal_jimage_NativeImageBuffer { + @Substitute + static ByteBuffer getNativeMap(String imagePath) { + throw VMError.unsupportedFeature("Using jdk.internal.jimage.NativeImageBuffer is not supported"); + } +} 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 cfa4f4f15caa..98407ad3f4d0 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 @@ -53,7 +53,6 @@ import java.util.List; import java.util.ListIterator; import java.util.Map; -import java.util.Objects; import java.util.Optional; import java.util.Properties; import java.util.Set; @@ -62,7 +61,6 @@ import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.Function; -import java.util.function.Predicate; import java.util.jar.Attributes; import java.util.jar.JarFile; import java.util.jar.Manifest; @@ -106,6 +104,8 @@ import com.oracle.svm.util.ReflectionUtil; import com.oracle.svm.util.StringUtil; +import jdk.internal.jimage.ImageReader; + public class NativeImage { private static final String DEFAULT_GENERATOR_CLASS_NAME = NativeImageGeneratorRunner.class.getName(); @@ -1534,8 +1534,6 @@ protected int buildImage(List javaArgs, LinkedHashSet cp, LinkedHa arguments.addAll(strings); } - String javaExecutable = canonicalize(config.getJavaExecutable()).toString(); - if (useBundle()) { LogUtils.warning("Native Image Bundles are an experimental feature."); } @@ -1548,20 +1546,32 @@ protected int buildImage(List javaArgs, LinkedHashSet cp, LinkedHa List finalImageClassPath = imagecp.stream().map(substituteClassPath).collect(Collectors.toList()); Function substituteModulePath = useBundle() ? bundleSupport::substituteModulePath : Function.identity(); - List substitutedImageModulePath = imagemp.stream().map(substituteModulePath).toList(); + List imageModulePath = imagemp.stream().map(substituteModulePath).collect(Collectors.toList()); + Map applicationModules = getModulesFromPath(imageModulePath); + + if (!applicationModules.isEmpty()) { + // Remove modules that we already have built-in + applicationModules.keySet().removeAll(getBuiltInModules()); + // Remove modules that we get from the builder + applicationModules.keySet().removeAll(getModulesFromPath(mp).keySet()); + } + List finalImageModulePath = applicationModules.values().stream().toList(); - Map modules = listModulesFromPath(javaExecutable, Stream.concat(mp.stream(), imagemp.stream()).distinct().toList()); if (!addModules.isEmpty()) { arguments.add("-D" + ModuleSupport.PROPERTY_IMAGE_EXPLICITLY_ADDED_MODULES + "=" + String.join(",", addModules)); List addModulesForBuilderVM = new ArrayList<>(); - for (String module : addModules) { - Path jarPath = modules.get(module); - if (jarPath == null) { - // boot module - addModulesForBuilderVM.add(module); + for (String moduleNameInAddModules : addModules) { + if (!applicationModules.containsKey(moduleNameInAddModules)) { + /* + * Module names given to native-image --add-modules that are not referring to + * modules that are passed to native-image via -p/--module-path are considered + * to be part of the module-layer that contains the builder itself. Those module + * names need to be passed as --add-modules arguments to the builder VM. + */ + addModulesForBuilderVM.add(moduleNameInAddModules); } } @@ -1580,43 +1590,20 @@ protected int buildImage(List javaArgs, LinkedHashSet cp, LinkedHa arguments.addAll(Arrays.asList(SubstrateOptions.WATCHPID_PREFIX, "" + ProcessProperties.getProcessID())); } - /* - * Workaround for GR-47186: Native image cannot handle modules on the image module path, - * that are also already installed in the JDK as boot module. As a workaround we filter all - * modules from the module-path that are either already installed in the JDK as boot module, - * or were explicitly added to the builder module-path. - * - * First compute all module-jar paths that are not on the builder module-path. - */ - Set nonBuilderModulePaths = modules.values().stream() - .filter(Objects::nonNull) - .filter(Predicate.not(mp::contains)) - .collect(Collectors.toSet()); - - /* - * Now we need to filter the substituted module path list for all the modules that may - * remain on the module-path. - * - * This should normally not be necessary, as the nonBuilderModulePaths should already be the - * set of jar files for the image module path. Nevertheless, we use the original definition - * of the module path to preserve the order of the original module path and as a precaution - * to protect against --list-modules returning too many modules. - */ - List finalImageModulePath = substitutedImageModulePath.stream() - .filter(nonBuilderModulePaths::contains) - .toList(); - List finalImageBuilderArgs = createImageBuilderArgs(finalImageArgs, finalImageClassPath, finalImageModulePath); /* Construct ProcessBuilder command from final arguments */ List command = new ArrayList<>(); List completeCommandList = new ArrayList<>(); + String javaExecutable; if (useBundle() && bundleSupport.useContainer) { ContainerSupport.replacePaths(arguments, config.getJavaHome(), bundleSupport.rootDir); ContainerSupport.replacePaths(finalImageBuilderArgs, config.getJavaHome(), bundleSupport.rootDir); Path binJava = Paths.get("bin", "java"); javaExecutable = ContainerSupport.GRAAL_VM_HOME.resolve(binJava).toString(); + } else { + javaExecutable = canonicalize(config.getJavaExecutable()).toString(); } Path argFile = createVMInvocationArgumentFile(arguments); @@ -1718,65 +1705,34 @@ protected int buildImage(List javaArgs, LinkedHashSet cp, LinkedHa } } - /** - * Resolves and lists all modules given a module path. - * - * @see #callListModules(String, List) - */ - private Map listModulesFromPath(String javaExecutable, Collection modulePath) { - if (modulePath.isEmpty() || !config.modulePathBuild) { - return Map.of(); + private Set getBuiltInModules() { + Path jdkRoot = config.rootDir; + try { + var reader = ImageReader.open(jdkRoot.resolve("lib/modules")); + return new LinkedHashSet<>(List.of(reader.getModuleNames())); + } catch (IOException e) { + throw showError("Unable to determine builtin modules of JDK in " + jdkRoot, e); } - String modulePathEntries = modulePath.stream() - .map(Path::toString) - .collect(Collectors.joining(File.pathSeparator)); - return callListModules(javaExecutable, List.of("-p", modulePathEntries)); } - /** - * Calls java $arguments --list-modules to list all modules and parse the output. - * The output consists of a map with module name as key and {@link Path} to jar file if the - * module is not installed as part of the JDK. If the module is installed as part of the - * jdk/boot-layer then a null path will be returned. - *

- * This is a much more robust solution then trying to parse the JDK file structure manually. - */ - private static Map callListModules(String javaExecutable, List arguments) { - Process listModulesProcess = null; - Map result = new LinkedHashMap<>(); + private Map getModulesFromPath(Collection modulePath) { + if (!config.modulePathBuild || modulePath.isEmpty()) { + return Map.of(); + } + + LinkedHashMap mrefs = new LinkedHashMap<>(); try { - var pb = new ProcessBuilder(javaExecutable); - pb.command().addAll(arguments); - pb.command().add("--list-modules"); - pb.environment().clear(); - listModulesProcess = pb.start(); - - List lines; - try (var br = new BufferedReader(new InputStreamReader(listModulesProcess.getInputStream()))) { - lines = br.lines().toList(); - } - int exitStatus = listModulesProcess.waitFor(); - if (exitStatus != 0) { - throw showError("Determining image-builder observable modules failed (Exit status %d). Process output: %n%s".formatted(exitStatus, String.join(System.lineSeparator(), lines))); - } - for (String line : lines) { - String[] splitString = StringUtil.split(line, " ", 3); - String[] splitModuleNameAndVersion = StringUtil.split(splitString[0], "@", 2); - Path externalPath = null; - if (splitString.length > 1) { - String pathURI = splitString[1]; // url: file://path/to/file - externalPath = Path.of(URI.create(pathURI)).toAbsolutePath(); - } - result.put(splitModuleNameAndVersion[0], externalPath); - } - } catch (IOException | InterruptedException e) { - throw showError(e.getMessage()); - } finally { - if (listModulesProcess != null) { - listModulesProcess.destroy(); + ModuleFinder finder = ModuleFinder.of(modulePath.toArray(Path[]::new)); + for (ModuleReference mref : finder.findAll()) { + String moduleName = mref.descriptor().name(); + VMError.guarantee(moduleName != null && !moduleName.isEmpty(), "Unnamed module on modulePath"); + URI moduleLocation = mref.location().orElseThrow(() -> VMError.shouldNotReachHere("ModuleReference for module " + moduleName + " has no location.")); + mrefs.put(moduleName, Path.of(moduleLocation)); } + } catch (FindException e) { + throw showError("Failed to collect ModuleReferences for module-path entries " + modulePath, e); } - return result; + return mrefs; } /** @@ -1858,14 +1814,6 @@ public static void main(String[] args) { performBuild(new BuildConfiguration(Arrays.asList(args)), defaultNativeImageProvider); } - public static void build(BuildConfiguration config) { - build(config, defaultNativeImageProvider); - } - - public static void agentBuild(Path javaHome, Path workDir, List buildArgs) { - performBuild(new BuildConfiguration(javaHome, workDir, buildArgs), NativeImage::new); - } - public static List translateAPIOptions(List arguments) { var handler = new APIOptionHandler(new NativeImage(new BuildConfiguration(arguments))); var argumentQueue = new ArgumentQueue(OptionOrigin.originDriver); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/CCLinkerInvocation.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/CCLinkerInvocation.java index af8a0291451c..14de7653ec1b 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/CCLinkerInvocation.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/CCLinkerInvocation.java @@ -31,13 +31,11 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; -import com.oracle.svm.core.BuildDirectoryProvider; import org.graalvm.compiler.options.Option; import org.graalvm.compiler.options.OptionStability; import org.graalvm.nativeimage.ImageSingletons; @@ -45,6 +43,7 @@ import com.oracle.objectfile.ObjectFile; import com.oracle.objectfile.macho.MachOSymtab; +import com.oracle.svm.core.BuildDirectoryProvider; import com.oracle.svm.core.LinkerInvocation; import com.oracle.svm.core.OS; import com.oracle.svm.core.SubstrateOptions; @@ -250,8 +249,9 @@ protected List getNativeLinkerOptions() { private static class BinutilsCCLinkerInvocation extends CCLinkerInvocation { - private final boolean staticExecWithDynamicallyLinkLibC = SubstrateOptions.StaticExecutableWithDynamicLibC.getValue(); - private final Set libCLibaries = new HashSet<>(Arrays.asList("pthread", "dl", "rt", "m")); + private final boolean dynamicLibC = SubstrateOptions.StaticExecutableWithDynamicLibC.getValue(); + private final boolean staticLibCpp = SubstrateOptions.StaticLibStdCpp.getValue(); + private final boolean customStaticLibs = dynamicLibC || staticLibCpp; BinutilsCCLinkerInvocation(AbstractImage.NativeImageKind imageKind, NativeLibraries nativeLibs, List symbols) { super(imageKind, nativeLibs, symbols); @@ -314,7 +314,7 @@ protected void setOutputKind(List cmd) { cmd.add("-Wl,--export-dynamic"); break; case STATIC_EXECUTABLE: - if (!staticExecWithDynamicallyLinkLibC) { + if (!customStaticLibs) { cmd.add("-static"); } break; @@ -326,21 +326,32 @@ protected void setOutputKind(List cmd) { } } + private static final Set LIB_C_NAMES = Set.of("pthread", "dl", "rt", "m"); + @Override protected List getLibrariesCommand() { List cmd = new ArrayList<>(); + if (customStaticLibs) { + cmd.add("-Wl,--push-state"); + } for (String lib : libs) { - if (staticExecWithDynamicallyLinkLibC) { - String linkingMode = libCLibaries.contains(lib) - ? "dynamic" - : "static"; + String linkingMode = null; + if (dynamicLibC) { + linkingMode = LIB_C_NAMES.contains(lib) ? "dynamic" : "static"; + } else if (staticLibCpp) { + linkingMode = lib.equals("stdc++") ? "static" : "dynamic"; + } + if (linkingMode != null) { cmd.add("-Wl,-B" + linkingMode); } cmd.add("-l" + lib); } + if (customStaticLibs) { + cmd.add("-Wl,--pop-state"); + } // Make sure libgcc gets statically linked - if (staticExecWithDynamicallyLinkLibC) { + if (customStaticLibs) { cmd.add("-static-libgcc"); } return cmd; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JRTFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JRTFeature.java deleted file mode 100644 index 425aab252ba1..000000000000 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/JRTFeature.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2021, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.svm.hosted.jdk; - -import com.oracle.svm.core.feature.InternalFeature; -import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; -import com.oracle.svm.hosted.FeatureImpl; - -@AutomaticallyRegisteredFeature -public class JRTFeature implements InternalFeature { - - @Override - public void beforeAnalysis(BeforeAnalysisAccess access) { - access.registerReachabilityHandler(duringAnalysisAccess -> { - FeatureImpl.BeforeAnalysisAccessImpl beforeAnalysisAccess = (FeatureImpl.BeforeAnalysisAccessImpl) access; - beforeAnalysisAccess.getNativeLibraries().addStaticJniLibrary("jimage"); - beforeAnalysisAccess.getNativeLibraries().addDynamicNonJniLibrary("stdc++"); - }, access.findClassByName("jdk.internal.jimage.NativeImageBuffer")); - } -}