aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/CcRules.java4
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCcModule.java107
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/CcModule.java234
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfiguration.java4
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionBuilder.java12
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/CppOptions.java11
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/LinkBuildVariables.java4
-rw-r--r--src/main/java/com/google/devtools/build/lib/skylarkbuildapi/cpp/BazelCcModuleApi.java204
-rw-r--r--src/main/java/com/google/devtools/build/lib/skylarkbuildapi/cpp/CcBootstrap.java29
-rw-r--r--src/main/java/com/google/devtools/build/skydoc/fakebuildapi/cpp/FakeCcModule.java39
-rw-r--r--src/test/java/com/google/devtools/build/lib/rules/cpp/BUILD16
-rw-r--r--src/test/java/com/google/devtools/build/lib/rules/cpp/LinkBuildVariablesTest.java48
-rw-r--r--src/test/java/com/google/devtools/build/lib/rules/cpp/SkylarkCcCommonTest.java111
-rw-r--r--src/test/java/com/google/devtools/build/lib/rules/cpp/SkylarkCcCommonTestHelper.java123
14 files changed, 938 insertions, 8 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/CcRules.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/CcRules.java
index eb8c6a9a56..620d810f61 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/CcRules.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/CcRules.java
@@ -19,6 +19,7 @@ import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider.RuleSe
import com.google.devtools.build.lib.bazel.rules.cpp.BazelCcBinaryRule;
import com.google.devtools.build.lib.bazel.rules.cpp.BazelCcImportRule;
import com.google.devtools.build.lib.bazel.rules.cpp.BazelCcLibraryRule;
+import com.google.devtools.build.lib.bazel.rules.cpp.BazelCcModule;
import com.google.devtools.build.lib.bazel.rules.cpp.BazelCcTestRule;
import com.google.devtools.build.lib.bazel.rules.cpp.BazelCppRuleClasses;
import com.google.devtools.build.lib.rules.core.CoreRules;
@@ -27,7 +28,6 @@ import com.google.devtools.build.lib.rules.cpp.CcHostToolchainAliasRule;
import com.google.devtools.build.lib.rules.cpp.CcImportRule;
import com.google.devtools.build.lib.rules.cpp.CcLibcTopAlias;
import com.google.devtools.build.lib.rules.cpp.CcLinkingInfo;
-import com.google.devtools.build.lib.rules.cpp.CcModule;
import com.google.devtools.build.lib.rules.cpp.CcToolchainAliasRule;
import com.google.devtools.build.lib.rules.cpp.CcToolchainRule;
import com.google.devtools.build.lib.rules.cpp.CcToolchainSuiteRule;
@@ -77,7 +77,7 @@ public class CcRules implements RuleSet {
builder.addRuleDefinition(new FdoProfileRule());
builder.addRuleDefinition(new FdoPrefetchHintsRule());
- builder.addSkylarkBootstrap(new CcBootstrap(new CcModule()));
+ builder.addSkylarkBootstrap(new CcBootstrap(new BazelCcModule()));
builder.addSkylarkAccessibleTopLevels("CcCompilationInfo", CcCompilationInfo.PROVIDER);
builder.addSkylarkAccessibleTopLevels("CcLinkingInfo", CcLinkingInfo.PROVIDER);
}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCcModule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCcModule.java
new file mode 100644
index 0000000000..3b3d944e74
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCcModule.java
@@ -0,0 +1,107 @@
+// Copyright 2018 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.bazel.rules.cpp;
+
+import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.analysis.skylark.SkylarkRuleContext;
+import com.google.devtools.build.lib.rules.cpp.CcCompilationHelper.CompilationInfo;
+import com.google.devtools.build.lib.rules.cpp.CcCompilationInfo;
+import com.google.devtools.build.lib.rules.cpp.CcCompilationOutputs;
+import com.google.devtools.build.lib.rules.cpp.CcLinkParams;
+import com.google.devtools.build.lib.rules.cpp.CcLinkingHelper.LinkingInfo;
+import com.google.devtools.build.lib.rules.cpp.CcLinkingInfo;
+import com.google.devtools.build.lib.rules.cpp.CcModule;
+import com.google.devtools.build.lib.rules.cpp.CcModule.CcSkylarkInfo;
+import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.FeatureConfiguration;
+import com.google.devtools.build.lib.rules.cpp.CcToolchainProvider;
+import com.google.devtools.build.lib.rules.cpp.CcToolchainVariables;
+import com.google.devtools.build.lib.rules.cpp.LinkerInputs.LibraryToLink;
+import com.google.devtools.build.lib.skylarkbuildapi.cpp.BazelCcModuleApi;
+import com.google.devtools.build.lib.syntax.EvalException;
+import com.google.devtools.build.lib.syntax.Runtime;
+import com.google.devtools.build.lib.syntax.SkylarkList;
+
+/**
+ * A module that contains Skylark utilities for C++ support.
+ *
+ * <p>This is a work in progress. The API is guarded behind --experimental_enable_cc_skylark_api.
+ * The API is under development and unstable.
+ */
+public class BazelCcModule extends CcModule
+ implements BazelCcModuleApi<
+ CcToolchainProvider,
+ FeatureConfiguration,
+ CompilationInfo,
+ CcCompilationInfo,
+ CcCompilationOutputs,
+ LinkingInfo,
+ CcLinkingInfo,
+ CcToolchainVariables,
+ LibraryToLink,
+ CcLinkParams,
+ CcSkylarkInfo> {
+
+ @Override
+ public CompilationInfo compile(
+ SkylarkRuleContext skylarkRuleContext,
+ FeatureConfiguration skylarkFeatureConfiguration,
+ CcToolchainProvider skylarkCcToolchainProvider,
+ SkylarkList<Artifact> sources,
+ SkylarkList<Artifact> headers,
+ Object skylarkIncludes,
+ Object skylarkCopts,
+ SkylarkList<CcCompilationInfo> ccCompilationInfos)
+ throws EvalException {
+ return BazelCcModule.compile(
+ BazelCppSemantics.INSTANCE,
+ skylarkRuleContext,
+ skylarkFeatureConfiguration,
+ skylarkCcToolchainProvider,
+ sources,
+ headers,
+ skylarkIncludes,
+ skylarkCopts,
+ /* generateNoPicOutputs= */ "conditionally",
+ /* generatePicOutputs= */ "conditionally",
+ /* skylarkAdditionalCompilationInputs= */ Runtime.NONE,
+ /* skylarkAdditionalIncludeScanningRoots= */ Runtime.NONE,
+ ccCompilationInfos,
+ /* purpose= */ Runtime.NONE);
+ }
+
+ @Override
+ public LinkingInfo link(
+ SkylarkRuleContext skylarkRuleContext,
+ FeatureConfiguration skylarkFeatureConfiguration,
+ CcToolchainProvider skylarkCcToolchainProvider,
+ CcCompilationOutputs ccCompilationOutputs,
+ Object skylarkLinkopts,
+ Object dynamicLibrary,
+ SkylarkList<CcLinkingInfo> skylarkCcLinkingInfos,
+ boolean neverLink)
+ throws InterruptedException, EvalException {
+ return BazelCcModule.link(
+ BazelCppSemantics.INSTANCE,
+ skylarkRuleContext,
+ skylarkFeatureConfiguration,
+ skylarkCcToolchainProvider,
+ ccCompilationOutputs,
+ skylarkLinkopts,
+ /* shouldCreateStaticLibraries= */ true,
+ dynamicLibrary,
+ skylarkCcLinkingInfos,
+ neverLink);
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcModule.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcModule.java
index d775a39793..1a6911c667 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcModule.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcModule.java
@@ -14,19 +14,25 @@
package com.google.devtools.build.lib.rules.cpp;
+import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.analysis.RuleContext;
import com.google.devtools.build.lib.analysis.platform.ToolchainInfo;
import com.google.devtools.build.lib.analysis.skylark.SkylarkRuleContext;
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.concurrent.ThreadSafety.Immutable;
+import com.google.devtools.build.lib.events.Location;
import com.google.devtools.build.lib.packages.NativeInfo;
import com.google.devtools.build.lib.packages.NativeProvider;
import com.google.devtools.build.lib.packages.Provider;
+import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException;
+import com.google.devtools.build.lib.rules.cpp.CcCompilationHelper.CompilationInfo;
+import com.google.devtools.build.lib.rules.cpp.CcLinkingHelper.LinkingInfo;
import com.google.devtools.build.lib.rules.cpp.CcModule.CcSkylarkInfo;
import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.FeatureConfiguration;
import com.google.devtools.build.lib.rules.cpp.LinkerInputs.LibraryToLink;
@@ -42,6 +48,11 @@ import com.google.devtools.build.lib.syntax.EvalUtils;
import com.google.devtools.build.lib.syntax.SkylarkDict;
import com.google.devtools.build.lib.syntax.SkylarkList;
import com.google.devtools.build.lib.syntax.SkylarkNestedSet;
+import com.google.devtools.build.lib.util.Pair;
+import com.google.devtools.build.lib.vfs.PathFragment;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
import javax.annotation.Nullable;
/** A module that contains Skylark utilities for C++ support. */
@@ -54,6 +65,41 @@ public class CcModule
CcLinkParams,
CcSkylarkInfo> {
+ private enum RegisterActions {
+ ALWAYS,
+ NEVER,
+ CONDITIONALLY;
+
+ private final String skylarkName;
+
+ RegisterActions() {
+ this.skylarkName = toString().toLowerCase();
+ }
+
+ public String getSkylarkName() {
+ return skylarkName;
+ }
+
+ public static RegisterActions fromString(
+ String skylarkName, Location location, String fieldForError) throws EvalException {
+ for (RegisterActions registerActions : values()) {
+ if (registerActions.getSkylarkName().equals(skylarkName)) {
+ return registerActions;
+ }
+ }
+ throw new EvalException(
+ location,
+ String.format(
+ "Possibles values for %s: %s",
+ fieldForError,
+ Joiner.on(", ")
+ .join(
+ Arrays.stream(values())
+ .map(RegisterActions::getSkylarkName)
+ .collect(ImmutableList.toImmutableList()))));
+ }
+ }
+
/**
* C++ Skylark rules should have this provider so that native rules can depend on them. This will
* eventually go away once b/73921130 is fixed.
@@ -329,4 +375,192 @@ public class CcModule
SkylarkList<CcCompilationInfo> ccCompilationInfos) {
return CcCompilationInfo.merge(ccCompilationInfos);
}
+
+ protected static CompilationInfo compile(
+ CppSemantics cppSemantics,
+ SkylarkRuleContext skylarkRuleContext,
+ Object skylarkFeatureConfiguration,
+ Object skylarkCcToolchainProvider,
+ SkylarkList<Artifact> sources,
+ SkylarkList<Artifact> headers,
+ Object skylarkIncludes,
+ Object skylarkCopts,
+ String generateNoPicOutputs,
+ String generatePicOutputs,
+ Object skylarkAdditionalCompilationInputs,
+ Object skylarkAdditionalIncludeScanningRoots,
+ SkylarkList<CcCompilationInfo> ccCompilationInfos,
+ Object purpose)
+ throws EvalException {
+ CcCommon.checkRuleWhitelisted(skylarkRuleContext);
+ RuleContext ruleContext = skylarkRuleContext.getRuleContext();
+ CcToolchainProvider ccToolchainProvider = convertFromNoneable(skylarkCcToolchainProvider, null);
+ if (ccToolchainProvider == null) {
+ ccToolchainProvider = CppHelper.getToolchainUsingDefaultCcToolchainAttribute(ruleContext);
+ }
+ FeatureConfiguration featureConfiguration =
+ convertFromNoneable(skylarkFeatureConfiguration, null);
+ if (featureConfiguration == null) {
+ featureConfiguration =
+ CcCommon.configureFeaturesOrReportRuleError(ruleContext, ccToolchainProvider);
+ }
+ Pair<List<Artifact>, List<Artifact>> separatedHeadersAndSources =
+ separateSourcesFromHeaders(sources);
+ FdoSupportProvider fdoSupport =
+ CppHelper.getFdoSupportUsingDefaultCcToolchainAttribute(ruleContext);
+ // TODO(plf): Need to flatten the nested set to convert the Strings to PathFragment. This could
+ // be avoided if path fragments are ever added to Skylark or in the C++ code we take Strings
+ // instead of PathFragments.
+ List<String> includeDirs = convertSkylarkListOrNestedSetToList(skylarkIncludes, String.class);
+ CcCompilationHelper helper =
+ new CcCompilationHelper(
+ ruleContext,
+ cppSemantics,
+ featureConfiguration,
+ CcCompilationHelper.SourceCategory.CC,
+ ccToolchainProvider,
+ fdoSupport)
+ .addPublicHeaders(headers)
+ .addIncludeDirs(
+ includeDirs
+ .stream()
+ .map(PathFragment::create)
+ .collect(ImmutableList.toImmutableList()))
+ .addPrivateHeaders(separatedHeadersAndSources.first)
+ .addSources(separatedHeadersAndSources.second)
+ .addCcCompilationInfos(ccCompilationInfos)
+ .setPurpose(convertFromNoneable(purpose, null));
+
+ SkylarkNestedSet additionalCompilationInputs =
+ convertFromNoneable(skylarkAdditionalCompilationInputs, null);
+ if (additionalCompilationInputs != null) {
+ helper.addAdditionalCompilationInputs(
+ additionalCompilationInputs.toCollection(Artifact.class));
+ }
+
+ SkylarkNestedSet additionalIncludeScanningRoots =
+ convertFromNoneable(skylarkAdditionalIncludeScanningRoots, null);
+ if (additionalIncludeScanningRoots != null) {
+ helper.addAditionalIncludeScanningRoots(
+ additionalIncludeScanningRoots.toCollection(Artifact.class));
+ }
+
+ SkylarkNestedSet copts = convertFromNoneable(skylarkCopts, null);
+ if (copts != null) {
+ helper.setCopts(copts.getSet(String.class));
+ }
+
+ Location location = ruleContext.getRule().getLocation();
+ RegisterActions generateNoPicOption =
+ RegisterActions.fromString(generateNoPicOutputs, location, "generate_no_pic_outputs");
+ if (!generateNoPicOption.equals(RegisterActions.CONDITIONALLY)) {
+ helper.setGenerateNoPicAction(generateNoPicOption == RegisterActions.ALWAYS);
+ }
+ RegisterActions generatePicOption =
+ RegisterActions.fromString(generatePicOutputs, location, "generate_pic_outputs");
+ if (!generatePicOption.equals(RegisterActions.CONDITIONALLY)) {
+ helper.setGeneratePicAction(generatePicOption == RegisterActions.ALWAYS);
+ }
+ try {
+ return helper.compile();
+ } catch (RuleErrorException e) {
+ throw new EvalException(ruleContext.getRule().getLocation(), e);
+ }
+ }
+
+ protected static LinkingInfo link(
+ CppSemantics cppSemantics,
+ SkylarkRuleContext skylarkRuleContext,
+ Object skylarkFeatureConfiguration,
+ Object skylarkCcToolchainProvider,
+ CcCompilationOutputs ccCompilationOutputs,
+ Object skylarkLinkopts,
+ boolean shouldCreateStaticLibraries,
+ Object dynamicLibrary,
+ SkylarkList<CcLinkingInfo> skylarkCcLinkingInfos,
+ boolean neverLink)
+ throws InterruptedException, EvalException {
+ CcCommon.checkRuleWhitelisted(skylarkRuleContext);
+ RuleContext ruleContext = skylarkRuleContext.getRuleContext();
+ CcToolchainProvider ccToolchainProvider = convertFromNoneable(skylarkCcToolchainProvider, null);
+ if (ccToolchainProvider == null) {
+ ccToolchainProvider = CppHelper.getToolchainUsingDefaultCcToolchainAttribute(ruleContext);
+ }
+ FeatureConfiguration featureConfiguration =
+ convertFromNoneable(skylarkFeatureConfiguration, null);
+ if (featureConfiguration == null) {
+ featureConfiguration =
+ CcCommon.configureFeaturesOrReportRuleError(ruleContext, ccToolchainProvider);
+ }
+ FdoSupportProvider fdoSupport =
+ CppHelper.getFdoSupportUsingDefaultCcToolchainAttribute(ruleContext);
+ NestedSet<String> linkopts =
+ convertSkylarkListOrNestedSetToNestedSet(skylarkLinkopts, String.class);
+ CcLinkingHelper helper =
+ new CcLinkingHelper(
+ ruleContext,
+ cppSemantics,
+ featureConfiguration,
+ ccToolchainProvider,
+ fdoSupport,
+ ruleContext.getConfiguration())
+ .addLinkopts(linkopts)
+ .setShouldCreateStaticLibraries(shouldCreateStaticLibraries)
+ .setDynamicLibrary(convertFromNoneable(dynamicLibrary, null))
+ .addCcLinkingInfos(skylarkCcLinkingInfos)
+ .setNeverLink(neverLink);
+ try {
+ return helper.link(ccCompilationOutputs, CcCompilationContext.EMPTY);
+ } catch (RuleErrorException e) {
+ throw new EvalException(ruleContext.getRule().getLocation(), e);
+ }
+ }
+
+ /**
+ * TODO(plf): This method exists only temporarily. Once the existing C++ rules have been migrated,
+ * they should pass sources and headers separately.
+ */
+ private static Pair<List<Artifact>, List<Artifact>> separateSourcesFromHeaders(
+ Iterable<Artifact> artifacts) {
+ List<Artifact> headers = new ArrayList<>();
+ List<Artifact> sources = new ArrayList<>();
+ for (Artifact artifact : artifacts) {
+ if (CppFileTypes.CPP_HEADER.matches(artifact.getExecPath())) {
+ headers.add(artifact);
+ } else {
+ sources.add(artifact);
+ }
+ }
+ return Pair.of(headers, sources);
+ }
+
+ /** Converts an object that can be the either SkylarkNestedSet or None into NestedSet. */
+ @SuppressWarnings("unchecked")
+ protected Object skylarkListToSkylarkNestedSet(Object o) throws EvalException {
+ if (o instanceof SkylarkList) {
+ SkylarkList<String> list = (SkylarkList<String>) o;
+ SkylarkNestedSet.Builder builder =
+ SkylarkNestedSet.builder(Order.STABLE_ORDER, Location.BUILTIN);
+ for (Object entry : list) {
+ builder.addDirect(entry);
+ }
+ return builder.build();
+ }
+ return o;
+ }
+
+ @SuppressWarnings("unchecked")
+ private static <T> List<T> convertSkylarkListOrNestedSetToList(Object o, Class<T> type) {
+ return o instanceof SkylarkNestedSet
+ ? ((SkylarkNestedSet) o).getSet(type).toList()
+ : ((SkylarkList) o).getImmutableList();
+ }
+
+ @SuppressWarnings("unchecked")
+ private static <T> NestedSet<T> convertSkylarkListOrNestedSetToNestedSet(
+ Object o, Class<T> type) {
+ return o instanceof SkylarkNestedSet
+ ? ((SkylarkNestedSet) o).getSet(type)
+ : NestedSetBuilder.wrap(Order.COMPILE_ORDER, (SkylarkList<T>) o);
+ }
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfiguration.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfiguration.java
index 8a9fc665d4..82a4ae7176 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfiguration.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfiguration.java
@@ -104,6 +104,10 @@ public final class CppConfiguration extends BuildConfiguration.Fragment
return cppOptions.disableLinkingModeFlags;
}
+ public boolean enableLinkoptsInUserLinkFlags() {
+ return cppOptions.enableLinkoptsInUserLinkFlags;
+ }
+
/**
* An enumeration of all the tools that comprise a toolchain.
*/
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionBuilder.java
index 56bca06241..8a99e731a3 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionBuilder.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionBuilder.java
@@ -926,6 +926,16 @@ public class CppLinkActionBuilder {
CcToolchainVariables variables;
try {
+ ImmutableList<String> userLinkFlags;
+ if (cppConfiguration.enableLinkoptsInUserLinkFlags()) {
+ userLinkFlags =
+ ImmutableList.<String>builder()
+ .addAll(linkopts)
+ .addAll(toolchain.getLinkOptions())
+ .build();
+ } else {
+ userLinkFlags = ImmutableList.copyOf(linkopts);
+ }
variables =
LinkBuildVariables.setupVariables(
getLinkType().linkerOrArchiver().equals(LinkerOrArchiver.LINKER),
@@ -941,7 +951,7 @@ public class CppLinkActionBuilder {
featureConfiguration,
useTestOnlyFlags,
isLtoIndexing,
- ImmutableList.copyOf(linkopts),
+ userLinkFlags,
toolchain.getInterfaceSoBuilder().getExecPathString(),
interfaceOutput != null ? interfaceOutput.getExecPathString() : null,
ltoOutputRootPrefix,
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppOptions.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppOptions.java
index 5992b22f5c..b5616f0890 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppOptions.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppOptions.java
@@ -860,6 +860,17 @@ public class CppOptions extends FragmentOptions {
+ "field of CcLinkingInfo. See b/111289526.")
public boolean enableCcDynamicLibrariesForRuntime;
+ @Option(
+ name = "experimental_linkopts_in_user_link_flags",
+ defaultValue = "false",
+ documentationCategory = OptionDocumentationCategory.UNDOCUMENTED,
+ effectTags = {OptionEffectTag.LOADING_AND_ANALYSIS, OptionEffectTag.LOADING_AND_ANALYSIS},
+ metadataTags = {OptionMetadataTag.EXPERIMENTAL},
+ help =
+ "If true, flags coming from --linkopt Bazel option will appear in user_link_flags "
+ + "crosstool variable.")
+ public boolean enableLinkoptsInUserLinkFlags;
+
@Override
public FragmentOptions getHost() {
CppOptions host = (CppOptions) getDefault();
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/LinkBuildVariables.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/LinkBuildVariables.java
index b57dc237be..a26b8b76cc 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/LinkBuildVariables.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/LinkBuildVariables.java
@@ -329,7 +329,9 @@ public enum LinkBuildVariables {
result.addAll(ccToolchainProvider.getTestOnlyLinkOptions());
}
- result.addAll(ccToolchainProvider.getLinkOptions());
+ if (!cppConfiguration.enableLinkoptsInUserLinkFlags()) {
+ result.addAll(ccToolchainProvider.getLinkOptions());
+ }
// -pie is not compatible with shared and should be
// removed when the latter is part of the link command. Should we need to further
diff --git a/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/cpp/BazelCcModuleApi.java b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/cpp/BazelCcModuleApi.java
new file mode 100644
index 0000000000..0238e0c7ab
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/cpp/BazelCcModuleApi.java
@@ -0,0 +1,204 @@
+// Copyright 2018 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.skylarkbuildapi.cpp;
+
+import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.analysis.skylark.SkylarkRuleContext;
+import com.google.devtools.build.lib.skylarkbuildapi.SkylarkRuleContextApi;
+import com.google.devtools.build.lib.skylarkinterface.Param;
+import com.google.devtools.build.lib.skylarkinterface.ParamType;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
+import com.google.devtools.build.lib.syntax.EvalException;
+import com.google.devtools.build.lib.syntax.Runtime.NoneType;
+import com.google.devtools.build.lib.syntax.SkylarkList;
+import com.google.devtools.build.lib.syntax.SkylarkNestedSet;
+
+/** Utilites related to C++ support. */
+@SkylarkModule(
+ name = "cc_common",
+ doc = "Utilities for C++ compilation, linking, and command line generation.")
+// TODO(b/111365281): Add experimental field once it's available.
+public interface BazelCcModuleApi<
+ CcToolchainProviderT extends CcToolchainProviderApi,
+ FeatureConfigurationT extends FeatureConfigurationApi,
+ CompilationInfoT extends CompilationInfoApi,
+ CcCompilationInfoT extends CcCompilationInfoApi,
+ CcCompilationOutputsT extends CcCompilationOutputsApi,
+ LinkingInfoT extends LinkingInfoApi,
+ CcLinkingInfoT extends CcLinkingInfoApi,
+ CcToolchainVariablesT extends CcToolchainVariablesApi,
+ LibraryToLinkT extends LibraryToLinkApi,
+ CcLinkParamsT extends CcLinkParamsApi,
+ CcSkylarkInfoT extends CcSkylarkInfoApi>
+ extends CcModuleApi<
+ CcToolchainProviderT,
+ FeatureConfigurationT,
+ CcToolchainVariablesT,
+ LibraryToLinkT,
+ CcLinkParamsT,
+ CcSkylarkInfoT> {
+
+ @SkylarkCallable(
+ name = "compile",
+ documented = false,
+ parameters = {
+ @Param(
+ name = "ctx",
+ positional = false,
+ named = true,
+ type = SkylarkRuleContextApi.class,
+ doc = "The rule context."),
+ @Param(
+ name = "feature_configuration",
+ doc = "Feature configuration to be queried.",
+ positional = false,
+ named = true,
+ type = FeatureConfigurationApi.class),
+ @Param(
+ name = "cc_toolchain",
+ doc = "C++ toolchain provider to be used.",
+ positional = false,
+ named = true,
+ type = CcToolchainProviderApi.class),
+ @Param(
+ name = "srcs",
+ doc = "The list of source files to be compiled, see cc_library.srcs",
+ positional = false,
+ named = true,
+ defaultValue = "[]",
+ type = SkylarkList.class),
+ @Param(
+ name = "hdrs",
+ doc = "The list of public headers to be provided to dependents, see cc_library.hdrs",
+ positional = false,
+ named = true,
+ defaultValue = "[]",
+ type = SkylarkList.class),
+ @Param(
+ name = "includes",
+ doc = "Include directories",
+ positional = false,
+ named = true,
+ noneable = true,
+ defaultValue = "[]",
+ allowedTypes = {
+ @ParamType(type = SkylarkNestedSet.class),
+ @ParamType(type = SkylarkList.class)
+ }),
+ @Param(
+ name = "copts",
+ doc = "Additional list of compiler options.",
+ positional = false,
+ named = true,
+ noneable = true,
+ defaultValue = "None",
+ allowedTypes = {
+ @ParamType(type = SkylarkNestedSet.class),
+ @ParamType(type = NoneType.class)
+ }),
+ @Param(
+ name = "cc_compilation_infos",
+ doc = "cc_compilation_info instances affecting compilation, e.g. from dependencies",
+ positional = false,
+ named = true,
+ defaultValue = "[]",
+ type = SkylarkList.class)
+ })
+ CompilationInfoT compile(
+ SkylarkRuleContext skylarkRuleContext,
+ FeatureConfigurationT skylarkFeatureConfiguration,
+ CcToolchainProviderT skylarkCcToolchainProvider,
+ SkylarkList<Artifact> sources,
+ SkylarkList<Artifact> headers,
+ Object skylarkIncludes,
+ Object skylarkCopts,
+ SkylarkList<CcCompilationInfoT> ccCompilationInfos)
+ throws EvalException;
+
+ @SkylarkCallable(
+ name = "link",
+ documented = false,
+ parameters = {
+ @Param(
+ name = "ctx",
+ positional = false,
+ named = true,
+ type = SkylarkRuleContextApi.class,
+ doc = "The rule context."),
+ @Param(
+ name = "feature_configuration",
+ doc = "Feature configuration to be queried.",
+ positional = false,
+ named = true,
+ type = FeatureConfigurationApi.class),
+ @Param(
+ name = "cc_toolchain",
+ doc = "C++ toolchain provider to be used.",
+ positional = false,
+ named = true,
+ type = CcToolchainProviderApi.class),
+ @Param(
+ name = "cc_compilation_outputs",
+ doc = "List of object files to be linked.",
+ positional = false,
+ named = true,
+ defaultValue = "[]",
+ type = CcCompilationOutputsApi.class),
+ @Param(
+ name = "linkopts",
+ doc = "Additional list of linker options.",
+ positional = false,
+ named = true,
+ defaultValue = "[]",
+ noneable = true,
+ allowedTypes = {
+ @ParamType(type = SkylarkList.class),
+ @ParamType(type = SkylarkNestedSet.class)
+ }),
+ @Param(
+ name = "dynamic_library",
+ doc = "Dynamic library artifact.",
+ positional = false,
+ named = true,
+ defaultValue = "None",
+ noneable = true,
+ allowedTypes = {@ParamType(type = NoneType.class), @ParamType(type = Artifact.class)}),
+ @Param(
+ name = "cc_linking_infos",
+ doc = "cc_linking_info instances affecting linking, e.g. from dependencies",
+ positional = false,
+ named = true,
+ noneable = true,
+ defaultValue = "[]",
+ type = SkylarkList.class),
+ @Param(
+ name = "neverlink",
+ doc = "True if this should never be linked against other libraries.",
+ positional = false,
+ named = true,
+ defaultValue = "False"),
+ })
+ LinkingInfoT link(
+ SkylarkRuleContext skylarkRuleContext,
+ FeatureConfigurationT skylarkFeatureConfiguration,
+ CcToolchainProviderT skylarkCcToolchainProvider,
+ CcCompilationOutputsT ccCompilationOutputs,
+ Object skylarkLinkopts,
+ Object dynamicLibrary,
+ SkylarkList<CcLinkingInfoT> skylarkCcLinkingInfos,
+ boolean neverLink)
+ throws InterruptedException, EvalException;
+}
diff --git a/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/cpp/CcBootstrap.java b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/cpp/CcBootstrap.java
index 4286d3dbe2..02be5be14f 100644
--- a/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/cpp/CcBootstrap.java
+++ b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/cpp/CcBootstrap.java
@@ -22,9 +22,34 @@ import com.google.devtools.build.lib.skylarkbuildapi.Bootstrap;
*/
public class CcBootstrap implements Bootstrap {
- private final CcModuleApi ccModule;
+ private final BazelCcModuleApi<
+ ? extends CcToolchainProviderApi,
+ ? extends FeatureConfigurationApi,
+ ? extends CompilationInfoApi,
+ ? extends CcCompilationInfoApi,
+ ? extends CcCompilationOutputsApi,
+ ? extends LinkingInfoApi,
+ ? extends CcLinkingInfoApi,
+ ? extends CcToolchainVariablesApi,
+ ? extends LibraryToLinkApi,
+ ? extends CcLinkParamsApi,
+ ? extends CcSkylarkInfoApi>
+ ccModule;
- public CcBootstrap(CcModuleApi ccModule) {
+ public CcBootstrap(
+ BazelCcModuleApi<
+ ? extends CcToolchainProviderApi,
+ ? extends FeatureConfigurationApi,
+ ? extends CompilationInfoApi,
+ ? extends CcCompilationInfoApi,
+ ? extends CcCompilationOutputsApi,
+ ? extends LinkingInfoApi,
+ ? extends CcLinkingInfoApi,
+ ? extends CcToolchainVariablesApi,
+ ? extends LibraryToLinkApi,
+ ? extends CcLinkParamsApi,
+ ? extends CcSkylarkInfoApi>
+ ccModule) {
this.ccModule = ccModule;
}
diff --git a/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/cpp/FakeCcModule.java b/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/cpp/FakeCcModule.java
index 6e3ab8377a..25a187a621 100644
--- a/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/cpp/FakeCcModule.java
+++ b/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/cpp/FakeCcModule.java
@@ -17,13 +17,19 @@ package com.google.devtools.build.skydoc.fakebuildapi.cpp;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.analysis.skylark.SkylarkRuleContext;
import com.google.devtools.build.lib.skylarkbuildapi.ProviderApi;
+import com.google.devtools.build.lib.skylarkbuildapi.cpp.BazelCcModuleApi;
+import com.google.devtools.build.lib.skylarkbuildapi.cpp.CcCompilationInfoApi;
+import com.google.devtools.build.lib.skylarkbuildapi.cpp.CcCompilationOutputsApi;
import com.google.devtools.build.lib.skylarkbuildapi.cpp.CcLinkParamsApi;
+import com.google.devtools.build.lib.skylarkbuildapi.cpp.CcLinkingInfoApi;
import com.google.devtools.build.lib.skylarkbuildapi.cpp.CcModuleApi;
import com.google.devtools.build.lib.skylarkbuildapi.cpp.CcSkylarkInfoApi;
import com.google.devtools.build.lib.skylarkbuildapi.cpp.CcToolchainProviderApi;
import com.google.devtools.build.lib.skylarkbuildapi.cpp.CcToolchainVariablesApi;
+import com.google.devtools.build.lib.skylarkbuildapi.cpp.CompilationInfoApi;
import com.google.devtools.build.lib.skylarkbuildapi.cpp.FeatureConfigurationApi;
import com.google.devtools.build.lib.skylarkbuildapi.cpp.LibraryToLinkApi;
+import com.google.devtools.build.lib.skylarkbuildapi.cpp.LinkingInfoApi;
import com.google.devtools.build.lib.syntax.EvalException;
import com.google.devtools.build.lib.syntax.SkylarkDict;
import com.google.devtools.build.lib.syntax.SkylarkList;
@@ -31,9 +37,14 @@ import com.google.devtools.build.skydoc.fakebuildapi.FakeProviderApi;
/** Fake implementation of {@link CcModuleApi}. */
public class FakeCcModule
- implements CcModuleApi<
+ implements BazelCcModuleApi<
CcToolchainProviderApi,
FeatureConfigurationApi,
+ CompilationInfoApi,
+ CcCompilationInfoApi,
+ CcCompilationOutputsApi,
+ LinkingInfoApi,
+ CcLinkingInfoApi,
CcToolchainVariablesApi,
LibraryToLinkApi,
CcLinkParamsApi,
@@ -126,4 +137,30 @@ public class FakeCcModule
throws EvalException {
return null;
}
+
+ @Override
+ public CompilationInfoApi compile(
+ SkylarkRuleContext skylarkRuleContext,
+ FeatureConfigurationApi skylarkFeatureConfiguration,
+ CcToolchainProviderApi skylarkCcToolchainProvider,
+ SkylarkList<Artifact> sources,
+ SkylarkList<Artifact> headers,
+ Object skylarkIncludes,
+ Object skylarkCopts,
+ SkylarkList<CcCompilationInfoApi> ccCompilationInfos) {
+ return null;
+ }
+
+ @Override
+ public LinkingInfoApi link(
+ SkylarkRuleContext skylarkRuleContext,
+ FeatureConfigurationApi skylarkFeatureConfiguration,
+ CcToolchainProviderApi skylarkCcToolchainProvider,
+ CcCompilationOutputsApi ccCompilationOutputs,
+ Object skylarkLinkopts,
+ Object dynamicLibrary,
+ SkylarkList<CcLinkingInfoApi> skylarkCcLinkingInfos,
+ boolean neverLink) {
+ return null;
+ }
}
diff --git a/src/test/java/com/google/devtools/build/lib/rules/cpp/BUILD b/src/test/java/com/google/devtools/build/lib/rules/cpp/BUILD
index 8fa0c86c49..e15d4584cd 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/cpp/BUILD
+++ b/src/test/java/com/google/devtools/build/lib/rules/cpp/BUILD
@@ -14,7 +14,10 @@ java_test(
name = "cpp-rules-tests",
srcs = glob(
["*.java"],
- exclude = ["CcImportBaseConfiguredTargetTest.java"],
+ exclude = [
+ "CcImportBaseConfiguredTargetTest.java",
+ "SkylarkCcCommonTestHelper.java",
+ ],
) + ["proto/CcProtoLibraryTest.java"],
resources = [
"//tools/build_defs/cc:action_names.bzl",
@@ -25,6 +28,7 @@ java_test(
test_class = "com.google.devtools.build.lib.AllTests",
deps = [
":CcImportBaseConfiguredTargetTest",
+ ":SkylarkCcCommonTestHelper",
"//src/main/java/com/google/devtools/build/lib:bazel-main",
"//src/main/java/com/google/devtools/build/lib:bazel-rules",
"//src/main/java/com/google/devtools/build/lib:build-base",
@@ -43,6 +47,7 @@ java_test(
"//src/main/java/com/google/devtools/build/lib/skyframe/serialization",
"//src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec",
"//src/main/java/com/google/devtools/build/lib/skyframe/serialization/testutils",
+ "//src/main/java/com/google/devtools/build/lib/skylarkbuildapi/cpp",
"//src/main/java/com/google/devtools/build/lib/vfs",
"//src/main/java/com/google/devtools/build/lib/vfs/inmemoryfs",
"//src/main/java/com/google/devtools/common/options",
@@ -102,6 +107,15 @@ java_library(
],
)
+java_library(
+ name = "SkylarkCcCommonTestHelper",
+ srcs = ["SkylarkCcCommonTestHelper.java"],
+ deps = [
+ "//src/test/java/com/google/devtools/build/lib:analysis_testutil",
+ "//src/test/java/com/google/devtools/build/lib:testutil",
+ ],
+)
+
test_suite(
name = "windows_tests",
tags = [
diff --git a/src/test/java/com/google/devtools/build/lib/rules/cpp/LinkBuildVariablesTest.java b/src/test/java/com/google/devtools/build/lib/rules/cpp/LinkBuildVariablesTest.java
index cabbb2da82..cffef0494c 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/cpp/LinkBuildVariablesTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/cpp/LinkBuildVariablesTest.java
@@ -16,6 +16,7 @@ package com.google.devtools.build.lib.rules.cpp;
import static com.google.common.truth.Truth.assertThat;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.devtools.build.lib.actions.Action;
import com.google.devtools.build.lib.actions.Artifact;
@@ -367,4 +368,51 @@ public class LinkBuildVariablesTest extends LinkBuildVariablesTestCase {
}
return null;
}
+
+ @Test
+ public void testUserLinkFlags() throws Exception {
+ useConfiguration("--linkopt=-bar", "--noexperimental_linkopts_in_user_link_flags");
+
+ scratch.file("x/BUILD", "cc_binary(name = 'foo', srcs = ['a.cc'], linkopts = ['-foo'])");
+ scratch.file("x/a.cc");
+
+ ConfiguredTarget testTarget = getConfiguredTarget("//x:foo");
+ CcToolchainVariables testVariables =
+ getLinkBuildVariables(testTarget, LinkTargetType.EXECUTABLE);
+
+ ImmutableList<String> userLinkFlags =
+ CcToolchainVariables.toStringList(
+ testVariables, LinkBuildVariables.USER_LINK_FLAGS.getVariableName());
+ assertThat(userLinkFlags).contains("-foo");
+ assertThat(userLinkFlags).doesNotContain("-bar");
+
+ ImmutableList<String> legacyLinkFlags =
+ CcToolchainVariables.toStringList(
+ testVariables, LinkBuildVariables.LEGACY_LINK_FLAGS.getVariableName());
+ assertThat(legacyLinkFlags).doesNotContain("-foo");
+ assertThat(legacyLinkFlags).contains("-bar");
+ }
+
+ @Test
+ public void testUserLinkFlagsWithLinkoptOption() throws Exception {
+ useConfiguration("--linkopt=-bar", "--experimental_linkopts_in_user_link_flags");
+
+ scratch.file("x/BUILD", "cc_binary(name = 'foo', srcs = ['a.cc'], linkopts = ['-foo'])");
+ scratch.file("x/a.cc");
+
+ ConfiguredTarget testTarget = getConfiguredTarget("//x:foo");
+ CcToolchainVariables testVariables =
+ getLinkBuildVariables(testTarget, LinkTargetType.EXECUTABLE);
+
+ ImmutableList<String> userLinkFlags =
+ CcToolchainVariables.toStringList(
+ testVariables, LinkBuildVariables.USER_LINK_FLAGS.getVariableName());
+ assertThat(userLinkFlags).containsAllOf("-foo", "-bar").inOrder();
+
+ ImmutableList<String> legacyLinkFlags =
+ CcToolchainVariables.toStringList(
+ testVariables, LinkBuildVariables.LEGACY_LINK_FLAGS.getVariableName());
+ assertThat(legacyLinkFlags).doesNotContain("-foo");
+ assertThat(legacyLinkFlags).doesNotContain("-bar");
+ }
}
diff --git a/src/test/java/com/google/devtools/build/lib/rules/cpp/SkylarkCcCommonTest.java b/src/test/java/com/google/devtools/build/lib/rules/cpp/SkylarkCcCommonTest.java
index 86d914f073..cbb84be9ef 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/cpp/SkylarkCcCommonTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/cpp/SkylarkCcCommonTest.java
@@ -28,6 +28,7 @@ import com.google.devtools.build.lib.analysis.util.BuildViewTestCase;
import com.google.devtools.build.lib.packages.util.ResourceLoader;
import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.FeatureConfiguration;
import com.google.devtools.build.lib.rules.cpp.LinkerInputs.LibraryToLink;
+import com.google.devtools.build.lib.skylarkbuildapi.cpp.LibraryToLinkApi;
import com.google.devtools.build.lib.syntax.SkylarkDict;
import com.google.devtools.build.lib.syntax.SkylarkList;
import com.google.devtools.build.lib.syntax.SkylarkNestedSet;
@@ -1245,4 +1246,114 @@ public class SkylarkCcCommonTest extends BuildViewTestCase {
" fragments = ['cpp'],",
");");
}
+
+ @Test
+ public void testCcNativeRuleDependingOnSkylarkDefinedRule() throws Exception {
+ SkylarkCcCommonTestHelper.createFiles(scratch, "tools/build_defs/cc");
+ assertThat(getConfiguredTarget("//foo:bin")).isNotNull();
+ }
+
+ @Test
+ public void testWhitelist() throws Exception {
+ SkylarkCcCommonTestHelper.createFiles(scratch, "foo/bar");
+ AssertionError e = assertThrows(AssertionError.class, () -> getConfiguredTarget("//foo:bin"));
+ assertThat(e).hasMessageThat().contains("C++ Skylark API is for the time being");
+ }
+
+ @Test
+ public void testCopts() throws Exception {
+ SkylarkCcCommonTestHelper.createFilesForTestingCompilation(
+ scratch, "tools/build_defs/foo", "copts=depset(['-COMPILATION_OPTION'])");
+ assertThat(getConfiguredTarget("//foo:bin")).isNotNull();
+ ConfiguredTarget target = getConfiguredTarget("//foo:skylark_lib");
+ CppCompileAction action =
+ (CppCompileAction) getGeneratingAction(artifactByPath(getFilesToBuild(target), ".o"));
+ assertThat(action.getArguments()).contains("-COMPILATION_OPTION");
+ }
+
+ @Test
+ public void testIncludeDirs() throws Exception {
+ SkylarkCcCommonTestHelper.createFilesForTestingCompilation(
+ scratch, "tools/build_defs/foo", "includes=depset(['foo/bar', 'baz/qux'])");
+ ConfiguredTarget target = getConfiguredTarget("//foo:skylark_lib");
+ assertThat(target).isNotNull();
+ CppCompileAction action =
+ (CppCompileAction) getGeneratingAction(artifactByPath(getFilesToBuild(target), ".o"));
+ assertThat(action.getArguments()).containsAllOf("-Ifoo/bar", "-Ibaz/qux");
+ }
+
+ @Test
+ public void testLinkingOutputs() throws Exception {
+ SkylarkCcCommonTestHelper.createFiles(scratch, "tools/build_defs/foo");
+ ConfiguredTarget target = getConfiguredTarget("//foo:skylark_lib");
+ assertThat(target).isNotNull();
+ @SuppressWarnings("unchecked")
+ SkylarkList<LibraryToLinkApi> libraries =
+ (SkylarkList<LibraryToLinkApi>) target.get("libraries");
+ assertThat(
+ libraries
+ .stream()
+ .map(x -> x.getOriginalLibraryArtifact().getFilename())
+ .collect(ImmutableList.toImmutableList()))
+ .contains("libskylark_lib.so");
+ }
+
+ @Test
+ public void testLinkopts() throws Exception {
+ SkylarkCcCommonTestHelper.createFilesForTestingLinking(
+ scratch, "tools/build_defs/foo", "linkopts=depset(['-LINKING_OPTION'])");
+ ConfiguredTarget target = getConfiguredTarget("//foo:skylark_lib");
+ assertThat(target).isNotNull();
+ CppLinkAction action =
+ (CppLinkAction) getGeneratingAction(artifactByPath(getFilesToBuild(target), ".so"));
+ assertThat(action.getArguments()).contains("-LINKING_OPTION");
+ }
+
+ @Test
+ public void testSettingDynamicLibraryArtifact() throws Exception {
+ SkylarkCcCommonTestHelper.createFilesForTestingLinking(
+ scratch,
+ "tools/build_defs/foo",
+ "dynamic_library=ctx.actions.declare_file('dynamic_lib_artifact.so')");
+ assertThat(getConfiguredTarget("//foo:skylark_lib")).isNotNull();
+ ConfiguredTarget target = getConfiguredTarget("//foo:skylark_lib");
+ assertThat(
+ getFilesToBuild(target)
+ .toCollection()
+ .stream()
+ .map(x -> x.getFilename())
+ .collect(ImmutableList.toImmutableList()))
+ .contains("dynamic_lib_artifact.so");
+ }
+
+ @Test
+ public void testCcLinkingInfos() throws Exception {
+ SkylarkCcCommonTestHelper.createFilesForTestingLinking(
+ scratch, "tools/build_defs/foo", "cc_linking_infos=dep_cc_linking_infos");
+ assertThat(getConfiguredTarget("//foo:bin")).isNotNull();
+ ConfiguredTarget target = getConfiguredTarget("//foo:bin");
+ CppLinkAction action =
+ (CppLinkAction) getGeneratingAction(artifactByPath(getFilesToBuild(target), "bin"));
+ assertThat(action.getArguments()).containsAllOf("-DEP1_LINKOPT", "-DEP2_LINKOPT");
+ }
+
+ @Test
+ public void testNeverlinkTrue() throws Exception {
+ assertThat(setUpNeverlinkTest("True").getArguments()).doesNotContain("-NEVERLINK_OPTION");
+ }
+
+ @Test
+ public void testNeverlinkFalse() throws Exception {
+ assertThat(setUpNeverlinkTest("False").getArguments()).contains("-NEVERLINK_OPTION");
+ }
+
+ private CppLinkAction setUpNeverlinkTest(String value) throws Exception {
+ SkylarkCcCommonTestHelper.createFilesForTestingLinking(
+ scratch,
+ "tools/build_defs/foo",
+ String.join(",", "linkopts=depset(['-NEVERLINK_OPTION'])", "neverlink=" + value));
+ assertThat(getConfiguredTarget("//foo:bin")).isNotNull();
+ ConfiguredTarget target = getConfiguredTarget("//foo:bin");
+ return (CppLinkAction) getGeneratingAction(artifactByPath(getFilesToBuild(target), "bin"));
+ }
}
diff --git a/src/test/java/com/google/devtools/build/lib/rules/cpp/SkylarkCcCommonTestHelper.java b/src/test/java/com/google/devtools/build/lib/rules/cpp/SkylarkCcCommonTestHelper.java
new file mode 100644
index 0000000000..1aafab17b2
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/rules/cpp/SkylarkCcCommonTestHelper.java
@@ -0,0 +1,123 @@
+// Copyright 2018 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.cpp;
+
+import com.google.devtools.build.lib.analysis.util.AnalysisMock;
+import com.google.devtools.build.lib.testutil.Scratch;
+
+/** Methods useful for tests testing the C++ Skylark API. */
+public final class SkylarkCcCommonTestHelper {
+
+ public static void createFilesForTestingCompilation(
+ Scratch scratch, String bzlFilePath, String compileProviderLines) throws Exception {
+ createFiles(scratch, bzlFilePath, compileProviderLines, "");
+ }
+
+ public static void createFilesForTestingLinking(
+ Scratch scratch, String bzlFilePath, String linkProviderLines) throws Exception {
+ createFiles(scratch, bzlFilePath, "", linkProviderLines);
+ }
+
+ public static void createFiles(Scratch scratch, String bzlFilePath) throws Exception {
+ createFiles(scratch, bzlFilePath, "", "");
+ }
+
+ public static void createFiles(
+ Scratch scratch, String bzlFilePath, String compileProviderLines, String linkProviderLines)
+ throws Exception {
+ String fragments = " fragments = ['google_cpp', 'cpp'],";
+ if (AnalysisMock.get().isThisBazel()) {
+ fragments = " fragments = ['cpp'],";
+ }
+ scratch.file(bzlFilePath + "/BUILD");
+ scratch.file(
+ bzlFilePath + "/extension.bzl",
+ "def _cc_skylark_library_impl(ctx):",
+ " dep_cc_linking_infos = []",
+ " for dep in ctx.attr._deps:",
+ " dep_cc_linking_infos.append(dep[CcLinkingInfo])",
+ " toolchain = ctx.attr._cc_toolchain[cc_common.CcToolchainInfo]",
+ " feature_configuration = cc_common.configure_features(",
+ " cc_toolchain=toolchain,",
+ " requested_features = ctx.features,",
+ " unsupported_features = ctx.disabled_features)",
+ " compilation_info = cc_common.compile(",
+ " ctx=ctx,",
+ " feature_configuration=feature_configuration,",
+ " cc_toolchain=toolchain,",
+ " srcs=ctx.files.srcs,",
+ " hdrs=ctx.files.hdrs" + (compileProviderLines.isEmpty() ? "" : ","),
+ " " + compileProviderLines,
+ " )",
+ " linking_info = cc_common.link(",
+ " ctx=ctx,",
+ " feature_configuration=feature_configuration,",
+ " cc_compilation_outputs=compilation_info.cc_compilation_outputs(),",
+ " cc_toolchain=toolchain" + (linkProviderLines.isEmpty() ? "" : ","),
+ " " + linkProviderLines,
+ " )",
+ " files_to_build = []",
+ " files_to_build.extend(compilation_info.cc_compilation_outputs()",
+ " .object_files(use_pic=True))",
+ " files_to_build.extend(compilation_info.cc_compilation_outputs()",
+ " .object_files(use_pic=False))",
+ " static_libs = linking_info.cc_linking_outputs().pic_static_libraries()",
+ " for static_lib in static_libs:",
+ " files_to_build.append(static_lib.original_artifact())",
+ " dynamic_libs = linking_info.cc_linking_outputs().dynamic_libraries_for_linking()",
+ " for dynamic_lib in dynamic_libs:",
+ " files_to_build.append(dynamic_lib.original_artifact())",
+ " return struct(",
+ " libraries=dynamic_libs,",
+ " providers=[DefaultInfo(files=depset(files_to_build)),",
+ " cc_common.create_cc_skylark_info(ctx=ctx),",
+ " compilation_info.cc_compilation_info(),",
+ " linking_info.cc_linking_info()])",
+ "cc_skylark_library = rule(",
+ " implementation = _cc_skylark_library_impl,",
+ " attrs = {",
+ " 'srcs': attr.label_list(allow_files=True),",
+ " 'hdrs': attr.label_list(allow_files=True),",
+ " '_deps': attr.label_list(default=['//foo:dep1', '//foo:dep2']),",
+ " '_cc_toolchain': attr.label(default =",
+ " configuration_field(fragment = 'cpp', name = 'cc_toolchain'))",
+ " },",
+ fragments,
+ ")");
+ scratch.file(
+ "foo/BUILD",
+ "load('//" + bzlFilePath + ":extension.bzl', 'cc_skylark_library')",
+ "cc_library(",
+ " name = 'dep1',",
+ " srcs = ['dep1.cc'],",
+ " hdrs = ['dep1.h'],",
+ " linkopts = ['-DEP1_LINKOPT'],",
+ ")",
+ "cc_library(",
+ " name = 'dep2',",
+ " srcs = ['dep2.cc'],",
+ " hdrs = ['dep2.h'],",
+ " linkopts = ['-DEP2_LINKOPT'],",
+ ")",
+ "cc_skylark_library(",
+ " name = 'skylark_lib',",
+ " srcs = ['skylark_lib.cc'],",
+ " hdrs = ['skylark_lib.h'],",
+ ")",
+ "cc_binary(",
+ " name = 'bin',",
+ " deps = ['skylark_lib'],",
+ ")");
+ }
+}