Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
C++: Implements Skylark cc_common.compile()/link().
Browse files Browse the repository at this point in the history
Working towards bazelbuild#4570.

RELNOTES:none
PiperOrigin-RevId: 205274676
oquenchil authored and George Gensure committed Aug 2, 2018
1 parent a243094 commit d4ee93f
Showing 9 changed files with 861 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -19,6 +19,7 @@
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.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 void init(ConfiguredRuleClassProvider.Builder builder) {
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);
}
Original file line number Diff line number Diff line change
@@ -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);
}
}
234 changes: 234 additions & 0 deletions src/main/java/com/google/devtools/build/lib/rules/cpp/CcModule.java
Original file line number Diff line number Diff line change
@@ -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.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 CcCompilationInfo mergeCcCompilationInfos(
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);
}
}
Original file line number Diff line number Diff line change
@@ -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;
}
Original file line number Diff line number Diff line change
@@ -22,9 +22,34 @@
*/
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;
}

Original file line number Diff line number Diff line change
@@ -17,23 +17,34 @@
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;
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 CcSkylarkInfoApi createCcSkylarkInfo(Object skylarkRuleContextObject)
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;
}
}
16 changes: 15 additions & 1 deletion src/test/java/com/google/devtools/build/lib/rules/cpp/BUILD
Original file line number Diff line number Diff line change
@@ -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 = [
Original file line number Diff line number Diff line change
@@ -28,6 +28,7 @@
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 @@ private void setUpCcLinkingProviderParamsTest() throws Exception {
" 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"));
}
}
Original file line number Diff line number Diff line change
@@ -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'],",
")");
}
}

0 comments on commit d4ee93f

Please sign in to comment.