blob: 44a4b561c56b6fc5ad1e5e8525b9cf87ad1693be [file] [log] [blame]
Dmitry Lomov18212f12015-11-23 18:07:34 +00001// Copyright 2015 The Bazel Authors. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package com.google.devtools.build.lib.analysis;
16
17import static com.google.common.truth.Truth.assertThat;
Florian Weikert0509b912015-11-26 13:18:23 +000018import static org.junit.Assert.fail;
Dmitry Lomov18212f12015-11-23 18:07:34 +000019
20import com.google.common.collect.Iterables;
21import com.google.devtools.build.lib.actions.Artifact;
22import com.google.devtools.build.lib.actions.util.ActionsTestUtil;
23import com.google.devtools.build.lib.actions.util.ActionsTestUtil.UncheckedActionConflictException;
24import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
25import com.google.devtools.build.lib.analysis.util.AnalysisTestUtil;
Florian Weikertcca703a2015-12-07 09:56:38 +000026import com.google.devtools.build.lib.analysis.util.BuildViewTestCase;
cpeyser58fd82d2017-10-31 10:07:15 -040027import com.google.devtools.build.lib.rules.cpp.CcToolchainProvider;
Dmitry Lomov18212f12015-11-23 18:07:34 +000028import com.google.devtools.build.lib.rules.cpp.CppHelper;
janakre2df6e22018-03-19 14:31:00 -070029import com.google.devtools.build.lib.skyframe.ConfiguredTargetAndData;
lberkiaea56b32017-05-30 12:35:33 +020030import java.io.IOException;
31import java.util.List;
Florian Weikert0509b912015-11-26 13:18:23 +000032import org.junit.Before;
33import org.junit.Test;
34import org.junit.runner.RunWith;
35import org.junit.runners.JUnit4;
36
lberkiaea56b32017-05-30 12:35:33 +020037/** Unit tests for the {@link CompilationHelper} class. */
Florian Weikert0509b912015-11-26 13:18:23 +000038@RunWith(JUnit4.class)
Florian Weikertcca703a2015-12-07 09:56:38 +000039public class CompilationHelperTest extends BuildViewTestCase {
Dmitry Lomov18212f12015-11-23 18:07:34 +000040 private AnalysisTestUtil.CollectingAnalysisEnvironment analysisEnvironment;
41
Florian Weikert0509b912015-11-26 13:18:23 +000042 @Before
43 public final void createAnalysisEnvironment() throws Exception {
Dmitry Lomov18212f12015-11-23 18:07:34 +000044 analysisEnvironment =
45 new AnalysisTestUtil.CollectingAnalysisEnvironment(getTestAnalysisEnvironment());
46 }
47
48 private List<Artifact> getAggregatingMiddleman(
49 ConfiguredTarget rule, BuildConfiguration configuration, boolean withSolib) throws Exception {
cpeyser58fd82d2017-10-31 10:07:15 -040050 RuleContext ruleContext = getRuleContext(rule, analysisEnvironment);
51 CcToolchainProvider toolchain =
52 CppHelper.getToolchainUsingDefaultCcToolchainAttribute(ruleContext);
Dmitry Lomov18212f12015-11-23 18:07:34 +000053 return CppHelper.getAggregatingMiddlemanForTesting(
cpeyser58fd82d2017-10-31 10:07:15 -040054 ruleContext,
Dmitry Lomov18212f12015-11-23 18:07:34 +000055 ActionsTestUtil.NULL_ACTION_OWNER,
56 "middleman",
Lukacs Berkie3ed60d2016-09-09 15:20:49 +000057 rule.getProvider(FileProvider.class).getFilesToBuild(),
Dmitry Lomov18212f12015-11-23 18:07:34 +000058 withSolib,
cpeyser58fd82d2017-10-31 10:07:15 -040059 toolchain.getSolibDirectory(),
Dmitry Lomov18212f12015-11-23 18:07:34 +000060 configuration);
61 }
62
janakre2df6e22018-03-19 14:31:00 -070063 private List<Artifact> getAggregatingMiddleman(ConfiguredTargetAndData rule, boolean withSolib)
Dmitry Lomov18212f12015-11-23 18:07:34 +000064 throws Exception {
janakre2df6e22018-03-19 14:31:00 -070065 return getAggregatingMiddleman(rule.getConfiguredTarget(), rule.getConfiguration(), withSolib);
Dmitry Lomov18212f12015-11-23 18:07:34 +000066 }
67
68 /**
69 * Tests that duplicate calls to
70 * {@link com.google.devtools.build.lib.analysis.CompilationHelper#getAggregatingMiddleman}
71 * with identical parameters return the same artifact.
72 */
Florian Weikert0509b912015-11-26 13:18:23 +000073 @Test
Dmitry Lomov18212f12015-11-23 18:07:34 +000074 public void testDuplicateCallsReturnSameObject() throws Exception {
janakre2df6e22018-03-19 14:31:00 -070075 ConfiguredTargetAndData rule =
76 scratchConfiguredTargetAndData(
77 "package", "a", "cc_binary(name = 'a'," + " srcs = ['a.cc'])");
Dmitry Lomov18212f12015-11-23 18:07:34 +000078 List<Artifact> middleman1 = getAggregatingMiddleman(rule, false);
79 assertThat(middleman1).hasSize(1);
80 List<Artifact> middleman2 = getAggregatingMiddleman(rule, false);
81 assertThat(middleman2).hasSize(1);
lberkiaea56b32017-05-30 12:35:33 +020082 assertThat(middleman2.get(0)).isEqualTo(middleman1.get(0));
Dmitry Lomov18212f12015-11-23 18:07:34 +000083 }
84
85 /**
86 * Tests that
87 * {@link com.google.devtools.build.lib.analysis.CompilationHelper#getAggregatingMiddleman}
88 * returns distinct artifacts even when called with identical rules, depending on
89 * whether solib symlink are created.
90 */
Florian Weikert0509b912015-11-26 13:18:23 +000091 @Test
Dmitry Lomov18212f12015-11-23 18:07:34 +000092 public void testMiddlemanAndSolibMiddlemanAreDistinct() throws Exception {
janakre2df6e22018-03-19 14:31:00 -070093 ConfiguredTargetAndData rule =
94 scratchConfiguredTargetAndData(
95 "package", "liba.so", "cc_binary(name = 'liba.so', srcs = ['a.cc'], linkshared = 1)");
Dmitry Lomov18212f12015-11-23 18:07:34 +000096
97 List<Artifact> middleman = getAggregatingMiddleman(rule, false);
98 assertThat(middleman).hasSize(1);
99 List<Artifact> middlemanWithSymlinks = getAggregatingMiddleman(rule, true);
100 assertThat(middlemanWithSymlinks).hasSize(1);
lberkiaea56b32017-05-30 12:35:33 +0200101 assertThat(middlemanWithSymlinks.get(0)).isNotSameAs(middleman.get(0));
Dmitry Lomov18212f12015-11-23 18:07:34 +0000102 }
103
104 /**
105 * Regression test: tests that Python CPU configurations are taken into account
106 * when generating a rule's aggregating middleman, so that otherwise equivalent rules can sustain
107 * distinct middlemen.
108 */
Florian Weikert0509b912015-11-26 13:18:23 +0000109 @Test
Dmitry Lomov18212f12015-11-23 18:07:34 +0000110 public void testPythonCcConfigurations() throws Exception {
111 setupJavaPythonCcConfigurationFiles();
112
113 // Equivalent cc / Python configurations:
114
janakre2df6e22018-03-19 14:31:00 -0700115 ConfiguredTargetAndData ccRuleA = getConfiguredTargetAndData("//foo:liba.so");
Dmitry Lomov18212f12015-11-23 18:07:34 +0000116 List<Artifact> middleman1 = getAggregatingMiddleman(ccRuleA, true);
117 try {
janakre2df6e22018-03-19 14:31:00 -0700118 ConfiguredTargetAndData ccRuleB = getConfiguredTargetAndData("//foo:libb.so");
Dmitry Lomov18212f12015-11-23 18:07:34 +0000119 getAggregatingMiddleman(ccRuleB, true);
120 analysisEnvironment.registerWith(getMutableActionGraph());
121 fail("Expected ActionConflictException due to same middleman artifact with different files");
122 } catch (UncheckedActionConflictException e) {
123 // Expected failure: same "purpose" and root directory sent to the middleman generator
124 // (which results in the same output artifact), but different rules / middleman inputs.
125 }
126
127 // This should succeed because the py_binary's middleman is under the Python configuration's
128 // internal directory, while the cc_binary's middleman is under the cc config's directory,
129 // and both configurations are the same.
janakre2df6e22018-03-19 14:31:00 -0700130 ConfiguredTargetAndData pyRuleB =
131 getConfiguredTargetAndDataDirectPrerequisite(
132 getConfiguredTargetAndData("//foo:c"), "//foo:libb.so");
Lukacs Berki4e844f02016-08-22 08:48:37 +0000133
134 List<Artifact> middleman2 = getAggregatingMiddleman(pyRuleB, true);
lberkiaea56b32017-05-30 12:35:33 +0200135 assertThat(Iterables.getOnlyElement(middleman2).getExecPathString())
136 .isEqualTo(Iterables.getOnlyElement(middleman1).getExecPathString());
Dmitry Lomov18212f12015-11-23 18:07:34 +0000137 }
138
139 /**
140 * Regression test: tests that Java CPU configurations are taken into account when
141 * generating a rule's aggregating middleman, so that otherwise equivalent rules can sustain
142 * distinct middlemen.
143 */
Florian Weikert0509b912015-11-26 13:18:23 +0000144 @Test
Dmitry Lomov18212f12015-11-23 18:07:34 +0000145 public void testJavaCcConfigurations() throws Exception {
146 setupJavaPythonCcConfigurationFiles();
147
148 // Equivalent cc / Java configurations:
149
janakre2df6e22018-03-19 14:31:00 -0700150 ConfiguredTargetAndData ccRuleA = getConfiguredTargetAndData("//foo:liba.so");
Dmitry Lomov18212f12015-11-23 18:07:34 +0000151 List<Artifact> middleman1 = getAggregatingMiddleman(ccRuleA, true);
152 try {
janakre2df6e22018-03-19 14:31:00 -0700153 ConfiguredTargetAndData ccRuleB = getConfiguredTargetAndData("//foo:libb.so");
Dmitry Lomov18212f12015-11-23 18:07:34 +0000154 getAggregatingMiddleman(ccRuleB, true);
155 analysisEnvironment.registerWith(getMutableActionGraph());
156 fail("Expected ActionConflictException due to same middleman artifact with different files");
157 } catch (UncheckedActionConflictException e) {
158 // Expected failure: same "purpose" and root directory sent to the middleman generator
159 // (which results in the same output artifact), but different rules / middleman inputs.
160 }
161
162 // This should succeed because the java_binary's middleman is under the Java configuration's
163 // internal directory, while the cc_binary's middleman is under the cc config's directory.
janakre2df6e22018-03-19 14:31:00 -0700164 ConfiguredTargetAndData javaRuleB =
165 getConfiguredTargetAndDataDirectPrerequisite(
166 getConfiguredTargetAndData("//foo:d"), "//foo:libb.so");
Lukacs Berki4e844f02016-08-22 08:48:37 +0000167 List<Artifact> middleman2 = getAggregatingMiddleman(javaRuleB, false);
lberkiaea56b32017-05-30 12:35:33 +0200168 assertThat(
169 Iterables.getOnlyElement(middleman1)
170 .getExecPathString()
171 .equals(Iterables.getOnlyElement(middleman2).getExecPathString()))
172 .isFalse();
Dmitry Lomov18212f12015-11-23 18:07:34 +0000173 }
174
175 private void setupJavaPythonCcConfigurationFiles() throws IOException {
176 scratch.file(
177 "foo/BUILD",
Lukacs Berki4e844f02016-08-22 08:48:37 +0000178 "cc_binary(name = 'liba.so',",
179 " linkshared = 1,",
Dmitry Lomov18212f12015-11-23 18:07:34 +0000180 " srcs = ['a.cc'])",
Lukacs Berki4e844f02016-08-22 08:48:37 +0000181 "cc_binary(name = 'libb.so',",
182 " linkshared = 1,",
Dmitry Lomov18212f12015-11-23 18:07:34 +0000183 " srcs = ['b.cc'])",
184 "py_binary(name = 'c',",
Lukacs Berki4e844f02016-08-22 08:48:37 +0000185 " data = [':libb.so'],",
Dmitry Lomov18212f12015-11-23 18:07:34 +0000186 " srcs = ['c.py'])",
187 "java_binary(name = 'd',",
188 " srcs = ['d.java'],",
Lukacs Berki4e844f02016-08-22 08:48:37 +0000189 " data = [':libb.so'],",
Dmitry Lomov18212f12015-11-23 18:07:34 +0000190 " main_class = 'd')");
191 }
192}