blob: e37f2f53845c1acb13b725891afab9c4efd52b71 [file] [log] [blame]
// Copyright 2021 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 static com.google.common.collect.ImmutableList.toImmutableList;
import com.google.common.collect.ImmutableList;
import com.google.devtools.build.docgen.annot.DocCategory;
import com.google.devtools.build.lib.actions.Actions;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.actions.CommandLineExpansionException;
import com.google.devtools.build.lib.analysis.LicensesProvider;
import com.google.devtools.build.lib.analysis.LicensesProvider.TargetLicense;
import com.google.devtools.build.lib.analysis.LicensesProviderImpl;
import com.google.devtools.build.lib.analysis.RuleContext;
import com.google.devtools.build.lib.analysis.actions.ActionConstructionContext;
import com.google.devtools.build.lib.analysis.actions.SymlinkAction;
import com.google.devtools.build.lib.analysis.starlark.StarlarkActionFactory;
import com.google.devtools.build.lib.analysis.starlark.StarlarkActionFactory.StarlarkActionContext;
import com.google.devtools.build.lib.analysis.starlark.StarlarkRuleContext;
import com.google.devtools.build.lib.cmdline.Label;
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.packages.Attribute.ComputedDefault;
import com.google.devtools.build.lib.packages.AttributeMap;
import com.google.devtools.build.lib.packages.Info;
import com.google.devtools.build.lib.packages.License;
import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException;
import com.google.devtools.build.lib.packages.StarlarkProvider;
import com.google.devtools.build.lib.packages.Types;
import com.google.devtools.build.lib.rules.cpp.CcLinkingContext.Linkstamp;
import com.google.devtools.build.lib.starlarkbuildapi.NativeComputedDefaultApi;
import com.google.devtools.build.lib.starlarkbuildapi.core.ProviderApi;
import com.google.devtools.build.lib.vfs.PathFragment;
import java.util.Map;
import javax.annotation.Nullable;
import net.starlark.java.annot.Param;
import net.starlark.java.annot.ParamType;
import net.starlark.java.annot.StarlarkBuiltin;
import net.starlark.java.annot.StarlarkMethod;
import net.starlark.java.eval.Dict;
import net.starlark.java.eval.EvalException;
import net.starlark.java.eval.Sequence;
import net.starlark.java.eval.StarlarkValue;
import net.starlark.java.syntax.Location;
/** Utility methods for rules in Starlark Builtins */
@StarlarkBuiltin(name = "cc_internal", category = DocCategory.BUILTIN, documented = false)
public class CcStarlarkInternal implements StarlarkValue {
public static final String NAME = "cc_internal";
@StarlarkMethod(
name = "cc_toolchain_variables",
documented = false,
parameters = {
@Param(name = "vars", positional = false, named = true),
})
public CcToolchainVariables getCcToolchainVariables(Object vars) throws EvalException {
CcToolchainVariables.Builder ccToolchainVariables = CcToolchainVariables.builder();
for (Map.Entry<String, String> entry :
Dict.noneableCast(vars, String.class, String.class, "vars").entrySet()) {
ccToolchainVariables.addStringVariable(entry.getKey(), entry.getValue());
}
return ccToolchainVariables.build();
}
@StarlarkMethod(
name = "solib_symlink_action",
documented = false,
parameters = {
@Param(name = "ctx", positional = false, named = true),
@Param(name = "artifact", positional = false, named = true),
@Param(name = "solib_directory", positional = false, named = true),
@Param(name = "runtime_solib_dir_base", positional = false, named = true),
})
public Artifact solibSymlinkAction(
StarlarkRuleContext ruleContext,
Artifact artifact,
String solibDirectory,
String runtimeSolibDirBase) {
return SolibSymlinkAction.getCppRuntimeSymlink(
ruleContext.getRuleContext(), artifact, solibDirectory, runtimeSolibDirBase);
}
@StarlarkMethod(
name = "cc_toolchain_features",
documented = false,
parameters = {
@Param(name = "toolchain_config_info", positional = false, named = true),
@Param(name = "tools_directory", positional = false, named = true),
})
public CcToolchainFeatures ccToolchainFeatures(
CcToolchainConfigInfo ccToolchainConfigInfo, String toolsDirectoryPathString)
throws EvalException {
return new CcToolchainFeatures(
ccToolchainConfigInfo, PathFragment.create(toolsDirectoryPathString));
}
@StarlarkMethod(
name = "is_package_headers_checking_mode_set",
documented = false,
parameters = {@Param(name = "ctx", positional = false, named = true)})
public boolean isPackageHeadersCheckingModeSetForStarlark(
StarlarkRuleContext starlarkRuleContext) {
return starlarkRuleContext
.getRuleContext()
.getRule()
.getPackage()
.getPackageArgs()
.isDefaultHdrsCheckSet();
}
@StarlarkMethod(
name = "package_headers_checking_mode",
documented = false,
parameters = {@Param(name = "ctx", positional = false, named = true)})
public String getPackageHeadersCheckingModeForStarlark(StarlarkRuleContext starlarkRuleContext) {
return starlarkRuleContext
.getRuleContext()
.getRule()
.getPackage()
.getPackageArgs()
.getDefaultHdrsCheck();
}
@StarlarkMethod(
name = "is_package_headers_checking_mode_set_for_aspect",
documented = false,
parameters = {@Param(name = "ctx", positional = false, named = true)})
public boolean isPackageHeadersCheckingModeSetForStarlarkAspect(
StarlarkRuleContext starlarkRuleContext) {
return starlarkRuleContext
.getRuleContext()
.getTarget()
.getPackage()
.getPackageArgs()
.isDefaultHdrsCheckSet();
}
@StarlarkMethod(
name = "package_headers_checking_mode_for_aspect",
documented = false,
parameters = {@Param(name = "ctx", positional = false, named = true)})
public String getPackageHeadersCheckingModeForStarlarkAspect(
StarlarkRuleContext starlarkRuleContext) {
return starlarkRuleContext
.getRuleContext()
.getTarget()
.getPackage()
.getPackageArgs()
.getDefaultHdrsCheck();
}
@StarlarkMethod(
name = "create_common",
documented = false,
parameters = {
@Param(name = "ctx", positional = false, named = true),
})
public CcCommon createCommon(StarlarkRuleContext starlarkRuleContext) {
return new CcCommon(starlarkRuleContext.getRuleContext());
}
@StarlarkMethod(name = "launcher_provider", documented = false, structField = true)
public ProviderApi getCcLauncherInfoProvider() throws EvalException {
return CcLauncherInfo.PROVIDER;
}
@StarlarkMethod(
name = "create_linkstamp",
documented = false,
parameters = {
@Param(name = "actions", positional = false, named = true),
@Param(name = "linkstamp", positional = false, named = true),
@Param(name = "compilation_context", positional = false, named = true),
})
public Linkstamp createLinkstamp(
StarlarkActionFactory starlarkActionFactoryApi,
Artifact linkstamp,
CcCompilationContext ccCompilationContext)
throws EvalException {
try {
return new Linkstamp( // throws InterruptedException
linkstamp,
ccCompilationContext.getDeclaredIncludeSrcs(),
starlarkActionFactoryApi.getRuleContext().getActionKeyContext());
} catch (CommandLineExpansionException | InterruptedException ex) {
throw new EvalException(ex);
}
}
/**
* TODO(bazel-team): This can be re-written directly to Starlark but it will cause a memory
* regression due to the way StarlarkComputedDefault is stored for each rule.
*/
static class StlComputedDefault extends ComputedDefault implements NativeComputedDefaultApi {
@Override
@Nullable
public Object getDefault(AttributeMap rule) {
return rule.getOrDefault("tags", Types.STRING_LIST, ImmutableList.of()).contains("__CC_STL__")
? null
: Label.parseCanonicalUnchecked("@//third_party/stl");
}
}
@StarlarkMethod(name = "stl_computed_default", documented = false)
public ComputedDefault getStlComputedDefault() {
return new StlComputedDefault();
}
@StarlarkMethod(
name = "create_cc_launcher_info",
doc = "Create a CcLauncherInfo instance.",
parameters = {
@Param(
name = "cc_info",
positional = false,
named = true,
doc = "CcInfo instance.",
allowedTypes = {@ParamType(type = CcInfo.class)}),
@Param(
name = "compilation_outputs",
positional = false,
named = true,
doc = "CcCompilationOutputs instance.",
allowedTypes = {@ParamType(type = CcCompilationOutputs.class)})
})
public CcLauncherInfo createCcLauncherInfo(
CcInfo ccInfo, CcCompilationOutputs compilationOutputs) {
return new CcLauncherInfo(ccInfo, compilationOutputs);
}
private static final StarlarkProvider starlarkCcTestRunnerInfo =
StarlarkProvider.builder(Location.BUILTIN)
.setExported(
new StarlarkProvider.Key(
Label.parseCanonicalUnchecked("//tools/cpp/cc_test:toolchain.bzl"),
"CcTestRunnerInfo"))
.build();
@StarlarkMethod(name = "CcTestRunnerInfo", documented = false, structField = true)
public StarlarkProvider ccTestRunnerInfo() throws EvalException {
return starlarkCcTestRunnerInfo;
}
// This looks ugly, however it is necessary. Good thing is we are planning to get rid of genfiles
// directory altogether so this method has a bright future(of being removed).
@StarlarkMethod(
name = "bin_or_genfiles_relative_to_unique_directory",
documented = false,
parameters = {
@Param(name = "actions", positional = false, named = true),
@Param(name = "unique_directory", positional = false, named = true),
})
public String binOrGenfilesRelativeToUniqueDirectory(
StarlarkActionFactory actions, String uniqueDirectory) {
ActionConstructionContext actionConstructionContext = actions.getRuleContext();
return actionConstructionContext
.getBinOrGenfilesDirectory()
.getExecPath()
.getRelative(
actionConstructionContext.getUniqueDirectory(PathFragment.create(uniqueDirectory)))
.getPathString();
}
@StarlarkMethod(
name = "create_umbrella_header_action",
documented = false,
parameters = {
@Param(name = "actions", positional = false, named = true),
@Param(name = "umbrella_header", positional = false, named = true),
@Param(name = "public_headers", positional = false, named = true),
@Param(name = "additional_exported_headers", positional = false, named = true),
})
public void createUmbrellaHeaderAction(
StarlarkActionFactory actions,
Artifact umbrellaHeader,
Sequence<?> publicHeaders,
Sequence<?> additionalExportedHeaders)
throws EvalException {
actions
.getRuleContext()
.registerAction(
new UmbrellaHeaderAction(
actions.getRuleContext().getActionOwner(),
umbrellaHeader,
Sequence.cast(publicHeaders, Artifact.class, "public_headers"),
Sequence.cast(
additionalExportedHeaders, String.class, "additional_exported_headers")
.stream()
.map(PathFragment::create)
.collect(toImmutableList())));
}
@StarlarkMethod(
name = "create_module_map_action",
documented = false,
parameters = {
@Param(name = "actions", positional = false, named = true),
@Param(name = "feature_configuration", positional = false, named = true),
@Param(name = "module_map", positional = false, named = true),
@Param(name = "private_headers", positional = false, named = true),
@Param(name = "public_headers", positional = false, named = true),
@Param(name = "dependent_module_maps", positional = false, named = true),
@Param(name = "additional_exported_headers", positional = false, named = true),
@Param(name = "separate_module_headers", positional = false, named = true),
@Param(name = "compiled_module", positional = false, named = true),
@Param(name = "module_map_home_is_cwd", positional = false, named = true),
@Param(name = "generate_submodules", positional = false, named = true),
@Param(name = "without_extern_dependencies", positional = false, named = true),
})
public void createModuleMapAction(
StarlarkActionFactory actions,
FeatureConfigurationForStarlark featureConfigurationForStarlark,
CppModuleMap moduleMap,
Sequence<?> privateHeaders,
Sequence<?> publicHeaders,
Sequence<?> dependentModuleMaps,
Sequence<?> additionalExportedHeaders,
Sequence<?> separateModuleHeaders,
Boolean compiledModule,
Boolean moduleMapHomeIsCwd,
Boolean generateSubmodules,
Boolean withoutExternDependencies)
throws EvalException {
RuleContext ruleContext = actions.getRuleContext();
ruleContext.registerAction(
new CppModuleMapAction(
ruleContext.getActionOwner(),
moduleMap,
Sequence.cast(privateHeaders, Artifact.class, "private_headers"),
Sequence.cast(publicHeaders, Artifact.class, "public_headers"),
Sequence.cast(dependentModuleMaps, CppModuleMap.class, "dependent_module_maps"),
Sequence.cast(additionalExportedHeaders, String.class, "additional_exported_headers")
.stream()
.map(PathFragment::create)
.collect(toImmutableList()),
Sequence.cast(separateModuleHeaders, Artifact.class, "separate_module_headers"),
compiledModule,
moduleMapHomeIsCwd,
generateSubmodules,
withoutExternDependencies));
}
private static final StarlarkProvider buildSettingInfo =
StarlarkProvider.builder(Location.BUILTIN)
.setExported(
new StarlarkProvider.Key(
Label.parseCanonicalUnchecked(
"//third_party/bazel_skylib/rules:common_settings.bzl"),
"BuildSettingInfo"))
.build();
@StarlarkMethod(name = "BuildSettingInfo", documented = false, structField = true)
public StarlarkProvider buildSettingInfo() throws EvalException {
return buildSettingInfo;
}
@StarlarkMethod(
name = "escape_label",
documented = false,
parameters = {
@Param(name = "label", positional = false, named = true),
})
public String escapeLabel(Label label) {
return Actions.escapeLabel(label);
}
@StarlarkMethod(
name = "licenses",
documented = false,
parameters = {
@Param(name = "ctx", positional = false, named = true),
},
allowReturnNones = true)
@Nullable
public LicensesProvider getLicenses(StarlarkRuleContext starlarkRuleContext) {
RuleContext ruleContext = starlarkRuleContext.getRuleContext();
final License outputLicense =
ruleContext.getRule().getToolOutputLicense(ruleContext.attributes());
if (outputLicense != null && !outputLicense.equals(License.NO_LICENSE)) {
final NestedSet<TargetLicense> license =
NestedSetBuilder.create(
Order.STABLE_ORDER, new TargetLicense(ruleContext.getLabel(), outputLicense));
return new LicensesProviderImpl(
license, new TargetLicense(ruleContext.getLabel(), outputLicense));
} else {
return null;
}
}
@StarlarkMethod(
name = "get_artifact_name_for_category",
documented = false,
parameters = {
@Param(name = "cc_toolchain", positional = false, named = true),
@Param(name = "category", positional = false, named = true),
@Param(name = "output_name", positional = false, named = true),
})
public String getArtifactNameForCategory(Info ccToolchainInfo, String category, String outputName)
throws RuleErrorException, EvalException {
CcToolchainProvider ccToolchain = CcToolchainProvider.PROVIDER.wrap(ccToolchainInfo);
return ccToolchain
.getFeatures()
.getArtifactNameForCategory(ArtifactCategory.valueOf(category), outputName);
}
@StarlarkMethod(
name = "absolute_symlink",
documented = false,
parameters = {
@Param(name = "ctx", positional = false, named = true),
@Param(name = "output", positional = false, named = true),
@Param(name = "target_path", positional = false, named = true),
@Param(name = "progress_message", positional = false, named = true),
})
// TODO(b/333997009): remove command line flags that specify FDO with absolute path
public void absoluteSymlink(
StarlarkActionContext ctx, Artifact output, String targetPath, String progressMessage) {
SymlinkAction action =
SymlinkAction.toAbsolutePath(
ctx.getRuleContext().getActionOwner(),
PathFragment.create(targetPath),
output,
progressMessage);
ctx.getRuleContext().registerAction(action);
}
}