Skip to content

Commit

Permalink
Completing the Java sandwich and testing it.
Browse files Browse the repository at this point in the history
* Unwrapping JavaCompilationArgsProvider from JavaProvider when collecting compile time dependencies artifacts (in addition to JavaCompilationArgsProvider), so that java_library could depend on Skylark rules that return java_common.provider. (this makes java sandwich complete \o/)

* Added a new param (source_files) to java_common.compile to allow compilation of source files in addition to source jars.

* Added a new sourceFiles field to JavaLibraryHelper in order to pass them to JavaCompilationHelper.

* Added a new method (java_common.default_javac_opts) for default Java compilation.

* Added a test for a basic java sandwich.

--
PiperOrigin-RevId: 145064700
MOS_MIGRATED_REVID=145064700
  • Loading branch information
iirina authored and vladmos committed Jan 20, 2017
1 parent fbc546b commit d2293e2
Show file tree
Hide file tree
Showing 7 changed files with 234 additions and 5 deletions.
1 change: 1 addition & 0 deletions src/main/java/com/google/devtools/build/lib/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -845,6 +845,7 @@ java_library(
"rules/java/JavaNeverlinkInfoProvider.java",
"rules/java/JavaOptions.java",
"rules/java/JavaPluginInfoProvider.java",
"rules/java/JavaProvider.java",
"rules/java/JavaRuleOutputJarsProvider.java",
"rules/java/JavaRunfilesProvider.java",
"rules/java/JavaRuntimeProvider.java",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import com.google.devtools.build.lib.analysis.RuleContext;
import com.google.devtools.build.lib.analysis.Runfiles;
import com.google.devtools.build.lib.analysis.RunfilesProvider;
import com.google.devtools.build.lib.analysis.SkylarkProviders;
import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
import com.google.devtools.build.lib.analysis.TransitiveInfoProvider;
import com.google.devtools.build.lib.analysis.Util;
Expand Down Expand Up @@ -286,14 +287,33 @@ public JavaCompilationArgs collectJavaCompilationArgs(boolean recursive, boolean
*/
public NestedSet<Artifact> collectCompileTimeDependencyArtifacts(@Nullable Artifact outDeps) {
NestedSetBuilder<Artifact> builder = NestedSetBuilder.stableOrder();
Set<JavaCompilationArgsProvider> addedProviders = new LinkedHashSet<>();
if (outDeps != null) {
builder.add(outDeps);
}

for (JavaCompilationArgsProvider provider : AnalysisUtils.getProviders(
getExports(ruleContext), JavaCompilationArgsProvider.class)) {
builder.addTransitive(provider.getCompileTimeJavaDependencyArtifacts());
addedProviders.add(provider);
}

// We also check for artifacts in the JavaProvider of the dependencies (might exist when
// information is passed from a custom Skylark Java rule).
for (SkylarkProviders skylarkProviders : AnalysisUtils.getProviders(
getExports(ruleContext), SkylarkProviders.class)) {
JavaProvider javaProvider =
(JavaProvider) skylarkProviders.getDeclaredProvider(JavaProvider.JAVA_PROVIDER.getKey());
if (javaProvider != null) {
JavaCompilationArgsProvider compilationArgsProvider =
javaProvider.getJavaCompilationArgsProvider();
if (!addedProviders.contains(compilationArgsProvider)) {
builder.addTransitive(javaProvider
.getJavaCompilationArgsProvider().getCompileTimeJavaDependencyArtifacts());
}
}
}

return builder.build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import com.google.auto.value.AutoValue;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.analysis.FileProvider;
import com.google.devtools.build.lib.analysis.SkylarkProviders;
import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
Expand Down Expand Up @@ -152,6 +153,19 @@ public Builder addTransitiveCompilationArgs(
public Builder addTransitiveTarget(TransitiveInfoCollection dep, boolean recursive,
ClasspathType type) {
JavaCompilationArgsProvider provider = dep.getProvider(JavaCompilationArgsProvider.class);
if (provider == null) {
// Only look for the JavaProvider when there is no JavaCompilationArgsProvider, else
// it would encapsulate the same information.
SkylarkProviders skylarkProviders = dep.getProvider(SkylarkProviders.class);
if (skylarkProviders != null) {
JavaProvider javaProvider =
(JavaProvider) skylarkProviders.getDeclaredProvider(
JavaProvider.JAVA_PROVIDER.getKey());
if (javaProvider != null) {
provider = javaProvider.getJavaCompilationArgsProvider();
}
}
}
if (provider != null) {
addTransitiveCompilationArgs(provider, recursive, type);
return this;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.actions.ParameterFile.ParameterFileType;
import com.google.devtools.build.lib.analysis.AnalysisEnvironment;
import com.google.devtools.build.lib.analysis.AnalysisUtils;
import com.google.devtools.build.lib.analysis.FileProvider;
import com.google.devtools.build.lib.analysis.FilesToRunProvider;
import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode;
import com.google.devtools.build.lib.analysis.RuleContext;
import com.google.devtools.build.lib.analysis.SkylarkProviders;
import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
import com.google.devtools.build.lib.analysis.actions.CustomCommandLine;
import com.google.devtools.build.lib.analysis.actions.SpawnAction;
Expand All @@ -44,6 +44,7 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
Expand Down Expand Up @@ -661,9 +662,41 @@ public void addLibrariesToAttributes(Iterable<? extends TransitiveInfoCollection

JavaClasspathMode classpathMode = getJavaConfiguration().getReduceJavaClasspath();
if (isStrict() && classpathMode != JavaClasspathMode.OFF) {
addDependencyArtifactsToAttributes(
attributes, AnalysisUtils.getProviders(deps, JavaCompilationArgsProvider.class));
List<JavaCompilationArgsProvider> compilationArgsProviders = new LinkedList<>();
for (TransitiveInfoCollection dep : deps) {
// First check if there is a JavaCompilationArgsProvider.
JavaCompilationArgsProvider provider = dep.getProvider(JavaCompilationArgsProvider.class);

if (provider == null) {
// A target can either have both JavaCompilationArgsProvider and JavaProvider that
// encapsulates the same information, or just one of them.
provider = getJavaCompilationArgsProviderFromDep(dep);
}
if (provider != null) {
compilationArgsProviders.add(provider);
}
}
addDependencyArtifactsToAttributes(attributes, compilationArgsProviders);
}
}

/**
* Returns a JavaCompilationArgsProvider fetched from the JavaProvider of the given target.
* JavaProvider can be found as a declared provider in SkylarkProviders.
*/
@Nullable
private static JavaCompilationArgsProvider getJavaCompilationArgsProviderFromDep(
TransitiveInfoCollection target) {
SkylarkProviders skylarkProviders = target.getProvider(SkylarkProviders.class);
if (skylarkProviders == null) {
return null;
}
JavaProvider javaProvider =
(JavaProvider) skylarkProviders.getDeclaredProvider(JavaProvider.JAVA_PROVIDER.getKey());
if (javaProvider == null) {
return null;
}
return javaProvider.getJavaCompilationArgsProvider();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public final class JavaLibraryHelper {

private Artifact output;
private final List<Artifact> sourceJars = new ArrayList<>();
private final List<Artifact> sourceFiles = new ArrayList<>();

/**
* Contains all the dependencies; these are treated as both compile-time and runtime dependencies.
Expand Down Expand Up @@ -90,6 +91,14 @@ public JavaLibraryHelper addDep(JavaCompilationArgsProvider provider) {
return this;
}

/**
* Adds the given source files to be compiled.
*/
public JavaLibraryHelper addSourceFiles(Iterable<Artifact> sourceFiles) {
Iterables.addAll(this.sourceFiles, sourceFiles);
return this;
}

public JavaLibraryHelper addAllDeps(
Iterable<JavaCompilationArgsProvider> providers) {
Iterables.addAll(deps, providers);
Expand Down Expand Up @@ -131,6 +140,7 @@ public JavaCompilationArgs build(
Preconditions.checkState(output != null, "must have an output file; use setOutput()");
JavaTargetAttributes.Builder attributes = new JavaTargetAttributes.Builder(semantics);
attributes.addSourceJars(sourceJars);
attributes.addSourceFiles(sourceFiles);
addDepsToAttributes(attributes);
attributes.setStrictJavaDeps(strictDepsMode);
attributes.setRuleKind(ruleContext.getRule().getRuleClass());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@
import static com.google.common.base.Preconditions.checkNotNull;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.analysis.ConfiguredTarget;
import com.google.devtools.build.lib.analysis.MiddlemanProvider;
import com.google.devtools.build.lib.analysis.RuleContext;
import com.google.devtools.build.lib.analysis.config.BuildConfiguration.StrictDepsMode;
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
Expand Down Expand Up @@ -56,11 +58,20 @@ public SkylarkClassObjectConstructor getJavaProvider() {
mandatoryPositionals = 1,
parameters = {
@Param(
name = "source_jars",
name = "source_jars",
positional = false,
named = true,
type = SkylarkList.class,
generic1 = Artifact.class,
defaultValue = "[]"
),
@Param(
name = "source_files",
positional = false,
named = true,
type = SkylarkList.class,
generic1 = Artifact.class
generic1 = Artifact.class,
defaultValue = "[]"
),
@Param(name = "output", positional = false, named = true, type = Artifact.class),
@Param(
Expand Down Expand Up @@ -101,6 +112,7 @@ public SkylarkClassObjectConstructor getJavaProvider() {
public JavaProvider createJavaCompileAction(
SkylarkRuleContext skylarkRuleContext,
SkylarkList<Artifact> sourceJars,
SkylarkList<Artifact> sourceFiles,
Artifact outputJar,
SkylarkList<String> javacOpts,
SkylarkList<JavaProvider> deps,
Expand All @@ -111,7 +123,9 @@ public JavaProvider createJavaCompileAction(
new JavaLibraryHelper(skylarkRuleContext.getRuleContext())
.setOutput(outputJar)
.addSourceJars(sourceJars)
.addSourceFiles(sourceFiles)
.setJavacOpts(javacOpts);

helper.addAllDeps(getJavaCompilationArgsProviders(deps));
helper.setCompilationStrictDepsMode(getStrictDepsMode(strictDepsMode));
MiddlemanProvider hostJavabaseProvider = hostJavabase.getProvider(MiddlemanProvider.class);
Expand All @@ -131,6 +145,27 @@ public JavaProvider createJavaCompileAction(
return new JavaProvider(helper.buildCompilationArgsProvider(artifacts, true));
}

@SkylarkCallable(
name = "default_javac_opts",
// This function is experimental for now.
documented = false,
// There's only one mandatory positional,the Skylark context
mandatoryPositionals = 1,
parameters = {
@Param(name = "java_toolchain_attr", positional = false, named = true, type = String.class)
}
)
public static List<String> getDefaultJavacOpts(
SkylarkRuleContext skylarkRuleContext, String javaToolchainAttr) {
RuleContext ruleContext = skylarkRuleContext.getRuleContext();
ConfiguredTarget javaToolchainConfigTarget =
(ConfiguredTarget) checkNotNull(skylarkRuleContext.getAttr().getValue(javaToolchainAttr));
JavaToolchainProvider toolchain =
checkNotNull(javaToolchainConfigTarget.getProvider(JavaToolchainProvider.class));
return ImmutableList.copyOf(Iterables.concat(
toolchain.getJavacOptions(), ruleContext.getTokenizedStringListAttr("javacopts")));
}

@SkylarkCallable(
name = "merge",
// We have one positional argument: the list of providers to merge.
Expand Down
116 changes: 116 additions & 0 deletions src/test/shell/bazel/bazel_java_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -158,5 +158,121 @@ EOF
expect_log "testTest was run"
}

function test_basic_java_sandwich() {
mkdir -p java/com/google/sandwich
cd java/com/google/sandwich

touch BUILD A.java B.java C.java Main.java java_custom_library.bzl

cat > BUILD << EOF
load(':java_custom_library.bzl', 'java_custom_library')
java_binary(
name = "Main",
srcs = ["Main.java"],
deps = [":top"]
)
java_library(
name = "top",
srcs = ["A.java"],
deps = [":middle"]
)
java_custom_library(
name = "middle",
srcs = ["B.java"],
deps = [":bottom"]
)
java_library(
name = "bottom",
srcs = ["C.java"]
)
EOF

cat > C.java << EOF
package com.google.sandwich;
class C {
public void printC() {
System.out.println("Message from C");
}
}
EOF

cat > B.java << EOF
package com.google.sandwich;
class B {
C myObject;
public void printB() {
System.out.println("Message from B");
myObject = new C();
myObject.printC();
}
}
EOF

cat > A.java << EOF
package com.google.sandwich;
class A {
B myObject;
public void printA() {
System.out.println("Message from A");
myObject = new B();
myObject.printB();
}
}
EOF

cat > Main.java << EOF
package com.google.sandwich;
class Main {
public static void main(String[] args) {
A myObject = new A();
myObject.printA();
}
}
EOF

cat > java_custom_library.bzl << EOF
def _impl(ctx):
deps = [dep[java_common.provider] for dep in ctx.attr.deps]
deps_provider = java_common.merge(deps)
output_jar = ctx.new_file("lib" + ctx.label.name + ".jar")
compilation_provider = java_common.compile(
ctx,
source_files = ctx.files.srcs,
output = output_jar,
javac_opts = java_common.default_javac_opts(ctx, java_toolchain_attr = "_java_toolchain"),
deps = deps,
strict_deps = "ERROR",
java_toolchain = ctx.attr._java_toolchain,
host_javabase = ctx.attr._host_javabase
)
result = java_common.merge([deps_provider, compilation_provider])
return struct(
files = set([output_jar]),
providers = [result]
)
java_custom_library = rule(
implementation = _impl,
attrs = {
"srcs": attr.label_list(allow_files=True),
"deps": attr.label_list(),
"_java_toolchain": attr.label(default = Label("@bazel_tools//tools/jdk:toolchain")),
"_host_javabase": attr.label(default = Label("//tools/defaults:jdk"))
},
fragments = ["java"]
)
EOF

$PRODUCT_NAME run :Main > $TEST_log || fail "Java sandwich build failed"
expect_log "Message from A"
expect_log "Message from B"
expect_log "Message from C"
}

run_suite "Java integration tests"

0 comments on commit d2293e2

Please sign in to comment.