diff options
author | 2016-10-11 15:30:49 +0000 | |
---|---|---|
committer | 2016-10-12 08:55:07 +0000 | |
commit | 74b94328db5346e0f6c573731fcbaa85ca751304 (patch) | |
tree | cab3cab9a81aab6bea2016b2567039661f682324 /src/main | |
parent | 671045b8fd9cc53d208af6eb38dab5c1fb543545 (diff) |
Move interface so building to action configs
This cl moves the conditional building of interface libraries from LinkCommandLine to action configs and features. It provides link_dynamic_library.sh to keep blaze backwards compatible. The script and related code can be deleted once all crosstools are updated.
RELNOTES: No.
--
MOS_MIGRATED_REVID=135799041
Diffstat (limited to 'src/main')
8 files changed, 444 insertions, 373 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchain.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchain.java index ec766a7d72..5ff24aa753 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchain.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchain.java @@ -56,6 +56,7 @@ import java.util.Map; * Implementation for the cc_toolchain rule. */ public class CcToolchain implements RuleConfiguredTargetFactory { + /** * This file (found under the sysroot) may be unconditionally included in every C/C++ compilation. */ @@ -198,6 +199,8 @@ public class CcToolchain implements RuleConfiguredTargetFactory { "FDO_DIR", cppConfiguration.getFdoInstrument().getPathString())); } + Artifact linkDynamicLibraryTool = getLinkDynamicLibraryTool(ruleContext); + CcToolchainProvider provider = new CcToolchainProvider( cppConfiguration, @@ -220,6 +223,7 @@ public class CcToolchain implements RuleConfiguredTargetFactory { getBuildVariables(ruleContext), getBuiltinIncludes(ruleContext), coverageEnvironment.build(), + linkDynamicLibraryTool, getEnvironment(ruleContext)); RuleConfiguredTargetBuilder builder = new RuleConfiguredTargetBuilder(ruleContext) @@ -250,6 +254,10 @@ public class CcToolchain implements RuleConfiguredTargetFactory { return builder.build(); } + private Artifact getLinkDynamicLibraryTool(RuleContext ruleContext) { + return ruleContext.getPrerequisiteArtifact("$link_dynamic_library_tool", Mode.TARGET); + } + private ImmutableList<Artifact> getBuiltinIncludes(RuleContext ruleContext) { ImmutableList.Builder<Artifact> result = ImmutableList.builder(); for (Artifact artifact : inputsForLibc(ruleContext)) { @@ -285,6 +293,7 @@ public class CcToolchain implements RuleConfiguredTargetFactory { return NestedSetBuilder.<Artifact>stableOrder() .addTransitive(link) .addTransitive(AnalysisUtils.getMiddlemanFor(ruleContext, ":libc_top")) + .add(getLinkDynamicLibraryTool(ruleContext)) .add( ruleContext .getAnalysisEnvironment() diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainFeatures.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainFeatures.java index 799be8b998..a5e37154a6 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainFeatures.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainFeatures.java @@ -1149,9 +1149,12 @@ public class CcToolchainFeatures implements Serializable { return enabledFeatureNames.contains(feature); } - /** - * @return whether an action config for the blaze action with the given name is enabled. - */ + /** @return true if tool_path in action_config points to a real tool, not a dummy placeholder */ + public boolean hasConfiguredLinkerPathInActionConfig() { + return isEnabled("has_configured_linker_path"); + } + + /** @return whether an action config for the blaze action with the given name is enabled. */ boolean actionIsConfigured(String actionName) { return enabledActionConfigActionNames.contains(actionName); } diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainProvider.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainProvider.java index 755da5311c..4145ebdede 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainProvider.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainProvider.java @@ -25,9 +25,7 @@ import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; import com.google.devtools.build.lib.util.Pair; import com.google.devtools.build.lib.util.Preconditions; import com.google.devtools.build.lib.vfs.PathFragment; - import java.util.Map; - import javax.annotation.Nullable; /** @@ -35,9 +33,7 @@ import javax.annotation.Nullable; */ @Immutable public final class CcToolchainProvider implements TransitiveInfoProvider { - /** - * An empty toolchain to be returned in the error case (instead of null). - */ + /** An empty toolchain to be returned in the error case (instead of null). */ public static final CcToolchainProvider EMPTY_TOOLCHAIN_IS_ERROR = new CcToolchainProvider( null, @@ -60,6 +56,7 @@ public final class CcToolchainProvider implements TransitiveInfoProvider { ImmutableMap.<String, String>of(), ImmutableList.<Artifact>of(), NestedSetBuilder.<Pair<String, String>>emptySet(Order.COMPILE_ORDER), + null, ImmutableMap.<String, String>of()); @Nullable private final CppConfiguration cppConfiguration; @@ -82,6 +79,7 @@ public final class CcToolchainProvider implements TransitiveInfoProvider { private final ImmutableMap<String, String> buildVariables; private final ImmutableList<Artifact> builtinIncludeFiles; private final NestedSet<Pair<String, String>> coverageEnvironment; + @Nullable private final Artifact linkDynamicLibraryTool; private final ImmutableMap<String, String> environment; public CcToolchainProvider( @@ -105,6 +103,7 @@ public final class CcToolchainProvider implements TransitiveInfoProvider { Map<String, String> buildVariables, ImmutableList<Artifact> builtinIncludeFiles, NestedSet<Pair<String, String>> coverageEnvironment, + Artifact linkDynamicLibraryTool, ImmutableMap<String, String> environment) { this.cppConfiguration = cppConfiguration; this.crosstool = Preconditions.checkNotNull(crosstool); @@ -126,6 +125,7 @@ public final class CcToolchainProvider implements TransitiveInfoProvider { this.buildVariables = ImmutableMap.copyOf(buildVariables); this.builtinIncludeFiles = builtinIncludeFiles; this.coverageEnvironment = coverageEnvironment; + this.linkDynamicLibraryTool = linkDynamicLibraryTool; this.environment = environment; } @@ -283,4 +283,12 @@ public final class CcToolchainProvider implements TransitiveInfoProvider { public ImmutableMap<String, String> getEnvironment() { return environment; } + + /** + * Returns the tool which should be used for linking dynamic libraries, or in case it's not + * specified by the crosstool this will be @tools_repository/tools/cpp:link_dynamic_library + */ + public Artifact getLinkDynamicLibraryTool() { + return linkDynamicLibraryTool; + } } diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainRule.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainRule.java index 9ee448165f..786add8315 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainRule.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainRule.java @@ -75,12 +75,16 @@ public final class CcToolchainRule implements RuleDefinition { .add(attr("module_map", LABEL).legacyAllowAnyFileType().cfg(HOST)) .add(attr("supports_param_files", BOOLEAN).value(true)) .add(attr("supports_header_parsing", BOOLEAN).value(false)) + .add( + attr("$link_dynamic_library_tool", LABEL) + .value(env.getToolsLabel("//tools/cpp:link_dynamic_library"))) // TODO(bazel-team): Should be using the TARGET configuration. .add(attr(":libc_top", LABEL).cfg(HOST).value(LIBC_TOP)) - .add(attr(":lipo_context_collector", LABEL) - .cfg(LipoTransition.LIPO_COLLECTOR) - .value(CppRuleClasses.LIPO_CONTEXT_COLLECTOR) - .skipPrereqValidatorCheck()) + .add( + attr(":lipo_context_collector", LABEL) + .cfg(LipoTransition.LIPO_COLLECTOR) + .value(CppRuleClasses.LIPO_CONTEXT_COLLECTOR) + .skipPrereqValidatorCheck()) .build(); } diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfiguration.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfiguration.java index 95f37e7d0c..7231f64869 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfiguration.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfiguration.java @@ -51,6 +51,7 @@ import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig.CTool import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig.CToolchain.ArtifactNamePattern; import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig.LinkingModeFlags; import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig.LipoMode; +import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig.ToolPath; import com.google.devtools.common.options.OptionsParsingException; import com.google.protobuf.TextFormat; import com.google.protobuf.TextFormat.ParseException; @@ -693,7 +694,6 @@ public class CppConfiguration extends BuildConfiguration.Fragment { // feature configuration, and all crosstools have been converted. private CToolchain addLegacyFeatures(CToolchain toolchain) { CToolchain.Builder toolchainBuilder = CToolchain.newBuilder(); - toolchainBuilder.mergeFrom(toolchain); Set<ArtifactCategory> definedCategories = new HashSet<>(); for (ArtifactNamePattern pattern : toolchainBuilder.getArtifactNamePatternList()) { @@ -719,292 +719,302 @@ public class CppConfiguration extends BuildConfiguration.Fragment { featuresBuilder.add(feature.getName()); } Set<String> features = featuresBuilder.build(); - if (features.contains(CppRuleClasses.NO_LEGACY_FEATURES)) { - // The toolchain requested to not get any legacy features enabled. - return toolchainBuilder.build(); - } + if (!features.contains(CppRuleClasses.NO_LEGACY_FEATURES)) { + try { + if (!linkActionsAreConfigured(toolchain)) { + String linkerToolPath = "DUMMY_LINKER_TOOL"; + for (ToolPath tool : toolchain.getToolPathList()) { + if (tool.getName().equals(Tool.GCC.getNamePart())) { + linkerToolPath = + crosstoolTopPathFragment + .getRelative(new PathFragment(tool.getPath())) + .getPathString(); + } + } + if (getTargetLibc().equals("macosx")) { + TextFormat.merge( + CppLinkActionConfigs.getCppLinkActionConfigs( + CppLinkPlatform.MAC, features, linkerToolPath), + toolchainBuilder); + } else { + TextFormat.merge( + CppLinkActionConfigs.getCppLinkActionConfigs( + CppLinkPlatform.LINUX, features, linkerToolPath), + toolchainBuilder); + } + } - try { - - if (!linkActionsAreConfigured(toolchain)) { - if (getTargetLibc().equals("macosx")) { - TextFormat.merge( - CppLinkActionConfigs.getCppLinkActionConfigs(CppLinkPlatform.MAC), toolchainBuilder); - } else { + if (!features.contains("dependency_file")) { + // Gcc options: + // -MD turns on .d file output as a side-effect (doesn't imply -E) + // -MM[D] enables user includes only, not system includes + // -MF <name> specifies the dotd file name + // Issues: + // -M[M] alone subverts actual .o output (implies -E) + // -M[M]D alone breaks some of the .d naming assumptions + // This combination gets user and system includes with specified name: + // -MD -MF <name> TextFormat.merge( - CppLinkActionConfigs.getCppLinkActionConfigs(CppLinkPlatform.LINUX), + "" + + "feature {" + + " name: 'dependency_file'" + + " flag_set {" + + " action: 'assemble'" + + " action: 'preprocess-assemble'" + + " action: 'c-compile'" + + " action: 'c++-compile'" + + " action: 'c++-module-compile'" + + " action: 'objc-compile'" + + " action: 'objc++-compile'" + + " action: 'c++-header-preprocessing'" + + " action: 'c++-header-parsing'" + + " expand_if_all_available: 'dependency_file'" + + " flag_group {" + + " flag: '-MD'" + + " flag: '-MF'" + + " flag: '%{dependency_file}'" + + " }" + + " }" + + "}", toolchainBuilder); } - } - if (!features.contains("dependency_file")) { - // Gcc options: - // -MD turns on .d file output as a side-effect (doesn't imply -E) - // -MM[D] enables user includes only, not system includes - // -MF <name> specifies the dotd file name - // Issues: - // -M[M] alone subverts actual .o output (implies -E) - // -M[M]D alone breaks some of the .d naming assumptions - // This combination gets user and system includes with specified name: - // -MD -MF <name> - TextFormat.merge("" - + "feature {" - + " name: 'dependency_file'" - + " flag_set {" - + " action: 'assemble'" - + " action: 'preprocess-assemble'" - + " action: 'c-compile'" - + " action: 'c++-compile'" - + " action: 'c++-module-compile'" - + " action: 'objc-compile'" - + " action: 'objc++-compile'" - + " action: 'c++-header-preprocessing'" - + " action: 'c++-header-parsing'" - + " expand_if_all_available: 'dependency_file'" - + " flag_group {" - + " flag: '-MD'" - + " flag: '-MF'" - + " flag: '%{dependency_file}'" - + " }" - + " }" - + "}", - toolchainBuilder); - } - if (!features.contains("random_seed")) { - // GCC and Clang give randomized names to symbols which are defined in - // an anonymous namespace but have external linkage. To make - // computation of these deterministic, we want to override the - // default seed for the random number generator. It's safe to use - // any value which differs for all translation units; we use the - // path to the object file. - TextFormat.merge("" - + "feature {" - + " name: 'random_seed'" - + " flag_set {" - + " action: 'c++-compile'" - + " action: 'c++-module-compile'" - + " flag_group {" - + " flag: '-frandom-seed=%{output_file}'" - + " }" - + " }" - + "}", - toolchainBuilder); - } + if (!features.contains("random_seed")) { + // GCC and Clang give randomized names to symbols which are defined in + // an anonymous namespace but have external linkage. To make + // computation of these deterministic, we want to override the + // default seed for the random number generator. It's safe to use + // any value which differs for all translation units; we use the + // path to the object file. + TextFormat.merge( + "" + + "feature {" + + " name: 'random_seed'" + + " flag_set {" + + " action: 'c++-compile'" + + " action: 'c++-module-compile'" + + " flag_group {" + + " flag: '-frandom-seed=%{output_file}'" + + " }" + + " }" + + "}", + toolchainBuilder); + } - if (!features.contains("pic")) { - TextFormat.merge("" - + "feature {" - + " name: 'pic'" - + " flag_set {" - + " action: 'c-compile'" - + " action: 'c++-compile'" - + " action: 'c++-module-compile'" - + " action: 'preprocess-assemble'" - + " expand_if_all_available: 'pic'" - + " flag_group {" - + " flag: '-fPIC'" - + " }" - + " }" - + "}", - toolchainBuilder); - } + if (!features.contains("pic")) { + TextFormat.merge( + "" + + "feature {" + + " name: 'pic'" + + " flag_set {" + + " action: 'c-compile'" + + " action: 'c++-compile'" + + " action: 'c++-module-compile'" + + " action: 'preprocess-assemble'" + + " expand_if_all_available: 'pic'" + + " flag_group {" + + " flag: '-fPIC'" + + " }" + + " }" + + "}", + toolchainBuilder); + } - if (!features.contains("per_object_debug_info")) { - TextFormat.merge("" - + "feature {" - + " name: 'per_object_debug_info'" - + " flag_set {" - + " action: 'c-compile'" - + " action: 'c++-compile'" - + " action: 'assemble'" - + " action: 'preprocess-assemble'" - + " expand_if_all_available: 'per_object_debug_info_file'" - + " flag_group {" - + " flag: '-gsplit-dwarf'" - + " }" - + " }" - + "}", - toolchainBuilder); - } + if (!features.contains("per_object_debug_info")) { + TextFormat.merge( + "" + + "feature {" + + " name: 'per_object_debug_info'" + + " flag_set {" + + " action: 'c-compile'" + + " action: 'c++-compile'" + + " action: 'assemble'" + + " action: 'preprocess-assemble'" + + " expand_if_all_available: 'per_object_debug_info_file'" + + " flag_group {" + + " flag: '-gsplit-dwarf'" + + " }" + + " }" + + "}", + toolchainBuilder); + } - if (!features.contains("preprocessor_defines")) { - TextFormat.merge( - "" - + "feature {" - + " name: 'preprocessor_defines'" - + " flag_set {" - + " action: 'preprocess-assemble'" - + " action: 'c-compile'" - + " action: 'c++-compile'" - + " action: 'c++-header-parsing'" - + " action: 'c++-header-preprocessing'" - + " action: 'c++-module-compile'" - + " action: 'clif-match'" - + " flag_group {" - + " flag: '-D%{preprocessor_defines}'" - + " }" - + " }" - + "}", - toolchainBuilder); - } - if (!features.contains("include_paths")) { - TextFormat.merge( - "" - + "feature {" - + " name: 'include_paths'" - + " flag_set {" - + " action: 'preprocess-assemble'" - + " action: 'c-compile'" - + " action: 'c++-compile'" - + " action: 'c++-header-parsing'" - + " action: 'c++-header-preprocessing'" - + " action: 'c++-module-compile'" - + " action: 'clif-match'" - + " action: 'objc-compile'" - + " action: 'objc++-compile'" - + " flag_group {" - + " flag: '-iquote'" - + " flag: '%{quote_include_paths}'" - + " }" - + " flag_group {" - + " flag: '-I%{include_paths}'" - + " }" - + " flag_group {" - + " flag: '-isystem'" - + " flag: '%{system_include_paths}'" - + " }" - + " }" - + "}", - toolchainBuilder); - } - if (!features.contains("fdo_instrument")) { - TextFormat.merge( - "" - + "feature {" - + " name: 'fdo_instrument'" - + " provides: 'profile'" - + " flag_set {" - + " action: 'c-compile'" - + " action: 'c++-compile'" - + " action: 'c++-link-interface-dynamic-library'" - + " action: 'c++-link-dynamic-library'" - + " action: 'c++-link-executable'" - + " flag_group {" - + " flag: '-fprofile-generate=%{fdo_instrument_path}'" - + " flag: '-fno-data-sections'" - + " }" - + " }" - + "}", - toolchainBuilder); - } - if (!features.contains("fdo_optimize")) { - TextFormat.merge( - "" - + "feature {" - + " name: 'fdo_optimize'" - + " provides: 'profile'" - + " flag_set {" - + " action: 'c-compile'" - + " action: 'c++-compile'" - + " expand_if_all_available: 'fdo_profile_path'" - + " flag_group {" - + " flag: '-fprofile-use=%{fdo_profile_path}'" - + " flag: '-Xclang-only=-Wno-profile-instr-unprofiled'" - + " flag: '-Xclang-only=-Wno-profile-instr-out-of-date'" - + " flag: '-fprofile-correction'" - + " }" - + " }" - + "}", - toolchainBuilder); - } - if (!features.contains("autofdo")) { - TextFormat.merge( - "" - + "feature {" - + " name: 'autofdo'" - + " provides: 'profile'" - + " flag_set {" - + " action: 'c-compile'" - + " action: 'c++-compile'" - + " expand_if_all_available: 'fdo_profile_path'" - + " flag_group {" - + " flag: '-fauto-profile=%{fdo_profile_path}'" - + " flag: '-fprofile-correction'" - + " }" - + " }" - + "}", - toolchainBuilder); - } - if (!features.contains("lipo")) { - TextFormat.merge( - "" - + "feature {" - + " name: 'lipo'" - + " requires { feature: 'autofdo' }" - + " requires { feature: 'fdo_optimize' }" - + " requires { feature: 'fdo_instrument' }" - + " flag_set {" - + " action: 'c-compile'" - + " action: 'c++-compile'" - + " flag_group {" - + " flag: '-fripa'" - + " }" - + " }" - + "}", - toolchainBuilder); - } - if (!features.contains("coverage")) { - String compileFlags; - String linkerFlags; - if (useLLVMCoverageMap) { - compileFlags = - "flag_group {" - + " flag: '-fprofile-instr-generate'" - + " flag: '-fcoverage-mapping'" - + "}"; - linkerFlags = - " flag_group {" - + " flag: '-fprofile-instr-generate'" - + "}"; - } else { - compileFlags = - " expand_if_all_available: 'gcov_gcno_file'" - + "flag_group {" - + " flag: '-fprofile-arcs'" - + " flag: '-ftest-coverage'" - + "}"; - linkerFlags = - " flag_group {" - + " flag: '-lgcov'" - + "}"; + if (!features.contains("preprocessor_defines")) { + TextFormat.merge( + "" + + "feature {" + + " name: 'preprocessor_defines'" + + " flag_set {" + + " action: 'preprocess-assemble'" + + " action: 'c-compile'" + + " action: 'c++-compile'" + + " action: 'c++-header-parsing'" + + " action: 'c++-header-preprocessing'" + + " action: 'c++-module-compile'" + + " action: 'clif-match'" + + " flag_group {" + + " flag: '-D%{preprocessor_defines}'" + + " }" + + " }" + + "}", + toolchainBuilder); + } + if (!features.contains("include_paths")) { + TextFormat.merge( + "" + + "feature {" + + " name: 'include_paths'" + + " flag_set {" + + " action: 'preprocess-assemble'" + + " action: 'c-compile'" + + " action: 'c++-compile'" + + " action: 'c++-header-parsing'" + + " action: 'c++-header-preprocessing'" + + " action: 'c++-module-compile'" + + " action: 'clif-match'" + + " action: 'objc-compile'" + + " action: 'objc++-compile'" + + " flag_group {" + + " flag: '-iquote'" + + " flag: '%{quote_include_paths}'" + + " }" + + " flag_group {" + + " flag: '-I%{include_paths}'" + + " }" + + " flag_group {" + + " flag: '-isystem'" + + " flag: '%{system_include_paths}'" + + " }" + + " }" + + "}", + toolchainBuilder); + } + if (!features.contains("fdo_instrument")) { + TextFormat.merge( + "" + + "feature {" + + " name: 'fdo_instrument'" + + " provides: 'profile'" + + " flag_set {" + + " action: 'c-compile'" + + " action: 'c++-compile'" + + " action: 'c++-link-interface-dynamic-library'" + + " action: 'c++-link-dynamic-library'" + + " action: 'c++-link-executable'" + + " flag_group {" + + " flag: '-fprofile-generate=%{fdo_instrument_path}'" + + " flag: '-fno-data-sections'" + + " }" + + " }" + + "}", + toolchainBuilder); + } + if (!features.contains("fdo_optimize")) { + TextFormat.merge( + "" + + "feature {" + + " name: 'fdo_optimize'" + + " provides: 'profile'" + + " flag_set {" + + " action: 'c-compile'" + + " action: 'c++-compile'" + + " expand_if_all_available: 'fdo_profile_path'" + + " flag_group {" + + " flag: '-fprofile-use=%{fdo_profile_path}'" + + " flag: '-Xclang-only=-Wno-profile-instr-unprofiled'" + + " flag: '-Xclang-only=-Wno-profile-instr-out-of-date'" + + " flag: '-fprofile-correction'" + + " }" + + " }" + + "}", + toolchainBuilder); + } + if (!features.contains("autofdo")) { + TextFormat.merge( + "" + + "feature {" + + " name: 'autofdo'" + + " provides: 'profile'" + + " flag_set {" + + " action: 'c-compile'" + + " action: 'c++-compile'" + + " expand_if_all_available: 'fdo_profile_path'" + + " flag_group {" + + " flag: '-fauto-profile=%{fdo_profile_path}'" + + " flag: '-fprofile-correction'" + + " }" + + " }" + + "}", + toolchainBuilder); + } + if (!features.contains("lipo")) { + TextFormat.merge( + "" + + "feature {" + + " name: 'lipo'" + + " requires { feature: 'autofdo' }" + + " requires { feature: 'fdo_optimize' }" + + " requires { feature: 'fdo_instrument' }" + + " flag_set {" + + " action: 'c-compile'" + + " action: 'c++-compile'" + + " flag_group {" + + " flag: '-fripa'" + + " }" + + " }" + + "}", + toolchainBuilder); + } + if (!features.contains("coverage")) { + String compileFlags; + String linkerFlags; + if (useLLVMCoverageMap) { + compileFlags = + "flag_group {" + + " flag: '-fprofile-instr-generate'" + + " flag: '-fcoverage-mapping'" + + "}"; + linkerFlags = " flag_group {" + " flag: '-fprofile-instr-generate'" + "}"; + } else { + compileFlags = + " expand_if_all_available: 'gcov_gcno_file'" + + "flag_group {" + + " flag: '-fprofile-arcs'" + + " flag: '-ftest-coverage'" + + "}"; + linkerFlags = " flag_group {" + " flag: '-lgcov'" + "}"; + } + TextFormat.merge( + "" + + "feature {" + + " name: 'coverage'" + + " provides: 'profile'" + + " flag_set {" + + " action: 'preprocess-assemble'" + + " action: 'c-compile'" + + " action: 'c++-compile'" + + " action: 'c++-header-parsing'" + + " action: 'c++-header-preprocessing'" + + " action: 'c++-module-compile'" + + compileFlags + + " }" + + " flag_set {" + + " action: 'c++-link-interface-dynamic-library'" + + " action: 'c++-link-dynamic-library'" + + " action: 'c++-link-executable'" + + linkerFlags + + " }" + + "}", + toolchainBuilder); } - TextFormat.merge( - "" - + "feature {" - + " name: 'coverage'" - + " provides: 'profile'" - + " flag_set {" - + " action: 'preprocess-assemble'" - + " action: 'c-compile'" - + " action: 'c++-compile'" - + " action: 'c++-header-parsing'" - + " action: 'c++-header-preprocessing'" - + " action: 'c++-module-compile'" - + compileFlags - + " }" - + " flag_set {" - + " action: 'c++-link-interface-dynamic-library'" - + " action: 'c++-link-dynamic-library'" - + " action: 'c++-link-executable'" - + linkerFlags - + " }" - + "}", - toolchainBuilder); + } catch (ParseException e) { + // Can only happen if we change the proto definition without changing our + // configuration above. + throw new RuntimeException(e); } - } catch (ParseException e) { - // Can only happen if we change the proto definition without changing our configuration above. - throw new RuntimeException(e); } + + toolchainBuilder.mergeFrom(toolchain); return toolchainBuilder.build(); } @@ -1026,7 +1036,8 @@ public class CppConfiguration extends BuildConfiguration.Fragment { private static final String SYSROOT_START = "%sysroot%/"; private static final String WORKSPACE_START = "%workspace%/"; private static final String CROSSTOOL_START = "%crosstool_top%/"; - private static final String PACKAGE_START = "%package(", PACKAGE_END = ")%"; + private static final String PACKAGE_START = "%package("; + private static final String PACKAGE_END = ")%"; /** * Resolve the given include directory. diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionBuilder.java index 178d0688fb..d6b2c62d94 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionBuilder.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionBuilder.java @@ -100,6 +100,18 @@ public class CppLinkActionBuilder { /** A build variable for the execpath of the output of the linker. */ public static final String OUTPUT_EXECPATH_VARIABLE = "output_execpath"; + /** A build variable setting if interface library should be generated. */ + public static final String GENERATE_INTERFACE_LIBRARY_VARIABLE = "generate_interface_library"; + + /** A build variable for the path to the interface library builder tool. */ + public static final String INTERFACE_LIBRARY_BUILDER_VARIABLE = "interface_library_builder_path"; + + /** A build variable for the input for the interface library builder tool. */ + public static final String INTERFACE_LIBRARY_INPUT_VARIABLE = "interface_library_input_path"; + + /** A build variable for the path where to generate interface library using the builder tool. */ + public static final String INTERFACE_LIBRARY_OUTPUT_VARIABLE = "interface_library_output_path"; + /** * A build variable that is set to indicate a mostly static linking for which the linked binary * should be piped to /dev/null. @@ -320,6 +332,10 @@ public class CppLinkActionBuilder { public List<String> getLinkstampOptions() { return this.linkstampOptions; } + + protected Artifact getInterfaceSoBuilder() { + return analysisEnvironment.getEmbeddedToolArtifact(CppRuleClasses.BUILD_INTERFACE_SO); + } /** * Returns command line options for this link action. @@ -552,7 +568,9 @@ public class CppLinkActionBuilder { runtimeLinkerInputs, null, linkerParamsFile, - ltoOutputRootPrefix) + ltoOutputRootPrefix, + null, + null) : new CppLinkVariablesExtension( configuration, linkstampMap, @@ -561,7 +579,9 @@ public class CppLinkActionBuilder { runtimeLinkerInputs, output, linkerParamsFile, - PathFragment.EMPTY_FRAGMENT); + PathFragment.EMPTY_FRAGMENT, + getInterfaceSoBuilder(), + interfaceOutput); variablesExtension.addVariables(buildVariablesBuilder); for (VariablesExtension extraVariablesExtension : variablesExtensions) { extraVariablesExtension.addVariables(buildVariablesBuilder); @@ -612,6 +632,7 @@ public class CppLinkActionBuilder { .setParamFile(paramFile) .setToolchain(toolchain) .setBuildVariables(buildVariables) + .setToolPath(getToolPath()) .setFeatureConfiguration(featureConfiguration); // TODO(b/30228443): Refactor noWholeArchiveInputs into action_configs, and remove this. @@ -622,9 +643,7 @@ public class CppLinkActionBuilder { if (!isLTOIndexing) { linkCommandLineBuilder .setOutput(output) - .setInterfaceOutput(interfaceOutput) .setBuildInfoHeaderArtifacts(buildInfoHeaderArtifacts) - .setInterfaceSoBuilder(getInterfaceSoBuilder()) .setLinkstamps(linkstampMap) .setLinkopts(ImmutableList.copyOf(linkopts)) .addLinkstampCompileOptions(linkstampOptions); @@ -639,6 +658,7 @@ public class CppLinkActionBuilder { // Compute the set of inputs - we only need stable order here. NestedSetBuilder<Artifact> dependencyInputsBuilder = NestedSetBuilder.stableOrder(); dependencyInputsBuilder.addTransitive(crosstoolInputs); + dependencyInputsBuilder.add(toolchain.getLinkDynamicLibraryTool()); dependencyInputsBuilder.addAll(linkActionInputs); if (runtimeMiddleman != null) { dependencyInputsBuilder.add(runtimeMiddleman); @@ -739,6 +759,26 @@ public class CppLinkActionBuilder { executionRequirements.build()); } + /** + * Returns the tool path from feature configuration, if the tool in the configuration is sane, or + * builtin tool, if configuration has a dummy value. + */ + private String getToolPath() { + if (!featureConfiguration.actionIsConfigured(linkType.getActionName())) { + return null; + } + String toolPath = + featureConfiguration + .getToolForAction(linkType.getActionName()) + .getToolPath(cppConfiguration.getCrosstoolTopPathFragment()) + .getPathString(); + if (linkType.equals(LinkTargetType.DYNAMIC_LIBRARY) + && !featureConfiguration.hasConfiguredLinkerPathInActionConfig()) { + toolPath = toolchain.getLinkDynamicLibraryTool().getExecPathString(); + } + return toolPath; + } + /** The default heuristic on whether we need to use whole-archive for the link. */ private static boolean needWholeArchive( LinkStaticness staticness, @@ -809,10 +849,6 @@ public class CppLinkActionBuilder { return ruleContext.getActionOwner(); } - protected Artifact getInterfaceSoBuilder() { - return analysisEnvironment.getEmbeddedToolArtifact(CppRuleClasses.BUILD_INTERFACE_SO); - } - /** Set the crosstool inputs required for the action. */ public CppLinkActionBuilder setCrosstoolInputs(NestedSet<Artifact> inputs) { this.crosstoolInputs = inputs; @@ -1196,6 +1232,8 @@ public class CppLinkActionBuilder { private final Iterable<LinkerInput> linkerInputs; private final ImmutableList<LinkerInput> runtimeLinkerInputs; private final Artifact outputArtifact; + private final Artifact interfaceLibraryBuilder; + private final Artifact interfaceLibraryOutput; private final Artifact linkerParamsFile; private final PathFragment ltoOutputRootPrefix; @@ -1209,13 +1247,17 @@ public class CppLinkActionBuilder { ImmutableList<LinkerInput> runtimeLinkerInputs, Artifact output, Artifact linkerParamsFile, - PathFragment ltoOutputRootPrefix) { + PathFragment ltoOutputRootPrefix, + Artifact interfaceLibraryBuilder, + Artifact interfaceLibraryOutput) { this.configuration = configuration; this.linkstampMap = linkstampMap; this.needWholeArchive = needWholeArchive; this.linkerInputs = linkerInputs; this.runtimeLinkerInputs = runtimeLinkerInputs; this.outputArtifact = output; + this.interfaceLibraryBuilder = interfaceLibraryBuilder; + this.interfaceLibraryOutput = interfaceLibraryOutput; this.linkerParamsFile = linkerParamsFile; this.ltoOutputRootPrefix = ltoOutputRootPrefix; @@ -1285,9 +1327,8 @@ public class CppLinkActionBuilder { } // output exec path - if (this.outputArtifact != null) { - buildVariables.addVariable( - OUTPUT_EXECPATH_VARIABLE, this.outputArtifact.getExecPathString()); + if (outputArtifact != null) { + buildVariables.addVariable(OUTPUT_EXECPATH_VARIABLE, outputArtifact.getExecPathString()); } if (!ltoOutputRootPrefix.equals(PathFragment.EMPTY_FRAGMENT)) { @@ -1303,6 +1344,21 @@ public class CppLinkActionBuilder { + ";" + configuration.getBinDirectory().getExecPath().getRelative(ltoOutputRootPrefix)); } + boolean shouldGenerateInterfaceLibrary = + outputArtifact != null + && interfaceLibraryBuilder != null + && interfaceLibraryOutput != null; + buildVariables.addVariable( + GENERATE_INTERFACE_LIBRARY_VARIABLE, shouldGenerateInterfaceLibrary ? "yes" : "no"); + buildVariables.addVariable( + INTERFACE_LIBRARY_BUILDER_VARIABLE, + shouldGenerateInterfaceLibrary ? interfaceLibraryBuilder.getExecPathString() : "ignored"); + buildVariables.addVariable( + INTERFACE_LIBRARY_INPUT_VARIABLE, + shouldGenerateInterfaceLibrary ? outputArtifact.getExecPathString() : "ignored"); + buildVariables.addVariable( + INTERFACE_LIBRARY_OUTPUT_VARIABLE, + shouldGenerateInterfaceLibrary ? interfaceLibraryOutput.getExecPathString() : "ignored"); // Variables arising from the toolchain buildVariables diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionConfigs.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionConfigs.java index a359350834..dc7b250c0a 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionConfigs.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionConfigs.java @@ -15,6 +15,7 @@ package com.google.devtools.build.lib.rules.cpp; import com.google.common.base.Joiner; import com.google.common.collect.ImmutableList; +import java.util.Set; /** * A helper class for creating action_configs for the c++ link action. @@ -30,7 +31,25 @@ public class CppLinkActionConfigs { MAC } - public static String getCppLinkActionConfigs(CppLinkPlatform platform) { + public static String getCppLinkActionConfigs( + CppLinkPlatform platform, Set<String> features, String cppLinkDynamicLibraryToolPath) { + String cppDynamicLibraryLinkerTool = ""; + if (!features.contains("dynamic_library_linker_tool")) { + cppDynamicLibraryLinkerTool = + "" + + "feature {" + + " name: 'dynamic_library_linker_tool'" + + " flag_set {" + + " action: 'c++-link-dynamic-library'" + + " flag_group {" + + " flag: '" + + cppLinkDynamicLibraryToolPath + + "'" + + " }" + + " }" + + "}"; + } + return Joiner.on("\n") .join( ImmutableList.of( @@ -55,6 +74,8 @@ public class CppLinkActionConfigs { " tool {", " tool_path: 'DUMMY_TOOL'", " }", + " implies: 'build_interface_libraries'", + " implies: 'dynamic_library_linker_tool'", " implies: 'symbol_counts'", " implies: 'shared_flag'", " implies: 'linkstamps'", @@ -109,6 +130,22 @@ public class CppLinkActionConfigs { " implies: 'global_whole_archive_close'", "}", "feature {", + " name: 'build_interface_libraries'", + " flag_set {", + " expand_if_all_available: 'generate_interface_library'", + " action: 'c++-link-dynamic-library'", + " flag_group {", + " flag: '%{generate_interface_library}'", + " flag: '%{interface_library_builder_path}'", + " flag: '%{interface_library_input_path}'", + " flag: '%{interface_library_output_path}'", + " }", + " }", + "}", + // Order of feature declaration matters, cppDynamicLibraryLinkerTool has to follow + // right after build_interface_libraries. + cppDynamicLibraryLinkerTool, + "feature {", " name: 'symbol_counts'", " flag_set {", " expand_if_all_available: 'symbol_counts_output'", diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/LinkCommandLine.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/LinkCommandLine.java index db3ab654fd..27e3e4db99 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/LinkCommandLine.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/LinkCommandLine.java @@ -53,14 +53,13 @@ import javax.annotation.Nullable; @Immutable public final class LinkCommandLine extends CommandLine { private final String actionName; - private final BuildConfiguration configuration; + private final String toolPath; private final CppConfiguration cppConfiguration; private final ActionOwner owner; private final CcToolchainFeatures.Variables variables; // The feature config can be null for tests. @Nullable private final FeatureConfiguration featureConfiguration; @Nullable private final Artifact output; - @Nullable private final Artifact interfaceOutput; private final ImmutableList<Artifact> buildInfoHeaderArtifacts; private final Iterable<? extends LinkerInput> linkerInputs; private final Iterable<? extends LinkerInput> runtimeInputs; @@ -77,14 +76,13 @@ public final class LinkCommandLine extends CommandLine { private final List<String> noWholeArchiveFlags; @Nullable private final Artifact paramFile; - @Nullable private final Artifact interfaceSoBuilder; private LinkCommandLine( String actionName, + String toolPath, BuildConfiguration configuration, ActionOwner owner, Artifact output, - @Nullable Artifact interfaceOutput, ImmutableList<Artifact> buildInfoHeaderArtifacts, Iterable<? extends LinkerInput> linkerInputs, Iterable<? extends LinkerInput> runtimeInputs, @@ -100,23 +98,17 @@ public final class LinkCommandLine extends CommandLine { boolean useTestOnlyFlags, boolean needWholeArchive, @Nullable Artifact paramFile, - Artifact interfaceSoBuilder, List<String> noWholeArchiveFlags, CcToolchainFeatures.Variables variables, @Nullable FeatureConfiguration featureConfiguration) { this.actionName = actionName; - this.configuration = Preconditions.checkNotNull(configuration); + this.toolPath = toolPath; this.cppConfiguration = configuration.getFragment(CppConfiguration.class); this.variables = variables; this.featureConfiguration = featureConfiguration; this.owner = Preconditions.checkNotNull(owner); this.output = output; - this.interfaceOutput = interfaceOutput; - if (interfaceOutput != null) { - Preconditions.checkNotNull(this.output); - } - this.buildInfoHeaderArtifacts = Preconditions.checkNotNull(buildInfoHeaderArtifacts); this.linkerInputs = Preconditions.checkNotNull(linkerInputs); this.runtimeInputs = Preconditions.checkNotNull(runtimeInputs); @@ -135,23 +127,6 @@ public final class LinkCommandLine extends CommandLine { this.useTestOnlyFlags = useTestOnlyFlags; this.paramFile = paramFile; this.noWholeArchiveFlags = noWholeArchiveFlags; - - // For now, silently ignore interfaceSoBuilder if we don't build an interface dynamic library. - this.interfaceSoBuilder = - ((linkTargetType == LinkTargetType.DYNAMIC_LIBRARY) && (interfaceOutput != null)) - ? Preconditions.checkNotNull( - interfaceSoBuilder, "cannot build interface dynamic library without builder") - : null; - } - - /** - * Returns an interface shared object output artifact produced during linking. This only returns - * non-null if {@link #getLinkTargetType} is {@code DYNAMIC_LIBRARY} and an interface shared - * object was requested. - */ - @Nullable - public Artifact getInterfaceOutput() { - return interfaceOutput; } @Nullable @@ -410,17 +385,7 @@ public final class LinkCommandLine extends CommandLine { break; case DYNAMIC_LIBRARY: - if (interfaceOutput != null) { - argv.add(configuration.getShellExecutable().getPathString()); - argv.add("-c"); - argv.add( - "build_iface_so=\"$0\"; impl=\"$1\"; iface=\"$2\"; cmd=\"$3\"; shift 3; " - + "\"$cmd\" \"$@\" && \"$build_iface_so\" \"$impl\" \"$iface\""); - argv.add(interfaceSoBuilder.getExecPathString()); - argv.add(output.getExecPathString()); - argv.add(interfaceOutput.getExecPathString()); - } - argv.add(cppConfiguration.getCppExecutable().getPathString()); + argv.add(toolPath); argv.addAll(featureConfiguration.getCommandLine(actionName, variables)); argv.addAll(noWholeArchiveFlags); addToolchainFlags(argv); @@ -443,11 +408,7 @@ public final class LinkCommandLine extends CommandLine { // TODO(b/30109612): make this pattern the case for all link variants. case OBJC_ARCHIVE: case OBJC_FULLY_LINKED_ARCHIVE: - argv.add( - featureConfiguration - .getToolForAction(actionName) - .getToolPath(cppConfiguration.getCrosstoolTopPathFragment()) - .getPathString()); + argv.add(toolPath); argv.addAll(featureConfiguration.getCommandLine(actionName, variables)); break; @@ -664,8 +625,8 @@ public final class LinkCommandLine extends CommandLine { private final ActionOwner owner; @Nullable private final RuleContext ruleContext; + @Nullable private String toolPath; @Nullable private Artifact output; - @Nullable private Artifact interfaceOutput; private ImmutableList<Artifact> buildInfoHeaderArtifacts = ImmutableList.of(); private Iterable<? extends LinkerInput> linkerInputs = ImmutableList.of(); private Iterable<? extends LinkerInput> runtimeInputs = ImmutableList.of(); @@ -680,7 +641,6 @@ public final class LinkCommandLine extends CommandLine { private boolean useTestOnlyFlags; private boolean needWholeArchive; @Nullable private Artifact paramFile; - @Nullable private Artifact interfaceSoBuilder; @Nullable private CcToolchainProvider toolchain; private Variables variables; private FeatureConfiguration featureConfiguration; @@ -740,10 +700,10 @@ public final class LinkCommandLine extends CommandLine { return new LinkCommandLine( actionName, + toolPath, configuration, owner, output, - interfaceOutput, buildInfoHeaderArtifacts, linkerInputs, runtimeInputs, @@ -759,7 +719,6 @@ public final class LinkCommandLine extends CommandLine { useTestOnlyFlags, needWholeArchive, paramFile, - interfaceSoBuilder, noWholeArchiveFlags, variables, featureConfiguration); @@ -774,9 +733,13 @@ public final class LinkCommandLine extends CommandLine { return this; } - /** - * Sets the feature configuration for this link action. - */ + /** Sets the tool path, with tool being the first thing on the command line */ + public Builder setToolPath(String toolPath) { + this.toolPath = toolPath; + return this; + } + + /** Sets the feature configuration for this link action. */ public Builder setFeatureConfiguration(FeatureConfiguration featureConfiguration) { this.featureConfiguration = featureConfiguration; return this; @@ -818,16 +781,6 @@ public final class LinkCommandLine extends CommandLine { } /** - * Sets the additional interface output artifact, which is only used for dynamic libraries. The - * {@link #build} method throws an exception if the target type is not {@link - * LinkTargetType#DYNAMIC_LIBRARY}. - */ - public Builder setInterfaceOutput(Artifact interfaceOutput) { - this.interfaceOutput = interfaceOutput; - return this; - } - - /** * Sets the linker options. These are passed to the linker in addition to the other linker * options like linker inputs, symbol count options, etc. The {@link #build} method throws an * exception if the linker options are non-empty for a static link (see {@link @@ -850,16 +803,6 @@ public final class LinkCommandLine extends CommandLine { } /** - * Sets the binary that should be used to create the interface output for a dynamic library. - * This is ignored unless the target type is {@link LinkTargetType#DYNAMIC_LIBRARY} and an - * interface output artifact is specified. - */ - public Builder setInterfaceSoBuilder(Artifact interfaceSoBuilder) { - this.interfaceSoBuilder = interfaceSoBuilder; - return this; - } - - /** * Sets the linkstamps. Linkstamps are additional C++ source files that are compiled as part of * the link command. The {@link #build} method throws an exception if the linkstamps are * non-empty for a static link (see {@link LinkTargetType#staticness()}}). |