C++: Bazel compile/link API
Introduces the C++ Starlark API to Bazel after discussion in https://docs.google.com/document/d/1cRRdHOPTTUXBbq9Cj9hk_WLnPqsGtAoQynYd7TKBQI8/edit.
This includes an integration test and will be followed by more integration tests for Objective-C as well as unit tests.
RELNOTES:Bazel C++ compile/link Starlark API. Can be used with experimental flag --experimental_cc_skylark_api_enabled_packages=<package_path>,<package_path2>.
PiperOrigin-RevId: 242825783
diff --git a/src/main/java/com/google/devtools/build/lib/BUILD b/src/main/java/com/google/devtools/build/lib/BUILD
index a125fe2..d4a86c7 100644
--- a/src/main/java/com/google/devtools/build/lib/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/BUILD
@@ -747,6 +747,7 @@
":packages-internal",
":proto-rules",
":python-rules",
+ ":skylarkinterface_internal",
":testing-support-rules",
":util",
"//src/main/java/com/google/devtools/build/lib/actions",
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
index 5201065..06bdaca 100644
--- 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
@@ -14,23 +14,43 @@
package com.google.devtools.build.lib.bazel.rules.cpp;
+import com.google.common.collect.ImmutableList;
import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.analysis.skylark.BazelStarlarkContext;
import com.google.devtools.build.lib.analysis.skylark.SkylarkActionFactory;
import com.google.devtools.build.lib.analysis.skylark.SkylarkRuleContext;
+import com.google.devtools.build.lib.cmdline.Label;
+import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
+import com.google.devtools.build.lib.events.Location;
+import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException;
+import com.google.devtools.build.lib.rules.cpp.CcCommon;
import com.google.devtools.build.lib.rules.cpp.CcCompilationContext;
+import com.google.devtools.build.lib.rules.cpp.CcCompilationHelper;
+import com.google.devtools.build.lib.rules.cpp.CcCompilationHelper.CompilationInfo;
import com.google.devtools.build.lib.rules.cpp.CcCompilationOutputs;
+import com.google.devtools.build.lib.rules.cpp.CcLinkingHelper;
import com.google.devtools.build.lib.rules.cpp.CcLinkingOutputs;
import com.google.devtools.build.lib.rules.cpp.CcModule;
import com.google.devtools.build.lib.rules.cpp.CcToolchainConfigInfo;
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.CppConfiguration;
+import com.google.devtools.build.lib.rules.cpp.CppRuleClasses;
+import com.google.devtools.build.lib.rules.cpp.FdoContext;
import com.google.devtools.build.lib.rules.cpp.FeatureConfigurationForStarlark;
import com.google.devtools.build.lib.rules.cpp.LibraryToLink;
import com.google.devtools.build.lib.rules.cpp.LibraryToLink.CcLinkingContext;
+import com.google.devtools.build.lib.rules.cpp.Link.LinkTargetType;
+import com.google.devtools.build.lib.rules.cpp.Link.LinkingMode;
import com.google.devtools.build.lib.skylarkbuildapi.cpp.BazelCcModuleApi;
+import com.google.devtools.build.lib.skylarkinterface.StarlarkContext;
+import com.google.devtools.build.lib.syntax.Environment;
import com.google.devtools.build.lib.syntax.EvalException;
import com.google.devtools.build.lib.syntax.SkylarkList;
import com.google.devtools.build.lib.syntax.SkylarkList.Tuple;
+import com.google.devtools.build.lib.vfs.PathFragment;
+import java.util.List;
+import java.util.stream.Stream;
/**
* A module that contains Skylark utilities for C++ support.
@@ -48,11 +68,30 @@
CcCompilationContext,
CcCompilationOutputs,
CcLinkingOutputs,
- CcLinkingContext,
LibraryToLink,
+ CcLinkingContext,
CcToolchainVariables,
CcToolchainConfigInfo> {
+ private static final List<String> SUPPORTED_OUTPUT_TYPES =
+ ImmutableList.of("executable", "dynamic_library");
+
+ private enum Language {
+ CPP("c++"),
+ OBJC("objc"),
+ OBJCPP("objc++");
+
+ private String representation;
+
+ Language(String representation) {
+ this.representation = representation;
+ }
+
+ private String getRepresentation() {
+ return representation;
+ }
+ }
+
@Override
public Tuple<Object> compile(
SkylarkActionFactory skylarkActionFactoryApi,
@@ -64,46 +103,261 @@
SkylarkList<String> includes,
SkylarkList<String> quoteIncludes,
SkylarkList<String> systemIncludes,
+ SkylarkList<String> defines,
SkylarkList<String> userCompileFlags,
SkylarkList<CcCompilationContext> ccCompilationContexts,
String name,
boolean disallowPicOutputs,
- boolean disallowNopicOutputs)
- throws EvalException, InterruptedException {
- return null;
+ boolean disallowNopicOutputs,
+ Location location,
+ Environment environment)
+ throws EvalException {
+ CcCommon.checkLocationWhitelisted(
+ environment.getSemantics(),
+ location,
+ environment.getGlobals().getLabel().getPackageIdentifier().toString());
+ SkylarkActionFactory actions = skylarkActionFactoryApi;
+ CcToolchainProvider ccToolchainProvider = convertFromNoneable(skylarkCcToolchainProvider, null);
+ FeatureConfigurationForStarlark featureConfiguration =
+ convertFromNoneable(skylarkFeatureConfiguration, null);
+ Label label = getCallerLabel(location, environment, name);
+ FdoContext fdoContext = ccToolchainProvider.getFdoContext();
+ CcCompilationHelper helper =
+ new CcCompilationHelper(
+ actions.asActionRegistry(location, actions),
+ actions.getActionConstructionContext(),
+ label,
+ /* grepIncludes= */ null,
+ BazelCppSemantics.INSTANCE,
+ featureConfiguration.getFeatureConfiguration(),
+ ccToolchainProvider,
+ fdoContext)
+ .addPublicHeaders(publicHeaders)
+ .addPrivateHeaders(privateHeaders)
+ .addSources(sources)
+ .addCcCompilationContexts(ccCompilationContexts)
+ .addIncludeDirs(
+ includes.stream()
+ .map(PathFragment::create)
+ .collect(ImmutableList.toImmutableList()))
+ .addQuoteIncludeDirs(
+ quoteIncludes.stream()
+ .map(PathFragment::create)
+ .collect(ImmutableList.toImmutableList()))
+ .addSystemIncludeDirs(
+ systemIncludes.stream()
+ .map(PathFragment::create)
+ .collect(ImmutableList.toImmutableList()))
+ .addDefines(defines)
+ .setCopts(userCompileFlags);
+ if (disallowNopicOutputs) {
+ helper.setGenerateNoPicAction(false);
+ }
+ if (disallowPicOutputs) {
+ helper.setGeneratePicAction(false);
+ }
+ try {
+ CompilationInfo compilationInfo = helper.compile();
+ return Tuple.of(
+ compilationInfo.getCcCompilationContext(), compilationInfo.getCcCompilationOutputs());
+ } catch (RuleErrorException e) {
+ throw new EvalException(location, e);
+ }
}
@Override
- public CcLinkingContext createLinkingContextFromCompilationOutputs(
+ public Tuple<Object> createLinkingContextFromCompilationOutputs(
SkylarkActionFactory skylarkActionFactoryApi,
FeatureConfigurationForStarlark skylarkFeatureConfiguration,
CcToolchainProvider skylarkCcToolchainProvider,
CcCompilationOutputs compilationOutputs,
- SkylarkList userLinkFlags,
+ SkylarkList<String> userLinkFlags,
+ SkylarkList<CcLinkingContext> linkingContexts,
String name,
String language,
boolean alwayslink,
- SkylarkList nonCodeInputs,
+ SkylarkList<Artifact> additionalInputs,
boolean disallowStaticLibraries,
- boolean disallowDynamicLibraries)
+ boolean disallowDynamicLibraries,
+ Location location,
+ Environment environment,
+ StarlarkContext starlarkContext)
throws InterruptedException, EvalException {
- return null;
+ CcCommon.checkLocationWhitelisted(
+ environment.getSemantics(),
+ location,
+ environment.getGlobals().getLabel().getPackageIdentifier().toString());
+ validateLanguage(location, language);
+ SkylarkActionFactory actions = skylarkActionFactoryApi;
+ CcToolchainProvider ccToolchainProvider = convertFromNoneable(skylarkCcToolchainProvider, null);
+ FeatureConfigurationForStarlark featureConfiguration =
+ convertFromNoneable(skylarkFeatureConfiguration, null);
+ Label label = getCallerLabel(location, environment, name);
+ FdoContext fdoContext = ccToolchainProvider.getFdoContext();
+ LinkTargetType staticLinkTargetType = null;
+ if (language.equals(Language.CPP.getRepresentation())) {
+ staticLinkTargetType = LinkTargetType.STATIC_LIBRARY;
+ } else if (language.equals(Language.OBJC.getRepresentation())
+ || language.equals(Language.OBJCPP.getRepresentation())) {
+ staticLinkTargetType = LinkTargetType.OBJC_ARCHIVE;
+ } else {
+ throw new IllegalStateException("Language is not valid.");
+ }
+ CcLinkingHelper helper =
+ new CcLinkingHelper(
+ actions.getActionConstructionContext().getRuleErrorConsumer(),
+ label,
+ actions.asActionRegistry(location, actions),
+ actions.getActionConstructionContext(),
+ BazelCppSemantics.INSTANCE,
+ featureConfiguration.getFeatureConfiguration(),
+ ccToolchainProvider,
+ fdoContext,
+ actions.getActionConstructionContext().getConfiguration(),
+ actions
+ .getActionConstructionContext()
+ .getConfiguration()
+ .getFragment(CppConfiguration.class),
+ ((BazelStarlarkContext) starlarkContext).getSymbolGenerator())
+ .addNonCodeLinkerInputs(additionalInputs)
+ .setShouldCreateStaticLibraries(!disallowStaticLibraries)
+ .setShouldCreateDynamicLibrary(
+ !disallowDynamicLibraries
+ && !featureConfiguration
+ .getFeatureConfiguration()
+ .isEnabled(CppRuleClasses.TARGETS_WINDOWS))
+ .setStaticLinkType(staticLinkTargetType)
+ .setDynamicLinkType(LinkTargetType.NODEPS_DYNAMIC_LIBRARY)
+ .addLinkopts(userLinkFlags);
+ try {
+ CcLinkingOutputs ccLinkingOutputs = CcLinkingOutputs.EMPTY;
+ ImmutableList<LibraryToLink> libraryToLink = ImmutableList.of();
+ if (!compilationOutputs.isEmpty()) {
+ ccLinkingOutputs = helper.link(compilationOutputs);
+ if (!ccLinkingOutputs.isEmpty()) {
+ libraryToLink =
+ ImmutableList.of(
+ ccLinkingOutputs.getLibraryToLink().toBuilder()
+ .setAlwayslink(alwayslink)
+ .build());
+ }
+ }
+ CcLinkingContext linkingContext =
+ helper.buildCcLinkingContextFromLibrariesToLink(
+ libraryToLink, CcCompilationContext.EMPTY);
+ return Tuple.of(
+ CcLinkingContext.merge(
+ ImmutableList.<CcLinkingContext>builder()
+ .add(linkingContext)
+ .addAll(linkingContexts)
+ .build()),
+ ccLinkingOutputs);
+ } catch (RuleErrorException e) {
+ throw new EvalException(location, e);
+ }
}
@Override
public CcLinkingOutputs link(
- SkylarkActionFactory skylarkActionFactoryApi,
+ SkylarkActionFactory actions,
FeatureConfigurationForStarlark skylarkFeatureConfiguration,
CcToolchainProvider skylarkCcToolchainProvider,
- Object compilationOutputs,
- SkylarkList userLinkFlags,
- SkylarkList linkingContexts,
+ CcCompilationOutputs compilationOutputs,
+ SkylarkList<String> userLinkFlags,
+ SkylarkList<CcLinkingContext> linkingContexts,
String name,
String language,
String outputType,
boolean linkDepsStatically,
- SkylarkList nonCodeInputs)
+ SkylarkList<Artifact> additionalInputs,
+ Location location,
+ Environment environment,
+ StarlarkContext starlarkContext)
throws InterruptedException, EvalException {
- return null;
+ CcCommon.checkLocationWhitelisted(
+ environment.getSemantics(),
+ location,
+ environment.getGlobals().getLabel().getPackageIdentifier().toString());
+ validateLanguage(location, language);
+ validateOutputType(location, outputType);
+ CcToolchainProvider ccToolchainProvider = convertFromNoneable(skylarkCcToolchainProvider, null);
+ FeatureConfigurationForStarlark featureConfiguration =
+ convertFromNoneable(skylarkFeatureConfiguration, null);
+ Label label = getCallerLabel(location, environment, name);
+ FdoContext fdoContext = ccToolchainProvider.getFdoContext();
+ LinkTargetType dynamicLinkTargetType = null;
+ if (language.equals(Language.CPP.getRepresentation())) {
+ if (outputType.equals("executable")) {
+ dynamicLinkTargetType = LinkTargetType.EXECUTABLE;
+ } else if (outputType.equals("dynamic_library")) {
+ dynamicLinkTargetType = LinkTargetType.DYNAMIC_LIBRARY;
+ }
+ } else if (language.equals(Language.OBJC.getRepresentation())
+ && outputType.equals("executable")) {
+ dynamicLinkTargetType = LinkTargetType.OBJC_EXECUTABLE;
+ } else if (language.equals(Language.OBJCPP.getRepresentation())
+ && outputType.equals("executable")) {
+ dynamicLinkTargetType = LinkTargetType.OBJCPP_EXECUTABLE;
+ } else {
+ throw new EvalException(
+ location, "Language '" + language + "' does not support " + outputType);
+ }
+
+ CcLinkingHelper helper =
+ new CcLinkingHelper(
+ actions.getActionConstructionContext().getRuleErrorConsumer(),
+ label,
+ actions.asActionRegistry(location, actions),
+ actions.getActionConstructionContext(),
+ BazelCppSemantics.INSTANCE,
+ featureConfiguration.getFeatureConfiguration(),
+ ccToolchainProvider,
+ fdoContext,
+ actions.getActionConstructionContext().getConfiguration(),
+ actions
+ .getActionConstructionContext()
+ .getConfiguration()
+ .getFragment(CppConfiguration.class),
+ ((BazelStarlarkContext) starlarkContext).getSymbolGenerator())
+ .setLinkingMode(linkDepsStatically ? LinkingMode.STATIC : LinkingMode.DYNAMIC)
+ .addNonCodeLinkerInputs(additionalInputs)
+ .setDynamicLinkType(dynamicLinkTargetType)
+ .addCcLinkingContexts(linkingContexts)
+ .addLinkopts(userLinkFlags);
+ try {
+ CcLinkingOutputs ccLinkingOutputs = CcLinkingOutputs.EMPTY;
+ if (!compilationOutputs.isEmpty()) {
+ ccLinkingOutputs = helper.link(compilationOutputs);
+ }
+ return ccLinkingOutputs;
+ } catch (RuleErrorException e) {
+ throw new EvalException(location, e);
+ }
+ }
+
+ private void validateLanguage(Location location, String language) throws EvalException {
+ if (!Stream.of(Language.values())
+ .map(Language::getRepresentation)
+ .collect(ImmutableList.toImmutableList())
+ .contains(language)) {
+ throw new EvalException(location, "Language '" + language + "' is not supported");
+ }
+ }
+
+ private void validateOutputType(Location location, String outputType) throws EvalException {
+ if (!SUPPORTED_OUTPUT_TYPES.contains(outputType)) {
+ throw new EvalException(location, "Output type '" + outputType + "' is not supported");
+ }
+ }
+
+ private Label getCallerLabel(Location location, Environment environment, String name)
+ throws EvalException {
+ Label label;
+ try {
+ label = Label.create(environment.getCallerLabel().getPackageName(), name);
+ } catch (LabelSyntaxException e) {
+ throw new EvalException(location, e);
+ }
+ return label;
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCompilationHelper.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCompilationHelper.java
index 81e7d5c..e65f09b 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCompilationHelper.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCompilationHelper.java
@@ -268,7 +268,6 @@
private String stripIncludePrefix = null;
private String includePrefix = null;
- // TODO(plf): Pull out of class.
private CcCompilationContext ccCompilationContext;
private final RuleErrorConsumer ruleErrorConsumer;
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCompilationOutputs.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCompilationOutputs.java
index cdd9e58..a7ae6b7 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCompilationOutputs.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCompilationOutputs.java
@@ -20,7 +20,10 @@
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
+import com.google.devtools.build.lib.events.Location;
import com.google.devtools.build.lib.skylarkbuildapi.cpp.CcCompilationOutputsApi;
+import com.google.devtools.build.lib.syntax.Environment;
+import com.google.devtools.build.lib.syntax.EvalException;
import com.google.devtools.build.lib.syntax.SkylarkList;
import java.util.LinkedHashSet;
import java.util.Set;
@@ -99,10 +102,35 @@
}
@Override
- public SkylarkList<Artifact> getSkylarkObjectFiles(boolean usePic) {
+ public SkylarkList<Artifact> getSkylarkObjectFiles(
+ boolean usePic, Location location, Environment environment) throws EvalException {
+ CcCommon.checkLocationWhitelisted(
+ environment.getSemantics(),
+ location,
+ environment.getGlobals().getLabel().getPackageIdentifier().toString());
return SkylarkList.createImmutable(getObjectFiles(usePic));
}
+ @Override
+ public SkylarkList<Artifact> getSkylarkObjects(Location location, Environment environment)
+ throws EvalException {
+ CcCommon.checkLocationWhitelisted(
+ environment.getSemantics(),
+ location,
+ environment.getGlobals().getLabel().getPackageIdentifier().toString());
+ return SkylarkList.createImmutable(getObjectFiles(/* usePic= */ false));
+ }
+
+ @Override
+ public SkylarkList<Artifact> getSkylarkPicObjects(Location location, Environment environment)
+ throws EvalException {
+ CcCommon.checkLocationWhitelisted(
+ environment.getSemantics(),
+ location,
+ environment.getGlobals().getLabel().getPackageIdentifier().toString());
+ return SkylarkList.createImmutable(getObjectFiles(/* usePic= */ true));
+ }
+
/** Returns information about bitcode object files resulting from compilation. */
public LtoCompilationContext getLtoCompilationContext() {
return ltoCompilationContext;
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLinkingHelper.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLinkingHelper.java
index 43596eb..4bbaf1f 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLinkingHelper.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLinkingHelper.java
@@ -262,7 +262,15 @@
* <p>This only sets the link type (see {@link #setStaticLinkType}), either to a static library or
* to an alwayslink static library (blaze uses a different file extension to signal alwayslink to
* downstream code).
+ *
+ * @deprecated This is only set here for naming always to link static libraries with the *.lo
+ * extension. This is no longer needed because {@link
+ * com.google.devtools.build.lib.rules.cpp.LinkerInputs.LibraryToLink}s already carry
+ * information about whether a library should always be linked or not. This method will be
+ * removed when we no longer use *.lo for always to link static libraries in native
+ * cc_library.
*/
+ @Deprecated
public CcLinkingHelper setAlwayslink(boolean alwayslink) {
staticLinkType =
alwayslink ? LinkTargetType.ALWAYS_LINK_STATIC_LIBRARY : LinkTargetType.STATIC_LIBRARY;
@@ -274,7 +282,6 @@
* anything other than a static link causes this class to skip the link action creation. This
* exists only for Objective-C.
*/
- @Deprecated
public CcLinkingHelper setStaticLinkType(LinkTargetType linkType) {
Preconditions.checkNotNull(linkType);
Preconditions.checkState(linkType.linkerOrArchiver() == LinkerOrArchiver.ARCHIVER);
@@ -442,12 +449,8 @@
(!dynamicLinkType.isExecutable() && usePicForDynamicLibs)
|| (dynamicLinkType.isExecutable() && usePicForBinaries);
hasBuiltDynamicLibrary =
- createDynamicLibrary(
- ccLinkingOutputsBuilder,
- libraryToLinkBuilder,
- usePic,
- libraryIdentifier,
- ccOutputs);
+ createDynamicLinkAction(
+ ccLinkingOutputsBuilder, libraryToLinkBuilder, usePic, libraryIdentifier, ccOutputs);
}
if (hasBuiltDynamicLibrary || shouldCreateStaticLibraries) {
@@ -621,7 +624,7 @@
return action;
}
- private boolean createDynamicLibrary(
+ private boolean createDynamicLinkAction(
CcLinkingOutputs.Builder ccLinkingOutputs,
LibraryToLink.Builder libraryToLinkBuilder,
boolean usePic,
@@ -630,21 +633,21 @@
throws RuleErrorException, InterruptedException {
boolean hasBuiltDynamicLibrary = false;
// Create dynamic library.
- Artifact soImpl;
+ Artifact linkerOutput;
String mainLibraryIdentifier;
if (linkerOutputArtifact == null) {
// If the crosstool is configured to select an output artifact, we use that selection.
// Otherwise, we use linux defaults.
- soImpl = getLinkedArtifact(LinkTargetType.NODEPS_DYNAMIC_LIBRARY);
+ linkerOutput = getLinkedArtifact(dynamicLinkType);
mainLibraryIdentifier = libraryIdentifier;
} else {
// This branch is only used for vestigial Google-internal rules where the name of the output
// file is explicitly specified in the BUILD file and as such, is platform-dependent. Thus,
// we just hardcode some reasonable logic to compute the library identifier and hope that this
// will eventually go away.
- soImpl = linkerOutputArtifact;
+ linkerOutput = linkerOutputArtifact;
mainLibraryIdentifier =
- FileSystemUtils.removeExtension(soImpl.getRootRelativePath().getPathString());
+ FileSystemUtils.removeExtension(linkerOutput.getRootRelativePath().getPathString());
}
List<String> sonameLinkopts = ImmutableList.of();
@@ -658,12 +661,12 @@
ImmutableList.of(
"-Wl,-soname="
+ SolibSymlinkAction.getDynamicLibrarySoname(
- soImpl.getRootRelativePath(), /* preserveName= */ false));
+ linkerOutput.getRootRelativePath(), /* preserveName= */ false));
}
}
CppLinkActionBuilder dynamicLinkActionBuilder =
- newLinkActionBuilder(soImpl)
+ newLinkActionBuilder(linkerOutput)
.setWholeArchive(wholeArchive)
.setNativeDeps(nativeDeps)
.setAdditionalLinkstampDefines(additionalLinkstampDefines.build())
@@ -746,6 +749,9 @@
ccLinkingOutputs.addAllLtoArtifacts(dynamicLinkActionBuilder.getAllLtoBackendArtifacts());
}
CppLinkAction dynamicLinkAction = dynamicLinkActionBuilder.build();
+ if (dynamicLinkType.isExecutable()) {
+ ccLinkingOutputs.setExecutable(linkerOutput);
+ }
ccLinkingOutputs.addLinkActionInputs(dynamicLinkAction.getInputs());
actionConstructionContext.registerAction(dynamicLinkAction);
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLinkingOutputs.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLinkingOutputs.java
index 430aa7b..4629a0f 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLinkingOutputs.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLinkingOutputs.java
@@ -28,15 +28,18 @@
public static final CcLinkingOutputs EMPTY = builder().build();
@Nullable private final LibraryToLink libraryToLink;
+ @Nullable private final Artifact executable;
private final ImmutableList<LtoBackendArtifacts> allLtoArtifacts;
private final ImmutableList<Artifact> linkActionInputs;
private CcLinkingOutputs(
LibraryToLink libraryToLink,
+ Artifact executable,
ImmutableList<LtoBackendArtifacts> allLtoArtifacts,
ImmutableList<Artifact> linkActionInputs) {
this.libraryToLink = libraryToLink;
+ this.executable = executable;
this.allLtoArtifacts = allLtoArtifacts;
this.linkActionInputs = linkActionInputs;
}
@@ -47,6 +50,12 @@
return libraryToLink;
}
+ @Override
+ @Nullable
+ public Artifact getExecutable() {
+ return executable;
+ }
+
public ImmutableList<LtoBackendArtifacts> getAllLtoArtifacts() {
return allLtoArtifacts;
}
@@ -95,9 +104,10 @@
return new Builder();
}
- /** Builder for {@link CcLinkingOutputs. */
+ /** Builder for {@link CcLinkingOutputs} */
public static final class Builder {
private LibraryToLink libraryToLink;
+ private Artifact executable;
private Builder() {
// private to avoid class initialization deadlock between this class and its outer class
@@ -110,7 +120,8 @@
private final ImmutableList.Builder<Artifact> linkActionInputs = ImmutableList.builder();
public CcLinkingOutputs build() {
- return new CcLinkingOutputs(libraryToLink, allLtoArtifacts.build(), linkActionInputs.build());
+ return new CcLinkingOutputs(
+ libraryToLink, executable, allLtoArtifacts.build(), linkActionInputs.build());
}
public Builder setLibraryToLink(LibraryToLink libraryToLink) {
@@ -118,6 +129,11 @@
return this;
}
+ public Builder setExecutable(Artifact executable) {
+ this.executable = executable;
+ return this;
+ }
+
public Builder addAllLtoArtifacts(Iterable<LtoBackendArtifacts> allLtoArtifacts) {
this.allLtoArtifacts.addAll(allLtoArtifacts);
return this;
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/LibraryToLink.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/LibraryToLink.java
index f0cac21..73315f1 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/LibraryToLink.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/LibraryToLink.java
@@ -61,7 +61,7 @@
}
/** Structure of CcLinkingContext. */
- public static class CcLinkingContext implements CcLinkingContextApi {
+ public static class CcLinkingContext implements CcLinkingContextApi<Artifact, LibraryToLink> {
public static final CcLinkingContext EMPTY = builder().build();
/** A list of link options contributed by a single configured target/aspect. */
@@ -289,7 +289,7 @@
}
@Override
- public SkylarkList<LibraryToLinkApi> getSkylarkLibrariesToLink() {
+ public SkylarkList<LibraryToLink> getSkylarkLibrariesToLink() {
return SkylarkList.createImmutable(libraries.toList());
}
@@ -443,6 +443,7 @@
public abstract Artifact getDynamicLibrary();
@Nullable
+ @Override
public abstract Artifact getResolvedSymlinkDynamicLibrary();
@Nullable
@@ -450,6 +451,7 @@
public abstract Artifact getInterfaceLibrary();
@Nullable
+ @Override
public abstract Artifact getResolvedSymlinkInterfaceLibrary();
@Override
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
index b01da22..fbc05dc 100644
--- 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
@@ -14,18 +14,18 @@
package com.google.devtools.build.lib.skylarkbuildapi.cpp;
+import com.google.devtools.build.lib.events.Location;
import com.google.devtools.build.lib.skylarkbuildapi.FileApi;
import com.google.devtools.build.lib.skylarkbuildapi.SkylarkActionFactoryApi;
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.skylarkinterface.StarlarkContext;
+import com.google.devtools.build.lib.syntax.Environment;
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.SkylarkList.Tuple;
-import com.google.devtools.build.lib.syntax.SkylarkNestedSet;
/** Utilites related to C++ support. */
@SkylarkModule(
@@ -40,8 +40,8 @@
CompilationContextT extends CcCompilationContextApi,
CompilationOutputsT extends CcCompilationOutputsApi<FileT>,
LinkingOutputsT extends CcLinkingOutputsApi<FileT>,
- LinkingContextT extends CcLinkingContextApi,
- LibraryToLinkT extends LibraryToLinkApi,
+ LibraryToLinkT extends LibraryToLinkApi<FileT>,
+ LinkingContextT extends CcLinkingContextApi<FileT, LibraryToLinkT>,
CcToolchainVariablesT extends CcToolchainVariablesApi,
CcToolchainConfigInfoT extends CcToolchainConfigInfoApi>
extends CcModuleApi<
@@ -57,7 +57,9 @@
@SkylarkCallable(
name = "compile",
- documented = false,
+ doc = "Should be used for C++ compilation.",
+ useEnvironment = true,
+ useLocation = true,
parameters = {
@Param(
name = "actions",
@@ -137,6 +139,13 @@
defaultValue = "[]",
type = SkylarkList.class),
@Param(
+ name = "defines",
+ doc = "Set of defines needed to compile this target. Each define is a string.",
+ positional = false,
+ named = true,
+ defaultValue = "[]",
+ type = SkylarkList.class),
+ @Param(
name = "user_compile_flags",
doc = "Additional list of compilation options.",
positional = false,
@@ -184,16 +193,22 @@
SkylarkList<String> includes,
SkylarkList<String> quoteIncludes,
SkylarkList<String> systemIncludes,
+ SkylarkList<String> defines,
SkylarkList<String> userCompileFlags,
SkylarkList<CompilationContextT> ccCompilationContexts,
String name,
boolean disallowPicOutputs,
- boolean disallowNopicOutputs)
+ boolean disallowNopicOutputs,
+ Location location,
+ Environment environment)
throws EvalException, InterruptedException;
@SkylarkCallable(
name = "link",
- documented = false,
+ doc = "Should be used for C++ transitive linking.",
+ useEnvironment = true,
+ useLocation = true,
+ useContext = true,
parameters = {
@Param(
name = "actions",
@@ -220,11 +235,7 @@
named = true,
defaultValue = "None",
noneable = true,
- allowedTypes = {
- @ParamType(type = NoneType.class),
- @ParamType(type = SkylarkList.class),
- @ParamType(type = SkylarkNestedSet.class)
- }),
+ type = CcCompilationOutputsApi.class),
@Param(
name = "user_link_flags",
doc = "Additional list of linker options.",
@@ -236,8 +247,8 @@
@Param(
name = "linking_contexts",
doc =
- "Libraries from dependencies. These libraries will be linked into the output "
- + "artifact of the link() call, be it a binary or a library.",
+ "Linking contexts from dependencies to be linked into the linking context "
+ + "generated by this rule.",
positional = false,
named = true,
noneable = true,
@@ -253,15 +264,15 @@
type = String.class),
@Param(
name = "language",
- doc = "Can be one of C++, objc or objc++.",
+ doc = "Can be one of c++, objc or objc++.",
positional = false,
named = true,
noneable = true,
- defaultValue = "'C++'",
+ defaultValue = "'c++'",
type = String.class),
@Param(
name = "output_type",
- doc = "Can be either 'executable' or 'shared_library'.",
+ doc = "Can be either 'executable' or 'dynamic_library'.",
positional = false,
named = true,
noneable = true,
@@ -276,7 +287,7 @@
defaultValue = "True",
type = Boolean.class),
@Param(
- name = "non_code_inputs",
+ name = "additional_inputs",
doc = "For additional inputs to the linking action, e.g.: linking scripts.",
positional = false,
named = true,
@@ -287,19 +298,28 @@
SkylarkActionFactoryT skylarkActionFactoryApi,
FeatureConfigurationT skylarkFeatureConfiguration,
CcToolchainProviderT skylarkCcToolchainProvider,
- Object compilationOutputs,
+ CompilationOutputsT compilationOutputs,
SkylarkList<String> userLinkFlags,
SkylarkList<LinkingContextT> linkingContexts,
String name,
String language,
String outputType,
boolean linkDepsStatically,
- SkylarkList<FileT> nonCodeInputs)
+ SkylarkList<FileT> additionalInputs,
+ Location location,
+ Environment environment,
+ StarlarkContext starlarkContext)
throws InterruptedException, EvalException;
@SkylarkCallable(
name = "create_linking_context_from_compilation_outputs",
- documented = false,
+ doc =
+ "Should be used for creating library rules that can propagate information downstream in"
+ + " order to be linked later by a top level rule that does transitive linking to"
+ + " create an executable or dynamic library.",
+ useLocation = true,
+ useEnvironment = true,
+ useContext = true,
parameters = {
@Param(
name = "actions",
@@ -334,6 +354,16 @@
noneable = true,
type = SkylarkList.class),
@Param(
+ name = "linking_contexts",
+ doc =
+ "Libraries from dependencies. These libraries will be linked into the output "
+ + "artifact of the link() call, be it a binary or a library.",
+ positional = false,
+ named = true,
+ noneable = true,
+ defaultValue = "[]",
+ type = SkylarkList.class),
+ @Param(
name = "name",
doc =
"This is used for naming the output artifacts of actions created by this "
@@ -343,11 +373,11 @@
type = String.class),
@Param(
name = "language",
- doc = "Can be one of C++, objc or objc++.",
+ doc = "Can be one of c++, objc or objc++.",
positional = false,
named = true,
noneable = true,
- defaultValue = "'C++'",
+ defaultValue = "'c++'",
type = String.class),
@Param(
name = "alwayslink",
@@ -358,7 +388,7 @@
defaultValue = "False",
type = Boolean.class),
@Param(
- name = "non_code_inputs",
+ name = "additional_inputs",
doc = "For additional inputs to the linking action, e.g.: linking scripts.",
positional = false,
named = true,
@@ -372,24 +402,28 @@
defaultValue = "False",
type = Boolean.class),
@Param(
- name = "disallow_dynamic_libraries",
- doc = "Whether dynamic libraries should be created.",
+ name = "disallow_dynamic_library",
+ doc = "Whether a dynamic library should be created.",
positional = false,
named = true,
defaultValue = "False",
type = Boolean.class)
})
- LinkingContextT createLinkingContextFromCompilationOutputs(
+ Tuple<Object> createLinkingContextFromCompilationOutputs(
SkylarkActionFactoryT skylarkActionFactoryApi,
FeatureConfigurationT skylarkFeatureConfiguration,
CcToolchainProviderT skylarkCcToolchainProvider,
CompilationOutputsT compilationOutputs,
SkylarkList<String> userLinkFlags,
+ SkylarkList<LinkingContextT> linkingContexts,
String name,
String language,
boolean alwayslink,
- SkylarkList<FileT> nonCodeInputs,
+ SkylarkList<FileT> additionalInputs,
boolean disallowStaticLibraries,
- boolean disallowDynamicLibraries)
+ boolean disallowDynamicLibraries,
+ Location location,
+ Environment environment,
+ StarlarkContext bazelStarlarkContext)
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 88c36c9..023de9c 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
@@ -33,8 +33,9 @@
? extends CcCompilationContextApi,
? extends CcCompilationOutputsApi<? extends FileApi>,
? extends CcLinkingOutputsApi<? extends FileApi>,
- ? extends CcLinkingContextApi,
- ? extends LibraryToLinkApi,
+ ? extends LibraryToLinkApi<? extends FileApi>,
+ ? extends
+ CcLinkingContextApi<? extends FileApi, ? extends LibraryToLinkApi<? extends FileApi>>,
? extends CcToolchainVariablesApi,
? extends CcToolchainConfigInfoApi>
ccModule;
@@ -49,8 +50,10 @@
? extends CcCompilationContextApi,
? extends CcCompilationOutputsApi<? extends FileApi>,
? extends CcLinkingOutputsApi<? extends FileApi>,
- ? extends CcLinkingContextApi,
- ? extends LibraryToLinkApi,
+ ? extends LibraryToLinkApi<? extends FileApi>,
+ ? extends
+ CcLinkingContextApi<
+ ? extends FileApi, ? extends LibraryToLinkApi<? extends FileApi>>,
? extends CcToolchainVariablesApi,
? extends CcToolchainConfigInfoApi>
ccModule) {
diff --git a/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/cpp/CcCompilationOutputsApi.java b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/cpp/CcCompilationOutputsApi.java
index eaa22b6..82d064b 100644
--- a/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/cpp/CcCompilationOutputsApi.java
+++ b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/cpp/CcCompilationOutputsApi.java
@@ -14,11 +14,14 @@
package com.google.devtools.build.lib.skylarkbuildapi.cpp;
+import com.google.devtools.build.lib.events.Location;
import com.google.devtools.build.lib.skylarkbuildapi.FileApi;
import com.google.devtools.build.lib.skylarkinterface.Param;
import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable;
import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
import com.google.devtools.build.lib.skylarkinterface.SkylarkModuleCategory;
+import com.google.devtools.build.lib.syntax.Environment;
+import com.google.devtools.build.lib.syntax.EvalException;
import com.google.devtools.build.lib.syntax.SkylarkList;
/** Interface for a structured representation of the compilation outputs of a C++ rule. */
@@ -28,11 +31,35 @@
documented = false,
doc = "Helper class containing CC compilation outputs.")
public interface CcCompilationOutputsApi<FileT extends FileApi> {
+
+ /** @deprecated use {@link #getSkylarkObjects} or {@link #getSkylarkPicObjects}. */
@SkylarkCallable(
name = "object_files",
documented = false,
+ useEnvironment = true,
+ useLocation = true,
parameters = {
@Param(name = "use_pic", doc = "use_pic", positional = false, named = true),
})
- SkylarkList<FileT> getSkylarkObjectFiles(boolean usePic);
+ @Deprecated
+ SkylarkList<FileT> getSkylarkObjectFiles(
+ boolean usePic, Location location, Environment environment) throws EvalException;
+
+ @SkylarkCallable(
+ name = "objects",
+ documented = false,
+ useEnvironment = true,
+ useLocation = true,
+ structField = true)
+ SkylarkList<FileT> getSkylarkObjects(Location location, Environment environment)
+ throws EvalException;
+
+ @SkylarkCallable(
+ name = "pic_objects",
+ documented = false,
+ useEnvironment = true,
+ useLocation = true,
+ structField = true)
+ SkylarkList<FileT> getSkylarkPicObjects(Location location, Environment environment)
+ throws EvalException;
}
diff --git a/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/cpp/CcLinkingOutputsApi.java b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/cpp/CcLinkingOutputsApi.java
index d0c61dc..f44f6e5 100644
--- a/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/cpp/CcLinkingOutputsApi.java
+++ b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/cpp/CcLinkingOutputsApi.java
@@ -28,4 +28,7 @@
public interface CcLinkingOutputsApi<FileT extends FileApi> {
@SkylarkCallable(name = "library_to_link", structField = true, documented = false)
LibraryToLinkApi<FileT> getLibraryToLink();
+
+ @SkylarkCallable(name = "executable", structField = true, documented = false)
+ FileT getExecutable();
}
diff --git a/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/cpp/LibraryToLinkApi.java b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/cpp/LibraryToLinkApi.java
index 9e365ef..14585cc 100644
--- a/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/cpp/LibraryToLinkApi.java
+++ b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/cpp/LibraryToLinkApi.java
@@ -52,6 +52,15 @@
FileT getDynamicLibrary();
@SkylarkCallable(
+ name = "resolved_symlink_dynamic_library",
+ doc =
+ "The resolved <code>Artifact</code> of the dynamic library to be linked if "
+ + "<code>dynamic_library</code> is a symlink, otherwise this is None.",
+ allowReturnNones = true,
+ structField = true)
+ FileT getResolvedSymlinkDynamicLibrary();
+
+ @SkylarkCallable(
name = "interface_library",
doc = "<code>Artifact</code> of interface library to be linked.",
allowReturnNones = true,
@@ -59,6 +68,15 @@
FileT getInterfaceLibrary();
@SkylarkCallable(
+ name = "resolved_symlink_interface_library",
+ doc =
+ "The resolved <code>Artifact</code> of the interface library to be linked if "
+ + "<code>interface_library</code> is a symlink, otherwise this is None.",
+ allowReturnNones = true,
+ structField = true)
+ FileT getResolvedSymlinkInterfaceLibrary();
+
+ @SkylarkCallable(
name = "alwayslink",
doc = "Whether to link the static library/objects in the --whole_archive block.",
allowReturnNones = true,
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 4e67320..db89916 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
@@ -50,8 +50,8 @@
CcCompilationContextApi,
CcCompilationOutputsApi<FileApi>,
CcLinkingOutputsApi<FileApi>,
- CcLinkingContextApi,
- LibraryToLinkApi,
+ LibraryToLinkApi<FileApi>,
+ CcLinkingContextApi<FileApi, LibraryToLinkApi<FileApi>>,
CcToolchainVariablesApi,
CcToolchainConfigInfoApi> {
@@ -179,29 +179,36 @@
SkylarkList<FileApi> privateHeaders,
SkylarkList<String> includes,
SkylarkList<String> quoteIncludes,
+ SkylarkList<String> defines,
SkylarkList<String> systemIncludes,
SkylarkList<String> userCompileFlags,
SkylarkList<CcCompilationContextApi> ccCompilationContexts,
String name,
boolean disallowPicOutputs,
- boolean disallowNopicOutputs)
+ boolean disallowNopicOutputs,
+ Location location,
+ Environment environment)
throws EvalException, InterruptedException {
return null;
}
@Override
- public CcLinkingContextApi createLinkingContextFromCompilationOutputs(
+ public Tuple<Object> createLinkingContextFromCompilationOutputs(
SkylarkActionFactoryApi skylarkActionFactoryApi,
FeatureConfigurationApi skylarkFeatureConfiguration,
CcToolchainProviderApi<FeatureConfigurationApi> skylarkCcToolchainProvider,
CcCompilationOutputsApi<FileApi> compilationOutputs,
SkylarkList<String> userLinkFlags,
+ SkylarkList<CcLinkingContextApi<FileApi, LibraryToLinkApi<FileApi>>> ccLinkingContextApis,
String name,
String language,
boolean alwayslink,
SkylarkList<FileApi> nonCodeInputs,
boolean disallowStaticLibraries,
- boolean disallowDynamicLibraries)
+ boolean disallowDynamicLibraries,
+ Location location,
+ Environment environment,
+ StarlarkContext starlarkContext)
throws InterruptedException, EvalException {
return null;
}
@@ -211,14 +218,17 @@
SkylarkActionFactoryApi skylarkActionFactoryApi,
FeatureConfigurationApi skylarkFeatureConfiguration,
CcToolchainProviderApi<FeatureConfigurationApi> skylarkCcToolchainProvider,
- Object compilationOutputs,
+ CcCompilationOutputsApi<FileApi> compilationOutputs,
SkylarkList<String> userLinkFlags,
- SkylarkList<CcLinkingContextApi> linkingContexts,
+ SkylarkList<CcLinkingContextApi<FileApi, LibraryToLinkApi<FileApi>>> linkingContexts,
String name,
String language,
String outputType,
boolean linkDepsStatically,
- SkylarkList<FileApi> nonCodeInputs)
+ SkylarkList<FileApi> additionalInputs,
+ Location location,
+ Environment environment,
+ StarlarkContext starlarkContext)
throws InterruptedException, EvalException {
return null;
}
diff --git a/src/test/shell/bazel/BUILD b/src/test/shell/bazel/BUILD
index 1cf5c94..2ece60f 100644
--- a/src/test/shell/bazel/BUILD
+++ b/src/test/shell/bazel/BUILD
@@ -38,6 +38,7 @@
name = "test-deps-wo-bazel",
testonly = 1,
srcs = [
+ "cc_api_rules.bzl",
"remote_helpers.sh",
"testing_server.py",
":langtools-copy",
diff --git a/src/test/shell/bazel/cc_api_rules.bzl b/src/test/shell/bazel/cc_api_rules.bzl
new file mode 100644
index 0000000..201b0a7
--- /dev/null
+++ b/src/test/shell/bazel/cc_api_rules.bzl
@@ -0,0 +1,181 @@
+# Copyright 2019 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.
+
+"""Example C++ API usage"""
+
+load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain")
+
+def _filter_none(input_list):
+ filtered_list = []
+ for element in input_list:
+ if element != None:
+ filtered_list.append(element)
+ return filtered_list
+
+def _cc_lib_impl(ctx):
+ cc_toolchain = find_cpp_toolchain(ctx)
+ feature_configuration = cc_common.configure_features(
+ cc_toolchain = cc_toolchain,
+ requested_features = ctx.features,
+ unsupported_features = ctx.disabled_features,
+ )
+ compilation_contexts = []
+ linking_contexts = []
+ for dep in ctx.attr.deps:
+ if CcInfo in dep:
+ compilation_contexts.append(dep[CcInfo].compilation_context)
+ linking_contexts.append(dep[CcInfo].linking_context)
+
+ (compilation_context, compilation_outputs) = cc_common.compile(
+ name = ctx.label.name,
+ actions = ctx.actions,
+ feature_configuration = feature_configuration,
+ cc_toolchain = cc_toolchain,
+ public_hdrs = ctx.files.public_hdrs,
+ private_hdrs = ctx.files.private_hdrs,
+ srcs = ctx.files.srcs,
+ includes = ctx.attr.includes,
+ quote_includes = ctx.attr.quote_includes,
+ system_includes = ctx.attr.system_includes,
+ defines = ctx.attr.defines,
+ user_compile_flags = ctx.attr.user_compile_flags,
+ compilation_contexts = compilation_contexts,
+ )
+ (linking_context, linking_outputs) = cc_common.create_linking_context_from_compilation_outputs(
+ name = ctx.label.name,
+ actions = ctx.actions,
+ feature_configuration = feature_configuration,
+ cc_toolchain = cc_toolchain,
+ language = "c++",
+ compilation_outputs = compilation_outputs,
+ linking_contexts = linking_contexts,
+ )
+ library = linking_outputs.library_to_link
+ files = []
+ files.extend(compilation_outputs.objects)
+ files.extend(compilation_outputs.pic_objects)
+ files.append(library.pic_static_library)
+ files.append(library.static_library)
+
+ files.append(library.dynamic_library)
+
+ return [
+ DefaultInfo(
+ files = depset(_filter_none(files)),
+ ),
+ CcInfo(
+ compilation_context = compilation_context,
+ linking_context = linking_context,
+ ),
+ ]
+
+cc_lib = rule(
+ implementation = _cc_lib_impl,
+ attrs = {
+ "public_hdrs": attr.label_list(allow_files = [".h"]),
+ "private_hdrs": attr.label_list(allow_files = [".h"]),
+ "srcs": attr.label_list(allow_files = [".cc"]),
+ "deps": attr.label_list(
+ allow_empty = True,
+ providers = [[CcInfo]],
+ ),
+ "user_compile_flags": attr.string_list(),
+ "user_link_flags": attr.string_list(),
+ "includes": attr.string_list(),
+ "quote_includes": attr.string_list(),
+ "system_includes": attr.string_list(),
+ "defines": attr.string_list(),
+ "alwayslink": attr.bool(default = False),
+ "_cc_toolchain": attr.label(default = "@bazel_tools//tools/cpp:current_cc_toolchain"),
+ },
+ fragments = ["cpp"],
+)
+
+def _cc_bin_impl(ctx):
+ cc_toolchain = find_cpp_toolchain(ctx)
+ feature_configuration = cc_common.configure_features(
+ cc_toolchain = cc_toolchain,
+ requested_features = ctx.features,
+ unsupported_features = ctx.disabled_features,
+ )
+ compilation_contexts = []
+ linking_contexts = []
+ for dep in ctx.attr.deps:
+ if CcInfo in dep:
+ compilation_contexts.append(dep[CcInfo].compilation_context)
+ linking_contexts.append(dep[CcInfo].linking_context)
+
+ (_compilation_context, compilation_outputs) = cc_common.compile(
+ name = ctx.label.name,
+ actions = ctx.actions,
+ feature_configuration = feature_configuration,
+ cc_toolchain = cc_toolchain,
+ srcs = ctx.files.srcs,
+ compilation_contexts = compilation_contexts,
+ )
+ output_type = "dynamic_library" if ctx.attr.linkshared else "executable"
+ user_link_flags = []
+ for user_link_flag in ctx.attr.user_link_flags:
+ user_link_flags.append(ctx.expand_location(user_link_flag, targets = ctx.attr.additional_linker_inputs))
+
+ linking_outputs = cc_common.link(
+ name = ctx.label.name,
+ actions = ctx.actions,
+ feature_configuration = feature_configuration,
+ cc_toolchain = cc_toolchain,
+ language = "c++",
+ compilation_outputs = compilation_outputs,
+ linking_contexts = linking_contexts,
+ user_link_flags = user_link_flags,
+ link_deps_statically = ctx.attr.linkstatic,
+ additional_inputs = ctx.files.additional_linker_inputs,
+ output_type = output_type,
+ )
+ files = []
+ if output_type == "executable":
+ files.append(linking_outputs.executable)
+ elif output_type == "dynamic_library":
+ files.append(linking_outputs.library_to_link.dynamic_library)
+ files.append(linking_outputs.library_to_link.resolved_symlink_dynamic_library)
+
+ return [
+ DefaultInfo(
+ files = depset(_filter_none(files)),
+ runfiles = ctx.runfiles(files = ctx.files.data),
+ ),
+ ]
+
+cc_bin = rule(
+ implementation = _cc_bin_impl,
+ attrs = {
+ "srcs": attr.label_list(allow_files = [".cc"]),
+ "additional_linker_inputs": attr.label_list(
+ allow_empty = True,
+ allow_files = [".lds"],
+ ),
+ "deps": attr.label_list(
+ allow_empty = True,
+ providers = [CcInfo],
+ ),
+ "data": attr.label_list(
+ default = [],
+ allow_files = True,
+ ),
+ "user_link_flags": attr.string_list(),
+ "linkstatic": attr.bool(default = True),
+ "linkshared": attr.bool(default = False),
+ "_cc_toolchain": attr.label(default = "@bazel_tools//tools/cpp:current_cc_toolchain"),
+ },
+ fragments = ["cpp"],
+)
diff --git a/src/test/shell/bazel/cc_integration_test.sh b/src/test/shell/bazel/cc_integration_test.sh
index c41a8da..5b21c80 100755
--- a/src/test/shell/bazel/cc_integration_test.sh
+++ b/src/test/shell/bazel/cc_integration_test.sh
@@ -277,4 +277,329 @@
grep "test_feature" bazel-bin/ea/feature_debug/cc/requested_features.txt || "test_feature should have been found in requested_features."
}
-run_suite "cc_integration_test"
+# TODO: test include dirs and defines
+function setup_cc_starlark_api_test() {
+ local pkg="$1"
+
+ touch "$pkg"/WORKSPACE
+
+ mkdir "$pkg"/include_dir
+ touch "$pkg"/include_dir/include.h
+ mkdir "$pkg"/system_include_dir
+ touch "$pkg"/system_include_dir/system_include.h
+ mkdir "$pkg"/quote_include_dir
+ touch "$pkg"/quote_include_dir/quote_include.h
+
+
+
+ cat > "$pkg"/BUILD << EOF
+load("//${pkg}:cc_api_rules.bzl", "cc_lib", "cc_bin")
+
+cc_lib(
+ name = "a",
+ srcs = [
+ "a1.cc",
+ "a2.cc",
+ ],
+ private_hdrs = [
+ "a2.h",
+ "include_dir/include.h",
+ "system_include_dir/system_include.h",
+ "quote_include_dir/quote_include.h"
+ ],
+ user_compile_flags = ["-DA_DEFINITION_LOCAL"],
+ public_hdrs = ["a.h"],
+ includes = ["$pkg/include_dir"],
+ system_includes = ["$pkg/system_include_dir"],
+ quote_includes = ["$pkg/quote_include_dir"],
+ defines = ["A_DEFINITION"],
+ deps = [
+ ":b",
+ ":d",
+ ],
+)
+
+cc_lib(
+ name = "b",
+ srcs = [
+ "b.cc",
+ ],
+ public_hdrs = ["b.h"],
+ deps = [":c"],
+)
+
+cc_lib(
+ name = "c",
+ srcs = [
+ "c.cc",
+ ],
+ public_hdrs = ["c.h"],
+)
+
+cc_lib(
+ name = "d",
+ srcs = ["d.cc"],
+ public_hdrs = ["d.h"],
+)
+
+cc_bin(
+ name = "e",
+ srcs = ["e.cc"],
+ data = [":f"],
+ linkstatic = 1,
+ user_link_flags = [
+ "-ldl",
+ "-lm",
+ "-Wl,-rpath,bazel-bin/${pkg}",
+ ],
+ deps = [
+ ":a",
+ ],
+)
+
+cc_bin(
+ name = "f",
+ srcs = ["f.cc"],
+ linkshared = 1,
+ deps = [
+ ":a",
+ ],
+)
+EOF
+
+ cat > $pkg/a1.cc << EOF
+#include <system_include.h>
+#include "include.h"
+
+#include "quote_include.h"
+#include "a.h"
+#include "a2.h"
+
+#ifdef A_DEFINITION_LOCAL
+#include "b.h"
+#include "d.h"
+#endif
+
+using namespace std;
+
+string alongernamethanusual() { return "a1" + a2() + b() + d(); }
+EOF
+
+ cat > $pkg/a2.cc << EOF
+#include <string>
+using namespace std;
+
+string a2() { return "a2"; }
+EOF
+
+ cat > $pkg/a.h << EOF
+#ifndef HEADER_A
+#define HEADER_A
+#include <string>
+using namespace std;
+string alongernamethanusual();
+#endif
+EOF
+
+ cat > $pkg/a2.h << EOF
+#ifndef HEADER_A2
+#define HEADER_A2
+#include <string>
+using namespace std;
+string a2();
+#endif
+EOF
+
+ cat > $pkg/b.cc << EOF
+#include "b.h"
+#include <string>
+#include "c.h"
+using namespace std;
+
+string b() { return "b" + c(); }
+EOF
+
+ cat > $pkg/b.h << EOF
+#ifndef HEADER_B
+#define HEADER_B
+#include <string>
+using namespace std;
+string b();
+#endif
+EOF
+
+ cat > $pkg/c.cc << EOF
+#include "c.h"
+#include <algorithm>
+#include <string>
+
+using namespace std;
+
+string c() { return "c"; }
+EOF
+
+ cat > $pkg/c.h << EOF
+#ifndef HEADER_C
+#define HEADER_C
+#include <string>
+using namespace std;
+string c();
+#endif
+EOF
+
+ cat > $pkg/d.cc << EOF
+#include "d.h"
+#include <string>
+using namespace std;
+
+string d() { return "d"; }
+EOF
+
+ cat > $pkg/d.h << EOF
+#ifndef HEADER_D
+#define HEADER_D
+#include <string>
+using namespace std;
+string d();
+#endif
+EOF
+
+ cat > $pkg/e.cc << EOF
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <iostream>
+
+#ifdef A_DEFINITION
+#include "a.h"
+#endif
+
+#ifdef A_DEFINITION_LOCAL
+#include "thisdoesntexist.h"
+#endif
+
+using namespace std;
+
+int main() {
+ void* handle = dlopen("libf.so", RTLD_LAZY);
+
+ typedef string (*f_t)();
+
+ f_t f = (f_t)dlsym(handle, "f");
+ cout << alongernamethanusual() + f() << endl;
+ return 0;
+}
+
+EOF
+
+ cat > $pkg/f.cc << EOF
+#include <algorithm>
+#include <string>
+#include "a.h"
+
+using namespace std;
+
+extern "C" string f() {
+ string str = alongernamethanusual();
+ reverse(str.begin(), str.end());
+ return str;
+}
+EOF
+
+ cat > $pkg/script.lds << EOF
+VERS_42.0 {
+ local:
+ *;
+};
+EOF
+
+ cp "$CURRENT_DIR"/cc_api_rules.bzl "$pkg"/cc_api_rules.bzl
+
+}
+
+function test_cc_starlark_api_default_values() {
+ local pkg="${FUNCNAME[0]}"
+ mkdir -p "$pkg"
+
+ setup_cc_starlark_api_test "${FUNCNAME[0]}"
+
+ bazel build --experimental_cc_skylark_api_enabled_packages=, --verbose_failures \
+ //"$pkg":e &>"$TEST_log" || fail "Build failed"
+
+ nm -u bazel-bin/"$pkg"/e | grep alongernamethanusual && \
+ fail "alongernamethanusual is not defined"
+
+ bazel-bin/"$pkg"/e | grep a1a2bcddcb2a1a || fail "output is incorrect"
+}
+
+
+function test_cc_starlark_api_link_static_false() {
+ local pkg="${FUNCNAME[0]}"
+ mkdir -p "$pkg"
+
+ setup_cc_starlark_api_test "${FUNCNAME[0]}"
+
+ cat >> "$pkg"/BUILD << EOF
+cc_bin(
+ name = "g",
+ srcs = ["e.cc"],
+ data = [":f"],
+ linkstatic = 0,
+ user_link_flags = [
+ "-ldl",
+ "-lm",
+ "-Wl,-rpath,bazel-bin/${pkg}",
+ ],
+ deps = [
+ ":a",
+ ],
+)
+EOF
+
+ bazel build --experimental_cc_skylark_api_enabled_packages=, --verbose_failures \
+ //"$pkg":g &>"$TEST_log" || fail "Build failed"
+
+ nm -u bazel-bin/"$pkg"/g | grep alongernamethanusual || fail "alongernamethanusual is defined"
+
+ bazel-bin/"$pkg"/g | grep a1a2bcddcb2a1a || fail "output is incorrect"
+}
+
+function test_cc_starlark_api_additional_inputs() {
+ # This uses --version-script which isn't available on Mac linker.
+ [ "$PLATFORM" != "darwin" ] || return 0
+
+ local pkg="${FUNCNAME[0]}"
+ mkdir -p "$pkg"
+
+ setup_cc_starlark_api_test "${FUNCNAME[0]}"
+
+ cat >> "$pkg"/BUILD << EOF
+cc_bin(
+ name = "g",
+ srcs = ["e.cc"],
+ data = [":f"],
+ linkstatic = 1,
+ additional_linker_inputs = ["script.lds"],
+ user_link_flags = [
+ "-ldl",
+ "-lm",
+ "-Wl,-rpath,bazel-bin/${pkg}",
+ "-Wl,--version-script=\$(location script.lds)",
+ ],
+ deps = [
+ ":a",
+ ],
+)
+EOF
+
+ bazel build --experimental_cc_skylark_api_enabled_packages=, --verbose_failures \
+ //"$pkg":g &>"$TEST_log" || fail "Build failed"
+
+ nm bazel-bin/"$pkg"/g | grep VERS_42.0 || fail "VERS_42.0 not in binary"
+
+ bazel-bin/"$pkg"/g | grep a1a2bcddcb2a1a || fail "output is incorrect"
+}
+
+
+
+run_suite "cc_integration_test"
\ No newline at end of file