diff options
author | 2017-01-16 23:06:11 +0000 | |
---|---|---|
committer | 2017-01-17 12:15:29 +0000 | |
commit | a27a5aa83696200e22a459950081eb443e01e427 (patch) | |
tree | 19d1f57e42a46cbe5af5105ac547e4a1ab1c9e85 | |
parent | 14d952232b0284fecc898a6d5cb1bf3467aff493 (diff) |
Initial implementation of java_runtime and java_runtime_suite
These rules can be used to configure JDKs, as an alternative to
the filegroups and filegroups-of-filegroups used currently.
--
PiperOrigin-RevId: 144655277
MOS_MIGRATED_REVID=144655277
8 files changed, 436 insertions, 79 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/BUILD b/src/main/java/com/google/devtools/build/lib/BUILD index 9f9708107d..b174fd42f3 100644 --- a/src/main/java/com/google/devtools/build/lib/BUILD +++ b/src/main/java/com/google/devtools/build/lib/BUILD @@ -753,8 +753,12 @@ java_library( "rules/java/JavaPlugin.java", "rules/java/JavaPrimaryClassProvider.java", "rules/java/JavaProvider.java", + "rules/java/JavaRuntime.java", "rules/java/JavaRuntimeClasspathProvider.java", "rules/java/JavaRuntimeJarProvider.java", + "rules/java/JavaRuntimeRule.java", + "rules/java/JavaRuntimeSuite.java", + "rules/java/JavaRuntimeSuiteRule.java", "rules/java/JavaSkylarkCommon.java", "rules/java/JavaSourceInfoProvider.java", "rules/java/JavaToolchain.java", @@ -842,6 +846,7 @@ java_library( "rules/java/JavaPluginInfoProvider.java", "rules/java/JavaRuleOutputJarsProvider.java", "rules/java/JavaRunfilesProvider.java", + "rules/java/JavaRuntimeProvider.java", "rules/java/JavaSemantics.java", "rules/java/JavaSkylarkApiProvider.java", "rules/java/JavaSourceJarsProvider.java", diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java index 362fd2709b..87dc0d5504 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java @@ -116,6 +116,8 @@ import com.google.devtools.build.lib.rules.genquery.GenQueryRule; import com.google.devtools.build.lib.rules.java.JavaConfigurationLoader; import com.google.devtools.build.lib.rules.java.JavaImportBaseRule; import com.google.devtools.build.lib.rules.java.JavaOptions; +import com.google.devtools.build.lib.rules.java.JavaRuntimeRule; +import com.google.devtools.build.lib.rules.java.JavaRuntimeSuiteRule; import com.google.devtools.build.lib.rules.java.JavaSkylarkCommon; import com.google.devtools.build.lib.rules.java.JavaToolchainRule; import com.google.devtools.build.lib.rules.java.JvmConfigurationLoader; @@ -484,6 +486,8 @@ public class BazelRuleClassProvider { builder.addRuleDefinition(new BazelJavaTestRule()); builder.addRuleDefinition(new BazelJavaPluginRule()); builder.addRuleDefinition(new JavaToolchainRule()); + builder.addRuleDefinition(new JavaRuntimeRule()); + builder.addRuleDefinition(new JavaRuntimeSuiteRule()); builder.addRuleDefinition(new ExtraActionRule()); builder.addRuleDefinition(new ActionListenerRule()); diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntime.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntime.java new file mode 100644 index 0000000000..e8ff3a8105 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntime.java @@ -0,0 +1,47 @@ +// Copyright 2017 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 com.google.devtools.build.lib.actions.Actions; +import com.google.devtools.build.lib.actions.Artifact; +import com.google.devtools.build.lib.analysis.CompilationHelper; +import com.google.devtools.build.lib.analysis.ConfiguredTarget; +import com.google.devtools.build.lib.analysis.MiddlemanProvider; +import com.google.devtools.build.lib.analysis.PrerequisiteArtifacts; +import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode; +import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder; +import com.google.devtools.build.lib.analysis.RuleContext; +import com.google.devtools.build.lib.analysis.RunfilesProvider; +import com.google.devtools.build.lib.collect.nestedset.NestedSet; +import com.google.devtools.build.lib.rules.RuleConfiguredTargetFactory; + +/** Implementation for the {@code java_runtime} rule. */ +public class JavaRuntime implements RuleConfiguredTargetFactory { + @Override + public ConfiguredTarget create(RuleContext ruleContext) + throws InterruptedException, RuleErrorException { + NestedSet<Artifact> filesToBuild = + PrerequisiteArtifacts.nestedSet(ruleContext, "srcs", Mode.TARGET); + NestedSet<Artifact> middleman = + CompilationHelper.getAggregatingMiddleman( + ruleContext, Actions.escapeLabel(ruleContext.getLabel()), filesToBuild); + return new RuleConfiguredTargetBuilder(ruleContext) + .addProvider(RunfilesProvider.class, RunfilesProvider.EMPTY) + .setFilesToBuild(filesToBuild) + .addProvider(JavaRuntimeProvider.class, JavaRuntimeProvider.create(filesToBuild)) + .addProvider(MiddlemanProvider.class, new MiddlemanProvider(middleman)) + .build(); + } +} diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntimeProvider.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntimeProvider.java new file mode 100644 index 0000000000..7ecd58c35e --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntimeProvider.java @@ -0,0 +1,34 @@ +// Copyright 2017 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 com.google.auto.value.AutoValue; +import com.google.devtools.build.lib.actions.Artifact; +import com.google.devtools.build.lib.analysis.TransitiveInfoProvider; +import com.google.devtools.build.lib.collect.nestedset.NestedSet; +import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; + +/** Information about the Java runtime used by the <code>java_*</code> rules. */ +@AutoValue +@Immutable +public abstract class JavaRuntimeProvider implements TransitiveInfoProvider { + + public static JavaRuntimeProvider create(NestedSet<Artifact> javaBaseInputs) { + return new AutoValue_JavaRuntimeProvider(javaBaseInputs); + } + + /** All input artifacts in the javabase. */ + public abstract NestedSet<Artifact> javaBaseInputs(); +} diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntimeRule.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntimeRule.java new file mode 100644 index 0000000000..ef526863f8 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntimeRule.java @@ -0,0 +1,71 @@ +// Copyright 2017 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.devtools.build.lib.packages.Attribute.attr; +import static com.google.devtools.build.lib.packages.BuildType.LABEL_LIST; +import static com.google.devtools.build.lib.packages.BuildType.LICENSE; +import static com.google.devtools.build.lib.syntax.Type.STRING; + +import com.google.devtools.build.lib.analysis.BaseRuleClasses; +import com.google.devtools.build.lib.analysis.RuleDefinition; +import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment; +import com.google.devtools.build.lib.packages.RuleClass; +import com.google.devtools.build.lib.packages.RuleClass.Builder; +import com.google.devtools.build.lib.util.FileTypeSet; + +/** Rule definition for {@code java_runtime} */ +public final class JavaRuntimeRule implements RuleDefinition { + @Override + public RuleClass build(Builder builder, RuleDefinitionEnvironment env) { + return builder + /* <!-- #BLAZE_RULE(java_runtime).ATTRIBUTE(srcs) --> + All files in the runtime. + <!-- #END_BLAZE_RULE.ATTRIBUTE --> */ + .add(attr("srcs", LABEL_LIST).allowedFileTypes(FileTypeSet.ANY_FILE).mandatory()) + /* <!-- #BLAZE_RULE(java_runtime).ATTRIBUTE(java_home) --> + The relative path to the root of the runtime. + <!-- #END_BLAZE_RULE.ATTRIBUTE --> */ + .add(attr("java_home", STRING)) + .add(attr("output_licenses", LICENSE)) + .build(); + } + + @Override + public Metadata getMetadata() { + return RuleDefinition.Metadata.builder() + .name("java_runtime") + .ancestors(BaseRuleClasses.BaseRule.class) + .factoryClass(JavaRuntime.class) + .build(); + } +} +/*<!-- #BLAZE_RULE (NAME = java_runtime, TYPE = OTHER, FAMILY = Java) --> + +<p> +Specifies the configuration for a Java runtime. +</p> + +<h4 id="java_runtime">Example:</h4> + +<pre class="code"> +java_runtime( + name = "jdk-9-ea+153", + srcs = glob(["jdk9-ea+153/**"]), + java_home = "jdk9-ea+153", +) +</pre> + +<!-- #END_BLAZE_RULE -->*/ diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntimeSuite.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntimeSuite.java new file mode 100644 index 0000000000..2a42e5e560 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntimeSuite.java @@ -0,0 +1,46 @@ +// Copyright 2017 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 com.google.devtools.build.lib.analysis.ConfiguredTarget; +import com.google.devtools.build.lib.analysis.FileProvider; +import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode; +import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder; +import com.google.devtools.build.lib.analysis.RuleContext; +import com.google.devtools.build.lib.analysis.RunfilesProvider; +import com.google.devtools.build.lib.analysis.TransitiveInfoCollection; +import com.google.devtools.build.lib.rules.RuleConfiguredTargetFactory; + +/** Implementation for the {@code java_runtime_suite} rule. */ +public class JavaRuntimeSuite implements RuleConfiguredTargetFactory { + @Override + public ConfiguredTarget create(RuleContext ruleContext) + throws InterruptedException, RuleErrorException { + TransitiveInfoCollection runtime = + ruleContext.getPrerequisiteMap("runtimes").get(ruleContext.getConfiguration().getCpu()); + if (runtime == null) { + runtime = ruleContext.getPrerequisite("default", Mode.TARGET); + } + if (runtime == null) { + ruleContext.throwWithRuleError( + "could not resolve runtime for cpu " + ruleContext.getConfiguration().getCpu()); + } + return new RuleConfiguredTargetBuilder(ruleContext) + .addProvider(JavaRuntimeProvider.class, runtime.getProvider(JavaRuntimeProvider.class)) + .addProvider(RunfilesProvider.class, runtime.getProvider(RunfilesProvider.class)) + .setFilesToBuild(runtime.getProvider(FileProvider.class).getFilesToBuild()) + .build(); + } +} diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntimeSuiteRule.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntimeSuiteRule.java new file mode 100644 index 0000000000..63aa2683ed --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntimeSuiteRule.java @@ -0,0 +1,80 @@ +// Copyright 2017 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.devtools.build.lib.packages.Attribute.attr; +import static com.google.devtools.build.lib.packages.BuildType.LICENSE; + +import com.google.common.collect.ImmutableList; +import com.google.devtools.build.lib.analysis.BaseRuleClasses; +import com.google.devtools.build.lib.analysis.RuleDefinition; +import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment; +import com.google.devtools.build.lib.analysis.TransitiveInfoProvider; +import com.google.devtools.build.lib.packages.BuildType; +import com.google.devtools.build.lib.packages.RuleClass; +import com.google.devtools.build.lib.packages.RuleClass.Builder; +import com.google.devtools.build.lib.util.FileTypeSet; + +/** Rule definition for {@code java_runtime_suite} */ +public final class JavaRuntimeSuiteRule implements RuleDefinition { + @Override + public RuleClass build(Builder builder, RuleDefinitionEnvironment env) { + return builder + /* <!-- #BLAZE_RULE(java_runtime_suite).ATTRIBUTE(runtimes) --> + A map from each supported architecture to the corresponding <code>java_runtime</code>. + <!-- #END_BLAZE_RULE.ATTRIBUTE --> */ + .add(attr("runtimes", BuildType.LABEL_DICT_UNARY)) + /* <!-- #BLAZE_RULE(java_runtime_suite).ATTRIBUTE(default) --> + A map from each supported architecture to the corresponding <code>java_runtime</code>. + <!-- #END_BLAZE_RULE.ATTRIBUTE --> */ + .add( + attr("default", BuildType.LABEL) + .mandatoryNativeProviders( + ImmutableList.<Class<? extends TransitiveInfoProvider>>of( + JavaRuntimeProvider.class)) + .allowedFileTypes(FileTypeSet.NO_FILE)) + .add(attr("output_licenses", LICENSE)) + .build(); + } + + @Override + public Metadata getMetadata() { + return RuleDefinition.Metadata.builder() + .name("java_runtime_suite") + .ancestors(BaseRuleClasses.BaseRule.class) + .factoryClass(JavaRuntimeSuite.class) + .build(); + } +} +/*<!-- #BLAZE_RULE (NAME = java_runtime_suite, TYPE = OTHER, FAMILY = Java) --> + +<p> +Specifies the configuration for the Java runtimes for each architecture. +</p> + +<h4 id="java_runtime_suite">Example:</h4> + +<pre class="code"> +java_runtime_suite( + name = "jdk9", + runtimes = { + "k8": ":jdk9-k8", + "ppc": ":jdk9-ppc", + "arm": ":jdk9-arm", + }, +) +</pre> + +<!-- #END_BLAZE_RULE -->*/ diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JvmConfigurationLoader.java b/src/main/java/com/google/devtools/build/lib/rules/java/JvmConfigurationLoader.java index 942d2abca3..a8fb7aaad4 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/java/JvmConfigurationLoader.java +++ b/src/main/java/com/google/devtools/build/lib/rules/java/JvmConfigurationLoader.java @@ -29,23 +29,30 @@ import com.google.devtools.build.lib.events.Event; import com.google.devtools.build.lib.packages.BuildType; import com.google.devtools.build.lib.packages.NoSuchPackageException; import com.google.devtools.build.lib.packages.NoSuchTargetException; +import com.google.devtools.build.lib.packages.NoSuchThingException; import com.google.devtools.build.lib.packages.RawAttributeMapper; import com.google.devtools.build.lib.packages.Rule; import com.google.devtools.build.lib.packages.Target; import com.google.devtools.build.lib.syntax.Type; import com.google.devtools.build.lib.vfs.PathFragment; import java.util.List; +import java.util.Map; import javax.annotation.Nullable; /** * A provider to load jvm configurations from the package path. * - * <p>If the given {@code javaHome} is a label, i.e. starts with {@code "//"}, - * then the loader will look at the target it refers to. If the target is a - * filegroup, then the loader will look in it's srcs for a filegroup that ends - * with {@code -<cpu>}. It will use that filegroup to construct the actual - * {@link Jvm} instance, using the filegroups {@code path} attribute to - * construct the new {@code javaHome} path. + * <p>If the given {@code javaHome} is a label, i.e. starts with {@code "//"}, then the loader will + * look at the target it refers to. + * + * <ul> + * <li>If the target is a {@code java_runtime_suite}, the loader will select the runtime from the + * entry in {@code java_runtime_suite.runtimes} for {@code cpu}. + * <li>If the target is a filegroup, then the loader will look in it's srcs for a filegroup that + * ends with {@code -<cpu>}. It will use that filegroup to construct the actual {@link Jvm} + * instance, using the filegroups {@code path} attribute to construct the new {@code javaHome} + * path. + * </ul> * * <p>The loader also supports legacy mode, where the JVM can be defined with an abolute path. */ @@ -90,88 +97,151 @@ public final class JvmConfigurationLoader implements ConfigurationFragmentFactor return null; } Target javaHomeTarget = lookup.getTarget(label); - if ((javaHomeTarget instanceof Rule) && - "filegroup".equals(((Rule) javaHomeTarget).getRuleClass())) { - RawAttributeMapper javaHomeAttributes = RawAttributeMapper.of((Rule) javaHomeTarget); - if (javaHomeAttributes.isConfigurable("srcs", BuildType.LABEL_LIST)) { - throw new InvalidConfigurationException("\"srcs\" in " + javaHome - + " is configurable. JAVABASE targets don't support configurable attributes"); - } - List<Label> labels = javaHomeAttributes.get("srcs", BuildType.LABEL_LIST); - Label selectedJvmLabel = null; - Label defaultJvmLabel = null; - for (Label jvmLabel : labels) { - if (jvmLabel.getName().endsWith("-" + cpu)) { - selectedJvmLabel = jvmLabel; - break; - } - // When we open sourced Bazel, we used the string "default" to look up the Jvm. This is - // incorrect for cross-platform builds, but works for purely local builds. Since we now - // need to support cross-platform builds, we need to look up by the CPU, rather than the - // hard-coded string "default". However, for local builds the Jvm is setup with a - // mechanism where we don't currently have access to the CPU value (this is different from - // C++, where we infer the CPU from the local machine). As such, looking up only by CPU - // breaks builds that currently work, unless we add alias rules for all possible CPU - // values (but this is problematic if Bazel is ported to more platforms). For now, we're - // working around this problem by falling back to -default if we can't find a Jvm ending - // in -<cpu>. This is backwards compatible, but still allows cross-platform builds. In the - // medium term, we should rewrite Jvm setup to use a Skylark remote repository, and also - // remove the necessity of having a Jvm defined for all platforms even if there's no Java - // code. - if (jvmLabel.getName().endsWith("-default")) { - defaultJvmLabel = jvmLabel; - } - } - if (selectedJvmLabel == null) { - selectedJvmLabel = defaultJvmLabel; - } - if (selectedJvmLabel != null) { - selectedJvmLabel = RedirectChaser.followRedirects( - lookup, selectedJvmLabel, "Architecture-specific JDK"); - if (selectedJvmLabel == null) { - return null; - } - - Target jvmTarget = lookup.getTarget(selectedJvmLabel); - if (jvmTarget == null) { - return null; - } - - PathFragment javaHomePath; - if (jvmTarget.getLabel().getPackageIdentifier().getRepository().isDefault()) { - javaHomePath = selectedJvmLabel.getPackageFragment(); - } else { - javaHomePath = jvmTarget.getLabel().getPackageIdentifier().getSourceRoot(); - } - - if ((jvmTarget instanceof Rule) && - "filegroup".equals(((Rule) jvmTarget).getRuleClass())) { - RawAttributeMapper jvmTargetAttributes = RawAttributeMapper.of((Rule) jvmTarget); - if (jvmTargetAttributes.isConfigurable("path", Type.STRING)) { - throw new InvalidConfigurationException("\"path\" in " + jvmTarget - + " is configurable. JVM targets don't support configurable attributes"); - } - String path = jvmTargetAttributes.get("path", Type.STRING); - if (path != null) { - javaHomePath = javaHomePath.getRelative(path); - } - } - return new Jvm(javaHomePath, selectedJvmLabel); + if (javaHomeTarget instanceof Rule) { + switch (((Rule) javaHomeTarget).getRuleClass()) { + case "filegroup": + return createFromFilegroup(lookup, javaHomeTarget, cpu); + case "java_runtime_suite": + return createFromRuntimeSuite(lookup, (Rule) javaHomeTarget, cpu); + default: + throw new InvalidConfigurationException( + "Unexpected javabase rule kind '" + ((Rule) javaHomeTarget).getRuleClass() + "'"); } } - throw new InvalidConfigurationException("No JVM target found under " + javaHome - + " that would work for " + cpu); - } catch (NoSuchPackageException | NoSuchTargetException e) { + throw new InvalidConfigurationException( + "No JVM target found under " + javaHome + " that would work for " + cpu); + } catch (NoSuchThingException e) { lookup.getEventHandler().handle(Event.error(e.getMessage())); throw new InvalidConfigurationException(e.getMessage(), e); } } - private Jvm createLegacy(String javaHome) + private static Jvm createFromFilegroup( + ConfigurationEnvironment lookup, Target javaHomeTarget, String cpu) + throws InvalidConfigurationException, InterruptedException, NoSuchPackageException, + NoSuchTargetException { + + RawAttributeMapper javaHomeAttributes = RawAttributeMapper.of((Rule) javaHomeTarget); + if (javaHomeAttributes.isConfigurable("srcs", BuildType.LABEL_LIST)) { + throw new InvalidConfigurationException( + String.format( + "\"srcs\" in %s is configurable. JAVABASE targets don't support configurable" + + " attributes", + javaHomeTarget)); + } + List<Label> labels = javaHomeAttributes.get("srcs", BuildType.LABEL_LIST); + Label selectedJvmLabel = null; + Label defaultJvmLabel = null; + for (Label jvmLabel : labels) { + if (jvmLabel.getName().endsWith("-" + cpu)) { + selectedJvmLabel = jvmLabel; + break; + } + // When we open sourced Bazel, we used the string "default" to look up the Jvm. This is + // incorrect for cross-platform builds, but works for purely local builds. Since we now + // need to support cross-platform builds, we need to look up by the CPU, rather than the + // hard-coded string "default". However, for local builds the Jvm is setup with a + // mechanism where we don't currently have access to the CPU value (this is different from + // C++, where we infer the CPU from the local machine). As such, looking up only by CPU + // breaks builds that currently work, unless we add alias rules for all possible CPU + // values (but this is problematic if Bazel is ported to more platforms). For now, we're + // working around this problem by falling back to -default if we can't find a Jvm ending + // in -<cpu>. This is backwards compatible, but still allows cross-platform builds. In the + // medium term, we should rewrite Jvm setup to use a Skylark remote repository, and also + // remove the necessity of having a Jvm defined for all platforms even if there's no Java + // code. + if (jvmLabel.getName().endsWith("-default")) { + defaultJvmLabel = jvmLabel; + } + } + if (selectedJvmLabel == null) { + selectedJvmLabel = defaultJvmLabel; + } + if (selectedJvmLabel != null) { + selectedJvmLabel = + RedirectChaser.followRedirects(lookup, selectedJvmLabel, "Architecture-specific JDK"); + if (selectedJvmLabel == null) { + return null; + } + + Target jvmTarget = lookup.getTarget(selectedJvmLabel); + + PathFragment javaHomePath = defaultJavaHome(jvmTarget.getLabel()); + + if ((jvmTarget instanceof Rule) && "filegroup".equals(((Rule) jvmTarget).getRuleClass())) { + RawAttributeMapper jvmTargetAttributes = RawAttributeMapper.of((Rule) jvmTarget); + if (jvmTargetAttributes.isConfigurable("path", Type.STRING)) { + throw new InvalidConfigurationException( + String.format( + "\"path\" in %s is configurable. JVM targets don't support configurable" + + " attributes", + jvmTarget)); + } + String path = jvmTargetAttributes.get("path", Type.STRING); + if (path != null) { + javaHomePath = javaHomePath.getRelative(path); + } + } + return new Jvm(javaHomePath, selectedJvmLabel); + } + throw new InvalidConfigurationException( + String.format("No JVM target found under %s that would work for %s", javaHomeTarget, cpu)); + } + + // TODO(b/34175492): this is temporary until support for filegroup-based javabases is removed. + // Eventually the Jvm fragement will containg only the label of a java_runtime rule, and all of + // the configuration will be accessed using JavaRuntimeProvider. + private static Jvm createFromRuntimeSuite( + ConfigurationEnvironment lookup, Rule javaRuntimeSuite, String cpu) + throws InvalidConfigurationException, InterruptedException, NoSuchTargetException, + NoSuchPackageException { + Label javaRuntimeLabel = selectRuntime(javaRuntimeSuite, cpu); + Target javaRuntimeTarget = lookup.getTarget(javaRuntimeLabel); + if (javaRuntimeTarget == null) { + return null; + } + if (!(javaRuntimeTarget instanceof Rule)) { + throw new InvalidConfigurationException( + String.format("Invalid java_runtime '%s'", javaRuntimeLabel)); + } + Rule javaRuntimeRule = (Rule) javaRuntimeTarget; + if (!javaRuntimeRule.getRuleClass().equals("java_runtime")) { + throw new InvalidConfigurationException( + String.format("Expected a java_runtime rule, was '%s'", javaRuntimeRule.getRuleClass())); + } + RawAttributeMapper attributes = RawAttributeMapper.of(javaRuntimeRule); + PathFragment javaHomePath = defaultJavaHome(javaRuntimeLabel); + if (attributes.isAttributeValueExplicitlySpecified("java_home")) { + javaHomePath = javaHomePath.getRelative(attributes.get("java_home", Type.STRING)); + } + return new Jvm(javaHomePath, javaRuntimeLabel); + } + + private static Label selectRuntime(Rule javaRuntimeSuite, String cpu) throws InvalidConfigurationException { + RawAttributeMapper suiteAttributes = RawAttributeMapper.of(javaRuntimeSuite); + Map<String, Label> runtimes = suiteAttributes.get("runtimes", BuildType.LABEL_DICT_UNARY); + if (runtimes.containsKey(cpu)) { + return runtimes.get(cpu); + } + if (suiteAttributes.isAttributeValueExplicitlySpecified("default")) { + return suiteAttributes.get("default", BuildType.LABEL); + } + throw new InvalidConfigurationException( + "No JVM target found under " + javaRuntimeSuite + " that would work for " + cpu); + } + + private static PathFragment defaultJavaHome(Label javaBase) { + if (javaBase.getPackageIdentifier().getRepository().isDefault()) { + return javaBase.getPackageFragment(); + } + return javaBase.getPackageIdentifier().getSourceRoot(); + } + + private static Jvm createLegacy(String javaHome) throws InvalidConfigurationException { if (!javaHome.startsWith("/")) { - throw new InvalidConfigurationException("Illegal javabase value '" + javaHome + - "', javabase must be an absolute path or label"); + throw new InvalidConfigurationException( + "Illegal javabase value '" + javaHome + "', javabase must be an absolute path or label"); } return new Jvm(new PathFragment(javaHome), null); } |