Skip to content

Commit

Permalink
Add add_exports and add_opens to java_ rules
Browse files Browse the repository at this point in the history
e.g.

```
java_library(
    ...
    add_exports = [
        "--add-exports=jdk.compiler/com.sun.tools.javac.api",
    ],
)
```

At compile-time the attributes correspond to javac's `--add-exports=` and
`--add-opens=` flags, to allow code in the unnamed module to access the given
packages.

At runtime the the attributes correspond to the similar runtime flags. They
are set in the stub script, and recorded as `Add-Exports:` and `Add-Opens:`
entries in the deploy jar's `MANIFEST.MF`.

PiperOrigin-RevId: 448039045
  • Loading branch information
cushon authored and copybara-github committed May 11, 2022
1 parent 11ec226 commit 2217b13
Show file tree
Hide file tree
Showing 19 changed files with 313 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ java_library(
"//src/main/java/com/google/devtools/build/lib/rules/cpp",
"//src/main/java/com/google/devtools/build/lib/rules/java:java-compilation",
"//src/main/java/com/google/devtools/build/lib/shell",
"//src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec",
"//src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec:serialization-constant",
"//src/main/java/com/google/devtools/build/lib/util",
"//src/main/java/com/google/devtools/build/lib/util:os",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -571,7 +571,9 @@ public CustomCommandLine buildSingleJarCommandLine(
boolean multiReleaseDeployJars,
PathFragment javaHome,
Artifact libModules,
NestedSet<Artifact> hermeticInputs) {
NestedSet<Artifact> hermeticInputs,
NestedSet<String> addExports,
NestedSet<String> addOpens) {
return DeployArchiveBuilder.defaultSingleJarCommandLineWithoutOneVersion(
output,
mainClass,
Expand All @@ -585,7 +587,9 @@ public CustomCommandLine buildSingleJarCommandLine(
/* multiReleaseDeployJars= */ multiReleaseDeployJars,
javaHome,
libModules,
hermeticInputs)
hermeticInputs,
addExports,
addOpens)
.build();
}

Expand Down
2 changes: 2 additions & 0 deletions src/main/java/com/google/devtools/build/lib/rules/java/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ java_library(
"//src/main/java/com/google/devtools/build/lib/util",
"//src/main/java/com/google/devtools/build/lib/util:filetype",
"//src/main/java/com/google/devtools/build/lib/util:os",
"//src/main/java/com/google/devtools/build/lib/util:string",
"//src/main/java/com/google/devtools/build/lib/vfs",
"//src/main/java/com/google/devtools/build/lib/vfs:pathfragment",
"//src/main/java/net/starlark/java/eval",
Expand Down Expand Up @@ -134,6 +135,7 @@ java_library(
"JavaInfo.java",
"JavaInfoBuildHelper.java",
"JavaLibraryHelper.java",
"JavaModuleFlagsProvider.java",
"JavaOptions.java",
"JavaPackageConfigurationProvider.java",
"JavaPluginInfo.java",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ public class DeployArchiveBuilder {
@Nullable private PathFragment javaHome;
@Nullable private Artifact libModules;
private NestedSet<Artifact> hermeticInputs = NestedSetBuilder.emptySet(Order.STABLE_ORDER);
private NestedSet<String> addExports;
private NestedSet<String> addOpens;

/** Type of compression to apply to output archive. */
public enum Compression {
Expand Down Expand Up @@ -201,6 +203,16 @@ public DeployArchiveBuilder setHermeticInputs(NestedSet<Artifact> hermeticInputs
return this;
}

public DeployArchiveBuilder setAddExports(NestedSet<String> addExports) {
this.addExports = addExports;
return this;
}

public DeployArchiveBuilder setAddOpens(NestedSet<String> addOpens) {
this.addOpens = addOpens;
return this;
}

public static CustomCommandLine.Builder defaultSingleJarCommandLineWithoutOneVersion(
Artifact outputJar,
String javaMainClass,
Expand All @@ -214,7 +226,9 @@ public static CustomCommandLine.Builder defaultSingleJarCommandLineWithoutOneVer
boolean multiReleaseDeployJars,
PathFragment javaHome,
Artifact libModules,
NestedSet<Artifact> hermeticInputs) {
NestedSet<Artifact> hermeticInputs,
NestedSet<String> addExports,
NestedSet<String> addOpens) {
return defaultSingleJarCommandLine(
outputJar,
javaMainClass,
Expand All @@ -230,7 +244,9 @@ public static CustomCommandLine.Builder defaultSingleJarCommandLineWithoutOneVer
/* multiReleaseDeployJars= */ multiReleaseDeployJars,
javaHome,
libModules,
hermeticInputs);
hermeticInputs,
addExports,
addOpens);
}

public static CustomCommandLine.Builder defaultSingleJarCommandLine(
Expand All @@ -248,7 +264,9 @@ public static CustomCommandLine.Builder defaultSingleJarCommandLine(
boolean multiReleaseDeployJars,
PathFragment javaHome,
Artifact libModules,
NestedSet<Artifact> hermeticInputs) {
NestedSet<Artifact> hermeticInputs,
NestedSet<String> addExports,
NestedSet<String> addOpens) {

CustomCommandLine.Builder args = CustomCommandLine.builder();
args.addExecPath("--output", outputJar);
Expand Down Expand Up @@ -298,6 +316,8 @@ public static CustomCommandLine.Builder defaultSingleJarCommandLine(
args.addPath("--hermetic_java_home", javaHome);
args.addExecPath("--jdk_lib_modules", libModules);
args.addExecPaths("--resources", hermeticInputs);
args.addAll("--add_exports", addExports);
args.addAll("--add_opens", addOpens);
return args;
}

Expand Down Expand Up @@ -414,7 +434,9 @@ public void build() throws InterruptedException {
/* multiReleaseDeployJars= */ multiReleaseDeployJars,
javaHome,
libModules,
hermeticInputs);
hermeticInputs,
addExports,
addOpens);
if (checkDesugarDeps) {
commandLine = CommandLine.concat(commandLine, ImmutableList.of("--check_desugar_deps"));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.actions.ExecutionRequirements;
import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
import com.google.devtools.build.lib.analysis.Allowlist;
import com.google.devtools.build.lib.analysis.AnalysisUtils;
import com.google.devtools.build.lib.analysis.ConfiguredTarget;
import com.google.devtools.build.lib.analysis.OutputGroupInfo;
Expand Down Expand Up @@ -70,6 +71,7 @@
import com.google.devtools.build.lib.rules.java.proto.GeneratedExtensionRegistryProvider;
import com.google.devtools.build.lib.util.OS;
import com.google.devtools.build.lib.util.Pair;
import com.google.devtools.build.lib.util.StringCanonicalizer;
import com.google.devtools.build.lib.vfs.FileSystemUtils;
import com.google.devtools.build.lib.vfs.PathFragment;
import java.util.ArrayList;
Expand Down Expand Up @@ -122,6 +124,17 @@ public ConfiguredTarget create(RuleContext ruleContext)
ruleContext.ruleError("launcher specified but use_launcher is false");
}

if (ruleContext.attributes().isAttributeValueExplicitlySpecified("add_exports")
&& Allowlist.hasAllowlist(ruleContext, "java_add_exports_allowlist")
&& !Allowlist.isAvailable(ruleContext, "java_add_exports_allowlist")) {
ruleContext.ruleError("setting add_exports is not permitted");
}
if (ruleContext.attributes().isAttributeValueExplicitlySpecified("add_opens")
&& Allowlist.hasAllowlist(ruleContext, "java_add_opens_allowlist")
&& !Allowlist.isAvailable(ruleContext, "java_add_opens_allowlist")) {
ruleContext.ruleError("setting add_opens is not permitted");
}

semantics.checkRule(ruleContext, common);
semantics.checkForProtoLibraryAndJavaProtoLibraryOnSameProto(ruleContext, common);
String mainClass = semantics.getMainClass(ruleContext, common.getSrcsArtifacts());
Expand Down Expand Up @@ -264,6 +277,19 @@ public ConfiguredTarget create(RuleContext ruleContext)

Iterables.addAll(
jvmFlags, semantics.getJvmFlags(ruleContext, common.getSrcsArtifacts(), userJvmFlags));

JavaModuleFlagsProvider javaModuleFlagsProvider =
JavaModuleFlagsProvider.create(
ruleContext,
JavaInfo.getProvidersFromListOfTargets(
JavaModuleFlagsProvider.class, common.targetsTreatedAsDeps(ClasspathType.BOTH))
.stream());

javaModuleFlagsProvider.toFlags().stream()
// Share strings in the heap with the equivalent javacopt flags, which are also interned
.map(StringCanonicalizer::intern)
.forEach(jvmFlags::add);

if (ruleContext.hasErrors()) {
return null;
}
Expand Down Expand Up @@ -419,6 +445,8 @@ public ConfiguredTarget create(RuleContext ruleContext)
JavaToolchainProvider.from(ruleContext).getOneVersionAllowlist())
.setMultiReleaseDeployJars(javaConfig.multiReleaseDeployJars())
.setSharedArchive(jsa)
.setAddExports(javaModuleFlagsProvider.addExports())
.setAddOpens(javaModuleFlagsProvider.addOpens())
.build();

Artifact unstrippedDeployJar =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Stream;
import javax.annotation.Nullable;

/** A helper class to create configured targets for Java rules. */
Expand Down Expand Up @@ -346,10 +347,15 @@ private ImmutableList<String> computeJavacOpts(Collection<String> extraRuleJavac
.addAll(javaToolchain.getJavacOptions(ruleContext))
.addAll(extraRuleJavacOpts)
.addAll(computePerPackageJavacOpts(ruleContext, javaToolchain))
.addAll(addModuleJavacopts(ruleContext))
.addAll(ruleContext.getExpander().withDataLocations().tokenized("javacopts"))
.build();
}

private static ImmutableList<String> addModuleJavacopts(RuleContext ruleContext) {
return JavaModuleFlagsProvider.create(ruleContext, Stream.empty()).toFlags();
}

/** Returns the per-package configured javacopts. */
public static ImmutableList<String> computePerPackageJavacOpts(
RuleContext ruleContext, JavaToolchainProvider toolchain) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import com.google.devtools.build.lib.starlarkbuildapi.FileApi;
import com.google.devtools.build.lib.starlarkbuildapi.cpp.CcInfoApi;
import com.google.devtools.build.lib.starlarkbuildapi.java.JavaInfoApi;
import com.google.devtools.build.lib.starlarkbuildapi.java.JavaModuleFlagsProviderApi;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
Expand Down Expand Up @@ -76,7 +77,8 @@ private static <T> T nullIfNone(Object object, Class<T> type) {
JavaRuleOutputJarsProvider.class,
JavaGenJarsProvider.class,
JavaCompilationInfoProvider.class,
JavaCcInfoProvider.class);
JavaCcInfoProvider.class,
JavaModuleFlagsProvider.class);

private final TransitiveInfoProviderMap providers;

Expand Down Expand Up @@ -405,6 +407,14 @@ public CcInfoApi<Artifact> getCcLinkParamInfo() {
return javaCcInfoProvider != null ? javaCcInfoProvider.getCcInfo() : CcInfo.EMPTY;
}

@Override
public JavaModuleFlagsProviderApi getJavaModuleFlagsInfo() {
JavaModuleFlagsProvider javaModuleFlagsProvider = getProvider(JavaModuleFlagsProvider.class);
return javaModuleFlagsProvider == null
? JavaModuleFlagsProvider.EMPTY
: javaModuleFlagsProvider;
}

@Override
public JavaPluginData plugins() {
JavaPluginInfo javaPluginInfo = getJavaPluginInfo();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,12 @@ private Stream<NestedSet<Artifact>> fetchSourceJars(Iterable<JavaInfo> javaInfos
return concat(transitiveSourceJars, sourceJars);
}

private static JavaModuleFlagsProvider createJavaModuleFlagsProvider(
List<String> addExports, List<String> addOpens, Iterable<JavaInfo> transitiveDeps) {
return JavaModuleFlagsProvider.create(
addExports, addOpens, streamProviders(transitiveDeps, JavaModuleFlagsProvider.class));
}

private JavaPluginInfo mergeExportedJavaPluginInfo(
Iterable<JavaPluginInfo> plugins, Iterable<JavaInfo> javaInfos) {
return JavaPluginInfo.mergeWithoutJavaOutputs(
Expand Down Expand Up @@ -260,6 +266,8 @@ public JavaInfo createJavaCompileAction(
boolean createOutputSourceJar,
JavaSemantics javaSemantics,
Object injectingRuleKind,
List<String> addExports,
List<String> addOpens,
StarlarkThread thread)
throws EvalException, InterruptedException {

Expand All @@ -284,6 +292,7 @@ public JavaInfo createJavaCompileAction(
.addAll(
JavaCommon.computePerPackageJavacOpts(
starlarkRuleContext.getRuleContext(), toolchainProvider))
.addAll(JavaModuleFlagsProvider.toFlags(addExports, addOpens))
.addAll(tokenize(javacOpts))
.build());

Expand Down Expand Up @@ -353,6 +362,9 @@ public JavaInfo createJavaCompileAction(
.addProvider(JavaRuleOutputJarsProvider.class, outputJarsBuilder.build())
.javaPluginInfo(mergeExportedJavaPluginInfo(exportedPlugins, exports))
.addProvider(JavaCcInfoProvider.class, JavaCcInfoProvider.merge(transitiveNativeLibraries))
.addProvider(
JavaModuleFlagsProvider.class,
createJavaModuleFlagsProvider(addExports, addOpens, concat(runtimeDeps, exports, deps)))
.setNeverlink(neverlink)
.build();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// Copyright 2022 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.devtools.build.lib.rules.java;

import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.devtools.build.lib.packages.Type.STRING_LIST;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.Streams;
import com.google.devtools.build.lib.analysis.RuleContext;
import com.google.devtools.build.lib.analysis.TransitiveInfoProvider;
import com.google.devtools.build.lib.collect.nestedset.Depset;
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
import com.google.devtools.build.lib.collect.nestedset.Order;
import com.google.devtools.build.lib.packages.AttributeMap;
import com.google.devtools.build.lib.starlarkbuildapi.java.JavaModuleFlagsProviderApi;
import java.util.List;
import java.util.stream.Stream;

/**
* Provides information about {@code --add-exports=} and {@code --add-opens=} flags for Java
* targets.
*/
final class JavaModuleFlagsProvider implements TransitiveInfoProvider, JavaModuleFlagsProviderApi {

private final NestedSet<String> addExports;
private final NestedSet<String> addOpens;

public NestedSet<String> addExports() {
return addExports;
}

public NestedSet<String> addOpens() {
return addOpens;
}

@Override
public Depset /*String*/ getAddExports() {
return Depset.of(Depset.ElementType.STRING, addExports);
}

@Override
public Depset /*String*/ getAddOpens() {
return Depset.of(Depset.ElementType.STRING, addOpens);
}

public JavaModuleFlagsProvider(NestedSet<String> addExports, NestedSet<String> addOpens) {
this.addExports = addExports;
this.addOpens = addOpens;
}

public static final JavaModuleFlagsProvider EMPTY =
new JavaModuleFlagsProvider(
NestedSetBuilder.emptySet(Order.STABLE_ORDER),
NestedSetBuilder.emptySet(Order.STABLE_ORDER));

public static JavaModuleFlagsProvider create(
List<String> addExports, List<String> addOpens, Stream<JavaModuleFlagsProvider> transitive) {
NestedSetBuilder<String> addExportsBuilder = NestedSetBuilder.stableOrder();
NestedSetBuilder<String> addOpensBuilder = NestedSetBuilder.stableOrder();
addExportsBuilder.addAll(addExports);
addOpensBuilder.addAll(addOpens);
transitive.forEach(
provider -> {
addExportsBuilder.addTransitive(provider.addExports());
addOpensBuilder.addTransitive(provider.addOpens());
});
if (addExportsBuilder.isEmpty() && addOpensBuilder.isEmpty()) {
return EMPTY;
}
return new JavaModuleFlagsProvider(addExportsBuilder.build(), addOpensBuilder.build());
}

public static JavaModuleFlagsProvider create(
RuleContext ruleContext, Stream<JavaModuleFlagsProvider> transitive) {
AttributeMap attributes = ruleContext.attributes();
return create(
attributes.getOrDefault("add_exports", STRING_LIST, ImmutableList.of()),
attributes.getOrDefault("add_opens", STRING_LIST, ImmutableList.of()),
transitive);
}

public static ImmutableList<String> toFlags(List<String> addExports, List<String> addOpens) {
return Streams.concat(
addExports.stream().map(x -> String.format("--add-exports=%s=ALL-UNNAMED", x)),
addOpens.stream().map(x -> String.format("--add-opens=%s=ALL-UNNAMED", x)))
.collect(toImmutableList());
}

public ImmutableList<String> toFlags() {
return toFlags(addExports().toList(), addOpens().toList());
}
}
Loading

0 comments on commit 2217b13

Please sign in to comment.