Skip to content

Commit

Permalink
[GR-39407] Add support for NATIVE_IMAGE_OPTIONS environment variable.
Browse files Browse the repository at this point in the history
PullRequest: graal/15786
  • Loading branch information
fniephaus committed Nov 6, 2023
2 parents 902dba9 + ae2de06 commit ebc75fa
Show file tree
Hide file tree
Showing 11 changed files with 226 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -83,22 +83,24 @@ protected void verify(StructuredGraph graph, CoreProviders context) {
ResolvedJavaType nodeType = metaAccess.lookupJavaType(Node.class);
ResolvedJavaType stringType = metaAccess.lookupJavaType(String.class);
ResolvedJavaType graalErrorType = metaAccess.lookupJavaType(GraalError.class);
ResolvedJavaType errorType = metaAccess.lookupJavaType(Error.class);

for (MethodCallTargetNode t : graph.getNodes(MethodCallTargetNode.TYPE)) {
ResolvedJavaMethod callee = t.targetMethod();
String calleeName = callee.getName();
if (callee.getDeclaringClass().equals(debugType)) {
ResolvedJavaType calleeDeclaringClass = callee.getDeclaringClass();
if (calleeDeclaringClass.equals(debugType)) {
boolean isDump = calleeName.equals("dump");
if (calleeName.equals("log") || calleeName.equals("logAndIndent") || calleeName.equals("verify") || isDump) {
verifyParameters(metaAccess, t, t.arguments(), stringType, isDump ? 2 : 1);
}
}
if (callee.getDeclaringClass().isAssignableFrom(nodeType)) {
if (calleeDeclaringClass.isAssignableFrom(nodeType)) {
if (calleeName.equals("assertTrue") || calleeName.equals("assertFalse")) {
verifyParameters(metaAccess, t, t.arguments(), stringType, 1);
}
}
if (callee.getDeclaringClass().isAssignableFrom(graalErrorType) && !graph.method().getDeclaringClass().isAssignableFrom(graalErrorType)) {
if (calleeDeclaringClass.isAssignableFrom(graalErrorType) && !calleeDeclaringClass.equals(errorType) && !graph.method().getDeclaringClass().isAssignableFrom(graalErrorType)) {
if (calleeName.equals("guarantee")) {
verifyParameters(metaAccess, t, t.arguments(), stringType, 0);
}
Expand Down
6 changes: 6 additions & 0 deletions docs/reference-manual/native-image/BuildOutput.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,12 @@ A list of all active experimental options, including their origin and possible A
Using experimental options should be avoided in production and can change in any release.
If you rely on experimental features and would like an option to be considered stable, please file an issue.
#### <a name="glossary-picked-up-ni-options"></a>Picked up `NATIVE_IMAGE_OPTIONS`
Additional build options picked up via the `NATIVE_IMAGE_OPTIONS` environment variable.
Similar to `JAVA_TOOL_OPTIONS`, the value of the environment variable is prepended to the options supplied to `native-image`.
Argument files are not allowed to be passed via `NATIVE_IMAGE_OPTIONS`.
The `NATIVE_IMAGE_OPTIONS` environment variable is designed to be used by users, build environments, or tools to inject additional build options.
#### <a name="glossary-build-resources"></a>Build Resources
The memory limit and number of threads used by the build process.
Expand Down
1 change: 1 addition & 0 deletions substratevm/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ This changelog summarizes major changes to GraalVM Native Image.
* (GR-48354) Remove native-image-agent legacy `build`-option
* (GR-49221) Support for thread dumps can now be enabled with `--enable-monitoring=threaddump`. The option `-H:±DumpThreadStacksOnSignal` is deprecated and marked for removal.
* (GR-48579) Options ParseOnce, ParseOnceJIT, and InlineBeforeAnalysis are deprecated and no longer have any effect.
* (GR-39407) Add support for the `NATIVE_IMAGE_OPTIONS` environment variable, which allows users and tools to pass additional arguments via the environment. Similar to `JAVA_TOOL_OPTIONS`, the value of the environment variable is prepended to the options supplied to `native-image`.

## 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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,11 @@ public static final boolean hasColorsEnabled(OptionValues values) {
"docs/reference-manual/native-image/assets/build-output-schema-v0.9.2.json", type = OptionType.User)//
public static final HostedOptionKey<LocatableMultiOptionValue.Paths> BuildOutputJSONFile = new HostedOptionKey<>(LocatableMultiOptionValue.Paths.build());

public static final String NATIVE_IMAGE_OPTIONS_ENV_VAR = "NATIVE_IMAGE_OPTIONS";

@Option(help = "Internal option to forward the value of " + NATIVE_IMAGE_OPTIONS_ENV_VAR)//
public static final HostedOptionKey<String> BuildOutputNativeImageOptionsEnvVarValue = new HostedOptionKey<>(null);

/*
* Object and array allocation options.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ boolean consume(ArgumentQueue args) {
String translatedOption = translateOption(args);
if (translatedOption != null) {
args.poll();
nativeImage.addPlainImageBuilderArg(NativeImage.injectHostedOptionOrigin(translatedOption, args.argumentOrigin + OptionOrigin.isAPISuffix));
nativeImage.addPlainImageBuilderArg(translatedOption, args.argumentOrigin + OptionOrigin.isAPISuffix);
return true;
}
if (ENTER_UNLOCK_SCOPE.equals(headArg)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,21 +33,28 @@
import java.util.List;
import java.util.Objects;

class ArgFilesOptionPreprocessor {
import com.oracle.svm.hosted.util.JDKArgsUtils;

public class ArgFilesOptionPreprocessor {

private static final String DISABLE_AT_FILES_OPTION = "--disable-@files";

private boolean disableAtFiles = false;

public List<String> process(String currentArg) {
switch (currentArg) {
case DISABLE_AT_FILES_OPTION:
disableAtFiles = true;
return List.of();
String argWithoutQuotes = currentArg.replaceAll("['\"]*", "");
if (DISABLE_AT_FILES_OPTION.equals(argWithoutQuotes)) {
disableAtFiles = true;
return List.of();
}

if (!disableAtFiles && currentArg.startsWith("@")) {
Path argFile = Paths.get(currentArg.substring(1));
if (!disableAtFiles && argWithoutQuotes.startsWith("@")) {
String argWithoutAt = argWithoutQuotes.substring(1);
if (argWithoutAt.startsWith("@")) {
// escaped @argument
return List.of(argWithoutAt);
}
Path argFile = Paths.get(argWithoutAt);
return readArgFile(argFile);
}

Expand Down Expand Up @@ -130,7 +137,7 @@ private static String nextToken(CTX_ARGS ctx) {

// Skip white space characters
if (ctx.state == PARSER_STATE.FIND_NEXT || ctx.state == PARSER_STATE.SKIP_LEAD_WS) {
while (ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t' || ch == '\f') {
while (JDKArgsUtils.isspace(ch)) {
nextc++;
if (nextc >= eob) {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,15 @@
import java.util.Optional;
import java.util.regex.Pattern;

import jdk.graal.compiler.options.OptionType;

import com.oracle.svm.core.VM;
import com.oracle.svm.core.option.OptionOrigin;
import com.oracle.svm.core.option.OptionUtils;
import com.oracle.svm.core.util.ExitStatus;
import com.oracle.svm.driver.NativeImage.ArgumentQueue;
import com.oracle.svm.util.LogUtils;

import jdk.graal.compiler.options.OptionType;

class CmdLineOptionHandler extends NativeImage.OptionHandler<NativeImage> {

private static final String HELP_TEXT = NativeImage.getResource("/Help.txt");
Expand Down Expand Up @@ -167,7 +167,7 @@ private boolean consume(ArgumentQueue args, String headArg) {
/* Using agentlib to allow interoperability with other agents */
nativeImage.addImageBuilderJavaArgs("-agentlib:jdwp=transport=dt_socket,server=y,address=" + address + ",suspend=y");
/* Disable watchdog mechanism */
nativeImage.addPlainImageBuilderArg(NativeImage.injectHostedOptionOrigin(nativeImage.oHDeadlockWatchdogInterval + "0", OptionOrigin.originDriver));
nativeImage.addPlainImageBuilderArg(nativeImage.oHDeadlockWatchdogInterval + "0", OptionOrigin.originDriver);
return true;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,9 @@ public boolean consume(ArgumentQueue args) {
}
String[] mainClassModuleArgParts = mainClassModuleArg.split("/", 2);
if (mainClassModuleArgParts.length > 1) {
nativeImage.addPlainImageBuilderArg(NativeImage.injectHostedOptionOrigin(nativeImage.oHClass + mainClassModuleArgParts[1], OptionOrigin.originDriver));
nativeImage.addPlainImageBuilderArg(nativeImage.oHClass + mainClassModuleArgParts[1], OptionOrigin.originDriver);
}
nativeImage.addPlainImageBuilderArg(NativeImage.injectHostedOptionOrigin(nativeImage.oHModule + mainClassModuleArgParts[0], OptionOrigin.originDriver));
nativeImage.addPlainImageBuilderArg(nativeImage.oHModule + mainClassModuleArgParts[0], OptionOrigin.originDriver);
nativeImage.setModuleOptionMode(true);
return true;
case addModulesOption:
Expand Down Expand Up @@ -152,7 +152,7 @@ public boolean consume(ArgumentQueue args) {
}
if (headArg.startsWith(NativeImage.oH)) {
args.poll();
nativeImage.addPlainImageBuilderArg(NativeImage.injectHostedOptionOrigin(headArg, args.argumentOrigin));
nativeImage.addPlainImageBuilderArg(headArg, args.argumentOrigin);
return true;
}
if (headArg.startsWith(NativeImage.oR)) {
Expand Down Expand Up @@ -252,7 +252,7 @@ private void handleJarFileArg(Path jarFilePath) {
}
if (!jarFileNameBase.isEmpty()) {
String origin = "manifest from " + jarFilePath.toUri();
nativeImage.addPlainImageBuilderArg(NativeImage.injectHostedOptionOrigin(nativeImage.oHName + jarFileNameBase, origin));
nativeImage.addPlainImageBuilderArg(nativeImage.oHName + jarFileNameBase, origin);
}
Path finalFilePath = nativeImage.useBundle() ? nativeImage.bundleSupport.substituteClassPath(jarFilePath) : jarFilePath;
if (!NativeImage.processJarManifestMainAttributes(finalFilePath, nativeImage::handleManifestFileAttributes)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,6 @@
import java.util.stream.Collectors;
import java.util.stream.Stream;

import jdk.graal.compiler.options.OptionKey;
import jdk.graal.compiler.serviceprovider.JavaVersionUtil;
import org.graalvm.nativeimage.Platform;
import org.graalvm.nativeimage.ProcessProperties;

Expand Down Expand Up @@ -98,11 +96,14 @@
import com.oracle.svm.driver.metainf.NativeImageMetaInfWalker;
import com.oracle.svm.hosted.NativeImageGeneratorRunner;
import com.oracle.svm.hosted.NativeImageSystemClassLoader;
import com.oracle.svm.hosted.util.JDKArgsUtils;
import com.oracle.svm.util.LogUtils;
import com.oracle.svm.util.ModuleSupport;
import com.oracle.svm.util.ReflectionUtil;
import com.oracle.svm.util.StringUtil;

import jdk.graal.compiler.options.OptionKey;
import jdk.graal.compiler.serviceprovider.JavaVersionUtil;
import jdk.internal.jimage.ImageReader;

public class NativeImage {
Expand Down Expand Up @@ -261,6 +262,7 @@ private static <T> String oR(OptionKey<T> option) {
final String oHCLibraryPath = oH(SubstrateOptions.CLibraryPath);
final String oHFallbackThreshold = oH(SubstrateOptions.FallbackThreshold);
final String oHFallbackExecutorJavaArg = oH(FallbackExecutor.Options.FallbackExecutorJavaArg);
final String oHNativeImageOptionsEnvVar = oH(SubstrateOptions.BuildOutputNativeImageOptionsEnvVarValue, OptionOrigin.originDriver);
final String oRRuntimeJavaArg = oR(Options.FallbackExecutorRuntimeJavaArg);
final String oHTraceClassInitialization = oH(SubstrateOptions.TraceClassInitialization);
final String oHTraceObjectInstantiation = oH(SubstrateOptions.TraceObjectInstantiation);
Expand Down Expand Up @@ -687,7 +689,7 @@ public boolean processMetaInfResource(Path classpathEntry, Path resourceRoot, Pa
if (isNativeImagePropertiesFile) {
String imageNameValue = properties.get("ImageName");
if (imageNameValue != null) {
addPlainImageBuilderArg(injectHostedOptionOrigin(oHName + resolver.apply(imageNameValue), resourcePath.toUri().toString()));
addPlainImageBuilderArg(oHName + resolver.apply(imageNameValue), resourcePath.toUri().toString());
}
forEachPropertyValue(properties.get("JavaArgs"), NativeImage.this::addImageBuilderJavaArgs, resolver);
forEachPropertyValue(properties.get("Args"), args, resolver);
Expand Down Expand Up @@ -826,7 +828,7 @@ protected NativeImage(BuildConfiguration config) {
}

// Generate images into the current directory
addPlainImageBuilderArg(injectHostedOptionOrigin(oHPath + config.getWorkingDirectory(), OptionOrigin.originDriver));
addPlainImageBuilderArg(oHPath + config.getWorkingDirectory(), OptionOrigin.originDriver);

/* Discover supported MacroOptions */
optionRegistry = new MacroOption.Registry();
Expand Down Expand Up @@ -854,13 +856,23 @@ protected void registerOptionHandler(OptionHandler<? extends NativeImage> handle
}

private List<String> getDefaultNativeImageArgs() {
String defaultNativeImageArgs = userConfigProperties.get("NativeImageArgs");
if (defaultNativeImageArgs != null && !defaultNativeImageArgs.isEmpty()) {
String optionName = BundleSupport.BundleOptionVariants.apply.optionName();
if (config.getBuildArgs().stream().noneMatch(arg -> arg.startsWith(optionName + "="))) {
return List.of(defaultNativeImageArgs.split(" "));
List<String> defaultNativeImageArgs = new ArrayList<>();
String propertyOptions = userConfigProperties.get("NativeImageArgs");
if (propertyOptions != null) {
Collections.addAll(defaultNativeImageArgs, propertyOptions.split(" "));
}
final String envVarName = SubstrateOptions.NATIVE_IMAGE_OPTIONS_ENV_VAR;
String nativeImageOptionsValue = System.getenv(envVarName);
if (nativeImageOptionsValue != null) {
addPlainImageBuilderArg(oHNativeImageOptionsEnvVar + nativeImageOptionsValue);
defaultNativeImageArgs.addAll(JDKArgsUtils.parseArgsFromEnvVar(nativeImageOptionsValue, envVarName, msg -> showError(msg)));
}
if (!defaultNativeImageArgs.isEmpty()) {
String buildApplyOptionName = BundleSupport.BundleOptionVariants.apply.optionName();
if (config.getBuildArgs().stream().noneMatch(arg -> arg.startsWith(buildApplyOptionName + "="))) {
return List.copyOf(defaultNativeImageArgs);
} else {
LogUtils.warning("Option " + optionName + " in use. Ignoring args from file specified with environment variable " + NativeImage.CONFIG_FILE_ENV_VAR_KEY + ".");
LogUtils.warning("Option " + buildApplyOptionName + " in use. Ignoring args from file specified with environment variable " + NativeImage.CONFIG_FILE_ENV_VAR_KEY + ".");
}
}
return List.of();
Expand Down Expand Up @@ -907,7 +919,7 @@ private void completeOptionArgs() {
LinkedHashSet<EnabledOption> enabledOptions = optionRegistry.getEnabledOptions();
/* Any use of MacroOptions opts-out of auto-fallback and activates --no-fallback */
if (!enabledOptions.isEmpty()) {
addPlainImageBuilderArg(injectHostedOptionOrigin(oHFallbackThreshold + SubstrateOptions.NoFallback, OptionOrigin.originDriver));
addPlainImageBuilderArg(oHFallbackThreshold + SubstrateOptions.NoFallback, OptionOrigin.originDriver);
}
consolidateListArgs(imageBuilderJavaArgs, "-Dpolyglot.engine.PreinitializeContexts=", ",", Function.identity()); // legacy
consolidateListArgs(imageBuilderJavaArgs, "-Dpolyglot.image-build-time.PreinitializeContexts=", ",", Function.identity());
Expand Down Expand Up @@ -950,7 +962,7 @@ public void addExcludeConfig(Pattern jarPattern, Pattern resourcePattern) {
excludedConfigs.add(new ExcludeConfig(jarPattern, resourcePattern));
}

static String injectHostedOptionOrigin(String option, String origin) {
private static String injectHostedOptionOrigin(String option, String origin) {
if (origin != null && option.startsWith(oH)) {
String optionOriginSeparator = "@";
int eqIndex = option.indexOf('=');
Expand Down Expand Up @@ -996,7 +1008,7 @@ void handleMainClassAttribute(Path jarFilePath, Attributes mainAttributes) {
NativeImage.showError("No main manifest attribute, in " + jarFilePath);
}
String origin = "manifest from " + jarFilePath.toUri();
addPlainImageBuilderArg(NativeImage.injectHostedOptionOrigin(oHClass + mainClassValue, origin));
addPlainImageBuilderArg(oHClass + mainClassValue, origin);
}

void handleModuleAttributes(Attributes mainAttributes) {
Expand Down Expand Up @@ -1986,6 +1998,10 @@ List<String> apply(boolean strict) {
}
}

void addPlainImageBuilderArg(String plainArg, String origin) {
addPlainImageBuilderArg(injectHostedOptionOrigin(plainArg, origin));
}

void addPlainImageBuilderArg(String plainArg) {
assert plainArg.startsWith(NativeImage.oH) || plainArg.startsWith(NativeImage.oR);
imageBuilderArgs.add(plainArg);
Expand Down Expand Up @@ -2320,15 +2336,15 @@ private boolean configureBuildOutput() {
useColorfulOutput = true;
} else if ("auto".equals(colorValue)) {
useColorfulOutput = hasColorSupport();
addPlainImageBuilderArg(injectHostedOptionOrigin(oHColor + (useColorfulOutput ? "always" : "never"), OptionOrigin.originDriver));
addPlainImageBuilderArg(oHColor + (useColorfulOutput ? "always" : "never"), OptionOrigin.originDriver);
}
} else {
Boolean buildOutputColorfulValue = getHostedOptionFinalBooleanArgumentValue(imageBuilderArgs, SubstrateOptions.BuildOutputColorful);
if (buildOutputColorfulValue != null) {
useColorfulOutput = buildOutputColorfulValue; // use value set by user
} else if (hasColorSupport()) {
useColorfulOutput = true;
addPlainImageBuilderArg(injectHostedOptionOrigin(oHColor + "always", OptionOrigin.originDriver));
addPlainImageBuilderArg(oHColor + "always", OptionOrigin.originDriver);
}
}
if (getHostedOptionFinalBooleanArgumentValue(imageBuilderArgs, SubstrateOptions.BuildOutputProgress) == null && hasProgressSupport(imageBuilderArgs)) {
Expand Down
Loading

0 comments on commit ebc75fa

Please sign in to comment.