From 3c5a1098af0c5ae80d4e3b1fc52dd1fef6027d43 Mon Sep 17 00:00:00 2001 From: hlopko Date: Wed, 21 Mar 2018 04:03:40 -0700 Subject: Add crosstool_lib.bzl and crosstool_utils.bzl These will be used to rewrite current crosstool autoconfiguration into action_configs and features. RELNOTES: None. PiperOrigin-RevId: 189888171 --- .../devtools/build/lib/rules/cpp/CcCommon.java | 36 +- .../com/google/devtools/build/lib/rules/cpp/BUILD | 5 +- .../rules/cpp/SkylarkCcToolchainConfigureTest.java | 144 +++++++- tools/cpp/BUILD | 10 + tools/cpp/crosstool_lib.bzl | 407 +++++++++++++++++++++ tools/cpp/crosstool_utils.bzl | 276 ++++++++++++++ 6 files changed, 863 insertions(+), 15 deletions(-) create mode 100644 tools/cpp/crosstool_lib.bzl create mode 100644 tools/cpp/crosstool_utils.bzl diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCommon.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCommon.java index b25dc7fc85..a2da30d674 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCommon.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCommon.java @@ -50,6 +50,7 @@ import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.Variables; import com.google.devtools.build.lib.rules.cpp.CppConfiguration.DynamicMode; import com.google.devtools.build.lib.rules.cpp.CppConfiguration.HeadersCheckingMode; import com.google.devtools.build.lib.rules.cpp.FdoSupport.FdoMode; +import com.google.devtools.build.lib.rules.cpp.Link.LinkTargetType; import com.google.devtools.build.lib.shell.ShellUtils; import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec; import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec.VisibleForSerialization; @@ -105,11 +106,8 @@ public final class CcCommon { } }; - /** Action configs we request to enable. */ - private static final ImmutableSet DEFAULT_ACTION_CONFIGS = + public static final ImmutableSet ALL_COMPILE_ACTIONS = ImmutableSet.of( - CppCompileAction.CC_FLAGS_MAKE_VARIABLE_ACTION_NAME, - CppCompileAction.STRIP_ACTION_NAME, CppCompileAction.C_COMPILE, CppCompileAction.CPP_COMPILE, CppCompileAction.CPP_HEADER_PARSING, @@ -120,16 +118,29 @@ public final class CcCommon { CppCompileAction.PREPROCESS_ASSEMBLE, CppCompileAction.CLIF_MATCH, CppCompileAction.LINKSTAMP_COMPILE, - Link.LinkTargetType.STATIC_LIBRARY.getActionName(), - // We need to create pic-specific actions for link actions, as they will produce - // differently named outputs. - Link.LinkTargetType.PIC_STATIC_LIBRARY.getActionName(), + CppCompileAction.CC_FLAGS_MAKE_VARIABLE_ACTION_NAME); + + public static final ImmutableSet ALL_LINK_ACTIONS = + ImmutableSet.of( Link.LinkTargetType.INTERFACE_DYNAMIC_LIBRARY.getActionName(), - Link.LinkTargetType.NODEPS_DYNAMIC_LIBRARY.getActionName(), Link.LinkTargetType.DYNAMIC_LIBRARY.getActionName(), - Link.LinkTargetType.ALWAYS_LINK_STATIC_LIBRARY.getActionName(), - Link.LinkTargetType.ALWAYS_LINK_PIC_STATIC_LIBRARY.getActionName(), - Link.LinkTargetType.EXECUTABLE.getActionName()); + Link.LinkTargetType.NODEPS_DYNAMIC_LIBRARY.getActionName(), + LinkTargetType.EXECUTABLE.getActionName()); + + public static final ImmutableSet ALL_ARCHIVE_ACTIONS = + ImmutableSet.of(Link.LinkTargetType.STATIC_LIBRARY.getActionName()); + + public static final ImmutableSet ALL_OTHER_ACTIONS = + ImmutableSet.of(CppCompileAction.STRIP_ACTION_NAME); + + /** Action configs we request to enable. */ + public static final ImmutableSet DEFAULT_ACTION_CONFIGS = + ImmutableSet.builder() + .addAll(ALL_COMPILE_ACTIONS) + .addAll(ALL_LINK_ACTIONS) + .addAll(ALL_ARCHIVE_ACTIONS) + .addAll(ALL_OTHER_ACTIONS) + .build(); /** Features we request to enable unless a rule explicitly doesn't support them. */ private static final ImmutableSet DEFAULT_FEATURES = @@ -142,6 +153,7 @@ public final class CcCommon { CppRuleClasses.INCLUDE_PATHS, CppRuleClasses.PIC, CppRuleClasses.PREPROCESSOR_DEFINES); + public static final String CC_TOOLCHAIN_DEFAULT_ATTRIBUTE_NAME = ":cc_toolchain"; /** C++ configuration */ diff --git a/src/test/java/com/google/devtools/build/lib/rules/cpp/BUILD b/src/test/java/com/google/devtools/build/lib/rules/cpp/BUILD index 7e0b17115b..9d5482bada 100644 --- a/src/test/java/com/google/devtools/build/lib/rules/cpp/BUILD +++ b/src/test/java/com/google/devtools/build/lib/rules/cpp/BUILD @@ -13,7 +13,10 @@ filegroup( java_test( name = "cpp-rules-tests", srcs = glob(["*.java"]) + ["proto/CcProtoLibraryTest.java"], - resources = ["//tools/cpp:lib_cc_configure"], + resources = [ + "//tools/cpp:crosstool_utils", + "//tools/cpp:lib_cc_configure", + ], tags = ["rules"], test_class = "com.google.devtools.build.lib.AllTests", deps = [ diff --git a/src/test/java/com/google/devtools/build/lib/rules/cpp/SkylarkCcToolchainConfigureTest.java b/src/test/java/com/google/devtools/build/lib/rules/cpp/SkylarkCcToolchainConfigureTest.java index dbaa612fb3..c3386fff9a 100644 --- a/src/test/java/com/google/devtools/build/lib/rules/cpp/SkylarkCcToolchainConfigureTest.java +++ b/src/test/java/com/google/devtools/build/lib/rules/cpp/SkylarkCcToolchainConfigureTest.java @@ -26,6 +26,15 @@ import org.junit.runners.JUnit4; @RunWith(JUnit4.class) public class SkylarkCcToolchainConfigureTest extends EvaluationTestCase { + @Test + public void testActionNames() throws Exception { + newTest() + .testStatement("COMPILE_ACTIONS", MutableList.copyOf(env, CcCommon.ALL_COMPILE_ACTIONS)) + .testStatement("LINK_ACTIONS", MutableList.copyOf(env, CcCommon.ALL_LINK_ACTIONS)) + .testStatement("ARCHIVE_ACTIONS", MutableList.copyOf(env, CcCommon.ALL_ARCHIVE_ACTIONS)) + .testStatement("OTHER_ACTIONS", MutableList.copyOf(env, CcCommon.ALL_OTHER_ACTIONS)); + } + @Test public void testSplitEscaped() throws Exception { newTest() @@ -47,7 +56,135 @@ public class SkylarkCcToolchainConfigureTest extends EvaluationTestCase { .testStatement("split_escaped('a%%b', ':')", MutableList.of(env, "a%b")) .testStatement("split_escaped('a%:', ':')", MutableList.of(env, "a:")); } - + + @Test + public void testActionConfig() throws Exception { + newTest() + .testStatement( + "action_config('c++-compile', '/usr/bin/gcc')", + "\n" + + " action_config {\n" + + " config_name: 'c++-compile'\n" + + " action_name: 'c++-compile'\n" + + " tool {\n" + + " tool_path: '/usr/bin/gcc'\n" + + " }\n" + + " }"); + } + + @Test + public void testFeature() throws Exception { + newTest() + .testStatement( + "feature(" + + "'fully_static_link', " + + " [ " + + " flag_set(" + + " ['c++-link-dynamic-library', 'c++-link-nodeps-dynamic-library'], " + + " [flag_group([flag('-a'), flag('-b'), flag('-c')])])])", + "\n" + + " feature {\n" + + " name: 'fully_static_link'\n" + + " enabled: true\n" + + " flag_set {\n" + + " action: 'c++-link-dynamic-library'\n" + + " action: 'c++-link-nodeps-dynamic-library'\n" + + " flag_group {\n" + + " flag: '-a'\n" + + " flag: '-b'\n" + + " flag: '-c'\n" + + " }\n" + + " }\n" + + " }"); + } + + @Test + public void testFeatureThoroughly() throws Exception { + newTest() + .testStatement( + "feature(" + + "'fully_static_link', " + + " [ " + + " flag_set(" + + " ['c++-link-dynamic-library'], " + + " [flag_group([flag('-a')])])," + + " flag_set(" + + " ['c++-link-dynamic-library']," + + " [" + + " flag_group(" + + " [flag('-a')]," + + " iterate_over='a')," + + " flag_group(" + + " [flag('-c')]," + + " expand_if_all_available=['a','b']," + + " expand_if_none_available=['a']," + + " expand_if_true=['a','b']," + + " expand_if_false=['a']," + + " expand_if_equal=[['a','val']]," + + " )," + + " flag_group(" + + " [flag('-c')]," + + " iterate_over='a'," + + " expand_if_all_available=['a','b']," + + " expand_if_none_available=['a']," + + " expand_if_true=['a','b']," + + " expand_if_false=['a']," + + " expand_if_equal=[['a','val']]," + + " )" + + " ])," + + " flag_set(" + + " ['c++-link-dynamic-library'], " + + " [flag_group([flag_group([flag('-a')])])])" + + " ])", + "\n" + + " feature {\n" + + " name: 'fully_static_link'\n" + + " enabled: true\n" + + " flag_set {\n" + + " action: 'c++-link-dynamic-library'\n" + + " flag_group {\n" + + " flag: '-a'\n" + + " }\n" + + " }\n" + + " flag_set {\n" + + " action: 'c++-link-dynamic-library'\n" + + " flag_group {\n" + + " iterate_over: 'a'\n" + + " flag: '-a'\n" + + " }\n" + + " flag_group {\n" + + " expand_if_all_available: 'a'\n" + + " expand_if_all_available: 'b'\n" + + " expand_if_none_available: 'a'\n" + + " expand_if_true: 'a'\n" + + " expand_if_true: 'b'\n" + + " expand_if_false: 'a'\n" + + " expand_if_equal { variable: 'a' value: 'val' }\n" + + " flag: '-c'\n" + + " }\n" + + " flag_group {\n" + + " expand_if_all_available: 'a'\n" + + " expand_if_all_available: 'b'\n" + + " expand_if_none_available: 'a'\n" + + " expand_if_true: 'a'\n" + + " expand_if_true: 'b'\n" + + " expand_if_false: 'a'\n" + + " expand_if_equal { variable: 'a' value: 'val' }\n" + + " iterate_over: 'a'\n" + + " flag: '-c'\n" + + " }\n" + + " }\n" + + " flag_set {\n" + + " action: 'c++-link-dynamic-library'\n" + + " flag_group {\n" + + " flag_group {\n" + + " flag: '-a'\n" + + " }\n" + + " }\n" + + " }\n" + + " }"); + } + private ModalTestCase newTest(String... skylarkOptions) throws IOException { return new SkylarkTest(skylarkOptions) // A mock implementation of Label to be able to parse lib_cc_configure under default @@ -56,6 +193,9 @@ public class SkylarkCcToolchainConfigureTest extends EvaluationTestCase { .setUp("def Label(arg):\n return 42") .setUp( ResourceLoader.readFromResources( - TestConstants.BAZEL_REPO_PATH + "tools/cpp/lib_cc_configure.bzl")); + TestConstants.BAZEL_REPO_PATH + "tools/cpp/lib_cc_configure.bzl")) + .setUp( + ResourceLoader.readFromResources( + TestConstants.BAZEL_REPO_PATH + "tools/cpp/crosstool_utils.bzl")); } } diff --git a/tools/cpp/BUILD b/tools/cpp/BUILD index 3ba10505c1..4412b1454f 100644 --- a/tools/cpp/BUILD +++ b/tools/cpp/BUILD @@ -219,6 +219,16 @@ filegroup( srcs = ["lib_cc_configure.bzl"], ) +filegroup( + name = "crosstool_utils", + srcs = ["crosstool_utils.bzl"], +) + +filegroup( + name = "crosstool_lib", + srcs = ["crosstool_lib.bzl"], +) + cc_toolchain_type(name = "toolchain_type") # A dummy toolchain is necessary to satisfy toolchain resolution until platforms diff --git a/tools/cpp/crosstool_lib.bzl b/tools/cpp/crosstool_lib.bzl new file mode 100644 index 0000000000..a2dfde6ffa --- /dev/null +++ b/tools/cpp/crosstool_lib.bzl @@ -0,0 +1,407 @@ +# pylint: disable=g-bad-file-header +# 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. +"""Library of common crosstool features.""" + +load("@bazel_tools//tools/cpp:crosstool_utils.bzl", + "feature", + "simple_feature", + "flag_set", + "flag_group", + "flags", + "COMPILE_ACTIONS", + "LINK_ACTIONS", + "ARCHIVE_ACTIONS") + + +def get_features_to_appear_first(platform): + """Returns standard features that should appear in the top of the toolchain. + + Args: + platform: one of [ k8, darwin, msvc ] + + Returns: + a collection of features to be put into crosstool + """ + return [ + simple_feature("no_legacy_features", [], []), + simple_feature( + "legacy_compile_flags", + COMPILE_ACTIONS, + ["%{legacy_compile_flags}"], + expand_if_all_available=["legacy_compile_flags"], + iterate_over="legacy_compile_flags"), + simple_feature( + "dependency_file", + COMPILE_ACTIONS, + ["-MD", "-MF", "%{dependency_file}"], + expand_if_all_available=["dependency_file"]), + simple_feature( + "random_seed", + COMPILE_ACTIONS, + ["-frandom-seed=%{output_file}"]), + simple_feature( + "pic", + COMPILE_ACTIONS, + ["-fPIC"], + expand_if_all_available=["pic"]), + simple_feature( + "per_object_debug_info", + COMPILE_ACTIONS, + ["-gsplit-dwarf"], + expand_if_all_available=["per_object_debug_info_file"]), + simple_feature( + "preprocessor_defines", + COMPILE_ACTIONS, + ["-D%{preprocessor_defines}"], + iterate_over="preprocessor_defines", + expand_if_all_available=["preprocessor_defines"]), + simple_feature( + "includes", + COMPILE_ACTIONS, + ["-include", "%{includes}"], + iterate_over="includes", + expand_if_all_available=["includes"]), + simple_feature( + "quote_include_paths", + COMPILE_ACTIONS, + ["-iquote", "%{quote_include_paths}"], + iterate_over="quote_include_paths", + expand_if_all_available=["quote_include_paths"]), + simple_feature( + "include_paths", + COMPILE_ACTIONS, + ["-I%{include_paths}"], + iterate_over="include_paths", + expand_if_all_available=["include_paths"]), + simple_feature( + "system_include_paths", + COMPILE_ACTIONS, + ["-isystem", "%{system_include_paths}"], + iterate_over="system_include_paths", + expand_if_all_available=["system_include_paths"]), + simple_feature( + "symbol_counts", + LINK_ACTIONS, + ["-Wl,--print-symbol-counts=%{symbol_counts_output}"], + expand_if_all_available=["symbol_counts_output"]), + simple_feature( + "shared_flag", + LINK_ACTIONS, + ["-shared"], + expand_if_all_available=["symbol_counts_output"]), + simple_feature( + "output_execpath_flags", + LINK_ACTIONS, + ["-o", "%{output_execpath}"], + expand_if_all_available=["output_execpath"]), + simple_feature( + "runtime_library_search_directories", + LINK_ACTIONS, + [_runtime_library_directory_flag(platform)], + iterate_over="runtime_library_search_directories", + expand_if_all_available=["runtime_library_search_directories"]), + simple_feature( + "library_search_directories", + LINK_ACTIONS, + ["-L%{library_search_directories}"], + iterate_over="library_search_directories", + expand_if_all_available=["library_search_directories"]), + simple_feature("_archiver_flags", ARCHIVE_ACTIONS, _archiver_flags(platform)), + feature( + "libraries_to_link", [ + flag_set(ARCHIVE_ACTIONS, [ + flag_group([ + flag_group( + flags("%{libraries_to_link.name}"), + expand_if_equal=[["libraries_to_link.type", "object_file"]]), + flag_group( + flags("%{libraries_to_link.object_files}"), + expand_if_equal=[["libraries_to_link.type", "object_file_group"]], + iterate_over="libraries_to_link.object_files"), + ], + iterate_over="libraries_to_link", + expand_if_all_available=["libraries_to_link"]) + ]), + flag_set(LINK_ACTIONS, [ + flag_group([ + flag_group( + flags("-Wl,--start-lib"), + expand_if_equal=[["libraries_to_link.type", "object_file_group"]] + ), + ] + + _libraries_to_link_flag_groupss(platform) + [ + flag_group( + flags("-Wl,--end-lib"), + expand_if_equal=[["libraries_to_link.type", "object_file_group"]] + ), + ], + iterate_over="libraries_to_link" + ), + flag_group(flags("-Wl,@%{thinlto_param_file}"), expand_if_true=["thinlto_param_file"]) + ]) + ]), + simple_feature( + "force_pic_flags", + ["c++-link-executable"], + ["-pie"], + expand_if_all_available=["force_pic"]), + simple_feature( + "legacy_link_flags", + LINK_ACTIONS, + ["%{legacy_link_flags}"], + iterate_over="legacy_link_flags", + expand_if_all_available=["legacy_link_flags"]), + simple_feature( + "fission_support", + LINK_ACTIONS, + ["-Wl,--gdb-index"], + expand_if_all_available=["is_using_fission"]), + simple_feature( + "strip_debug_symbols", + LINK_ACTIONS, + ["-Wl,-S"], + expand_if_all_available=["strip_debug_symbols"]), + _coverage_feature(platform), + simple_feature("strip_flags", ["strip"], _strip_flags(platform)), + ] + + +def get_features_to_appear_last(platform): + """Returns standard features that should appear at the end of the toolchain. + + Args: + platform: one of [ k8, darwin, msvc ] + + Returns: + a collection of features to be put into crosstool + """ + return [ + simple_feature( + "user_compile_flags", + COMPILE_ACTIONS, + ["%{user_compile_flags}"], + expand_if_all_available=["user_compile_flags"], + iterate_over="user_compile_flags"), + simple_feature( + "sysroot", + COMPILE_ACTIONS + LINK_ACTIONS, + ["--sysroot=%{sysroot}"], + expand_if_all_available=["sysroot"]), + simple_feature( + "unfiltered_compile_flags", + COMPILE_ACTIONS, + ["%{unfiltered_compile_flags}"], + expand_if_all_available=["unfiltered_compile_flags"], + iterate_over="unfiltered_compile_flags"), + simple_feature( + "linker_param_file", + LINK_ACTIONS, + [_linker_param_file_flag(platform)], + expand_if_all_available=["linker_param_file"]), + simple_feature( + "archiver_param_file", + ARCHIVE_ACTIONS, + [_archiver_param_file_flag(platform)], + expand_if_all_available=["linker_param_file"]), + simple_feature( + "compiler_input_flags", + COMPILE_ACTIONS, + ["-c", "%{source_file}"], + expand_if_all_available=["source_file"]), + feature( + "compiler_output_flags", [ + flag_set(COMPILE_ACTIONS,[ + flag_group( + flags("-o", "%{output_object_file}"), + expand_if_all_available=["output_object_file"], + ), + flag_group( + flags("-S", "-o", "%{output_assembly_file}"), + expand_if_all_available=["output_assembly_file"], + ), + flag_group( + flags("-E", "-o", "%{output_preprocess_file}"), + expand_if_all_available=["output_preprocess_file"], + ), + ]) + ] + ), + ] + + +def _is_linux(platform): + return platform == "k8" + + +def _is_darwin(platform): + return platform == "darwin" + + +def _is_msvc(platform): + return platform == "msvc" + + +def _coverage_feature(use_llvm_format): + if use_llvm_format: + compile_flags = flags("-fprofile-instr-generate", "-fcoverage-mapping") + link_flags = flags("-fprofile-instr-generate") + else: + compile_flags = flags("-fprofile-arcs", "-ftest-coverage") + link_flags = flags("-lgcov") + return feature( + "coverage", + [ + flag_set(COMPILE_ACTIONS, [ flag_group(compile_flags) ]), + flag_set(LINK_ACTIONS, [ flag_group(link_flags) ]), + ], + enabled = False, + provides = "profile") + + +def _runtime_library_directory_flag(platform): + if _is_linux(platform): + return "-Wl,-rpath,$ORIGIN/%{runtime_library_search_directories}" + elif _is_darwin(platform): + return "-Wl,-rpath,@loader_path/%{runtime_library_search_directories}" + elif _is_msvc(platform): + fail("todo") + else: + fail("Unsupported platform: " + platform) + + +def _archiver_flags(platform): + if _is_linux(platform): + return ["rcsD", "%{output_execpath}"] + elif _is_darwin(platform): + return ["-static", "-s", "-o", "%{output_execpath}"] + elif _is_msvc(platform): + fail("todo") + else: + fail("Unsupported platform: " + platform) + + +def _library_to_link_with_worce_load(variable_type, variable, flag = "", iterate = False): + return [ + flag_group([ + flag_group( + flags( + "-Wl,-force_load," + flag + "%{" + variable + "}", + expand_if_true=["libraries_to_link.is_whole_archive"])), + flag_group( + flags( + flag + "%{" + variable + "}", + expand_if_false=["libraries_to_link.is_whole_archive"])), + ], + iterate_over=variable if iterate else None, + expand_if_equal=[["libraries_to_link.type", variable_type]]), + ] + + +def _libraries_to_link_flag_groupss(platform): + if _is_linux(platform): + return [ + flag_group( + flags("-Wl,-whole-archive"), + expand_if_true=["libraries_to_link.is_whole_archive"]), + flag_group( + flags("-Wl,--start-lib"), + expand_if_equal=[["libraries_to_link.type", "object_file_group"]]), + flag_group( + flags("%{libraries_to_link.object_files}"), + iterate_over="libraries_to_link.object_files", + expand_if_equal=[["libraries_to_link.type", "object_file_group"]]), + flag_group( + flags("-Wl,--end-lib"), + expand_if_equal=[["libraries_to_link.type", "object_file_group"]]), + flag_group( + flags("%{libraries_to_link.name}"), + expand_if_equal=[["libraries_to_link.type", "object_file"]]), + flag_group( + flags("%{libraries_to_link.name}"), + expand_if_equal=[["libraries_to_link.type", "interface_library"]]), + flag_group( + flags("%{libraries_to_link.name}"), + expand_if_equal=[["libraries_to_link.type", "static_library"]]), + flag_group( + flags("-l%{libraries_to_link.name}"), + expand_if_equal=[["libraries_to_link.type", "dynamic_library"]]), + flag_group( + flags("-l:%{libraries_to_link.name}"), + expand_if_equal=[["libraries_to_link.type", "versioned_dynamic_library"]]), + flag_group( + flags("-Wl,-no-whole-archive"), + expand_if_true=["libraries_to_link.is_whole_archive"]), + ] + if _is_darwin(platform): + return [ + flag_group( + flags("-Wl,--start-lib"), + expand_if_equal=[["libraries_to_link.type", "object_file_group"]]), + _library_to_link_with_worce_load( + "object_file_group", "libraries_to_link.object_files", iterate = True), + flag_group( + flags("-Wl,--end-lib"), + expand_if_equal=[["libraries_to_link.type", "object_file_group"]]), + _library_to_link_with_worce_load("object_file", "libraries_to_link.name"), + _library_to_link_with_worce_load("interface_library", "libraries_to_link.name"), + _library_to_link_with_worce_load("static_library", "libraries_to_link.name"), + _library_to_link_with_worce_load("dynamic_library", "libraries_to_link.name", flag="-l"), + _library_to_link_with_worce_load("versioned_dynamic_library", "libraries_to_link.name", flag="-l:"), + ] + elif _is_msvc(platform): + fail("todo") + else: + fail("Unsupported platform: " + platform) + + +def _strip_flags(platform): + if _is_linux(platform): + return [ "-S", "-p", "-o", "%{output_file}", + "-R", ".gnu.switches.text.quote_paths", + "-R", ".gnu.switches.text.bracket_paths", + "-R", ".gnu.switches.text.system_paths", + "-R", ".gnu.switches.text.cpp_defines", + "-R", ".gnu.switches.text.cpp_includes", + "-R", ".gnu.switches.text.cl_args", + "-R", ".gnu.switches.text.lipo_info", + "-R", ".gnu.switches.text.annotation", ] + elif _is_darwin(platform): + return ["-S", "-o", "%{output_file}"] + elif _is_msvc(platform): + fail("todo") + else: + fail("Unsupported platform: " + platform) + + +def _linker_param_file_flag(platform): + if _is_linux(platform): + return "-Wl,@%{linker_param_file}" + elif _is_darwin(platform): + return "-Wl,@%{linker_param_file}" + elif _is_msvc(platform): + fail("todo") + else: + fail("Unsupported platform: " + platform) + + +def _archiver_param_file_flag(platform): + if _is_linux(platform): + return "@%{linker_param_file}" + elif _is_darwin(platform): + return "@%{linker_param_file}" + elif _is_msvc(platform): + fail("todo") + else: + fail("Unsupported platform: " + platform) diff --git a/tools/cpp/crosstool_utils.bzl b/tools/cpp/crosstool_utils.bzl new file mode 100644 index 0000000000..caadba1f31 --- /dev/null +++ b/tools/cpp/crosstool_utils.bzl @@ -0,0 +1,276 @@ +# pylint: disable=g-bad-file-header +# 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. +"""Utility functions for writing crosstool files in Skylark""" + +# All possible C++ compile actions +COMPILE_ACTIONS = [ + "c-compile", + "c++-compile", + "c++-header-parsing", + "c++-header-preprocessing", + "c++-module-compile", + "c++-module-codegen", + "assemble", + "preprocess-assemble", + "clif-match", + "linkstamp-compile", + "cc-flags-make-variable", +] + +# All possible C++ link actions +LINK_ACTIONS = [ + "c++-link-interface-dynamic-library", + "c++-link-dynamic-library", + "c++-link-nodeps-dynamic-library", + "c++-link-executable", +] + +# All possible C++ archive actions +ARCHIVE_ACTIONS = [ + "c++-link-static-library", +] + +# All remaining actions used by C++ rules that are configured in the CROSSTOOL +OTHER_ACTIONS = [ + "strip" +] + + +def action_config(action_name, tool_path): + """Emit action_config message. + + Examples: + action_config("c-compile", "/usr/bin/gcc") -> + action_config { + config_name: 'c-compile' + action_name: 'c-compile' + tool { + tool_path: '/usr/bin/gcc' + } + } + + Args: + action_name: name of the action + tool_path: absolute or CROSSTOOL-relative path to the tool + + Returns: + a string to be placed into the CROSSTOOL + """ + if action_name == None or action_name == "": + fail("action_name must be present") + if tool_path == None or tool_path == "": + fail("tool_path must be present") + return """ + action_config {{ + config_name: '{action_name}' + action_name: '{action_name}' + tool {{ + tool_path: '{tool_path}' + }} + }}""".format(action_name=action_name, tool_path=tool_path) + + +def feature(name, flag_sets, enabled = True, provides = None): + """Emit feature message. + + Examples: + feature("fully_static_link", flag_sets, enabled = False) -> + feature { + name: 'fully_static_link' + enabled = false + + } + + Args: + name: name of the feature + flag_sets: a collection of flag_set messages + enabled: whether this feature is turned on by default + provides: a symbol this feature provides, used to implement mutually incompatible features + + Returns: + a string to be placed into the CROSSTOOL + """ + if name == None or name == "": + fail("feature name must be present") + return """ + feature {{ + name: '{name}' + enabled: {enabled}{provides}{flag_sets} + }}""".format( + provides=("\n provides: '%s'" % provides if provides != None else ""), + name=name, + enabled=_to_proto_value(enabled), + flag_sets="".join(flag_sets)) + + +def simple_feature(name, actions, flags, enabled = True, provides = None, + expand_if_all_available = [], iterate_over = None): + """Sugar for emitting simple feature message. + + Examples: + simple_feature("foo", ['c-compile'], flags("-foo")) -> + feature { + name: 'foo' + flag_set { + action: 'c-compile' + flag_group { + flag: '-foo' + } + } + } + + Args: + name: name of the feature + actions: for which actions should flags be emitted + flags: a collection of flag messages + enabled: whether this feature is turned on by default + provides: a symbol this feature provides, used to implement mutually incompatible features + expand_if_all_available: specify which build variables need to be present + for this group to be expanded + iterate_over: expand this flag_group for every item in the build variable + + Returns: + a string to be placed into the CROSSTOOL + """ + if len(flags) == 0: + return feature(name, []) + else: + return feature( + name, + [flag_set( + actions, + [flag_group( + [flag(f) for f in flags], + iterate_over=iterate_over, + expand_if_all_available=expand_if_all_available)])], + enabled = enabled, + provides = provides) + + +def flag_set(actions, flag_groups): + """Emit flag_set message. + + Examples: + flag_set(['c-compile'], flag_groups) -> + flag_set { + action: 'c-compile' + + } + + Args: + actions: for which actions should flags be emitted + flag_groups: a collection of flag_group messages + + Returns: + a string to be placed into the CROSSTOOL + """ + if actions == None or len(actions) == 0: + fail("empty actions list is not allowed for flag_set") + if flag_groups == None or len(flag_groups) == 0: + fail("empty flag_groups list is not allowed for flag_set") + actions_string = "" + for action in actions: actions_string += "\n action: '%s'" % action + + return """ + flag_set {{{actions}{flag_groups} + }}""".format(actions=actions_string, flag_groups="".join(flag_groups)) + + +def flag_group( + content, expand_if_all_available = [], expand_if_none_available = [], expand_if_true = [], + expand_if_false = [], expand_if_equal = [], iterate_over = None): + """Emit flag_group message. + + Examples: + flag_group(flags("-foo %{output_file}"), expand_if_all_available="output_file") -> + flag_group { expand_if_all_available: "output_file" + flag: "-foo %{output_file}" + } + + Args: + content: a collection of flag messages or a collection of flag_group messages + expand_if_all_available: specify which build variables need to be present + for this group to be expanded + expand_if_none_available: specify which build variables need to be missing + for this group to be expanded + expand_if_true: specify which build variables need to be truthy for this group + to be expanded + expand_if_false: specify which build variables need to be falsey for this group + to be expanded + expand_if_equal: [[var1, value1], [var2, value2]...] specify what values + should specific build variables have for this group to be expanded + iterate_over: expand this flag_group for every item in the build variable + + Returns: + a string to be placed into the CROSSTOOL + """ + if content == None or len(content)== 0: + fail("flag_group without flags is not allowed") + conditions = "" + for var in expand_if_all_available: + conditions += "\n expand_if_all_available: '%s'" % var + for var in expand_if_none_available: + conditions += "\n expand_if_none_available: '%s'" % var + for var in expand_if_true: + conditions += "\n expand_if_true: '%s'" % var + for var in expand_if_false: + conditions += "\n expand_if_false: '%s'" % var + for var in expand_if_equal: + conditions += "\n expand_if_equal { variable: '%s' value: '%s' }" % (var[0], var[1]) + return """ + flag_group {{{conditions}{iterate_over}{content} + }}""".format( + content="".join(content), + iterate_over=("\n iterate_over: '%s'" % iterate_over if iterate_over != None else ""), + conditions=conditions) + + +def flag(flag): + """Emit flag field. + + Examples: + flag("-foo") -> flag: '-foo' + + Args: + flag: value to be emitted to the command line + + Returns: + a string to be placed into the CROSSTOOL + """ + return "\n flag: '%s'" % flag + + +def flags(*flags): + """Sugar for emitting sequence of flag fields. + + Examples: + flags("-foo", "-bar") -> + flag: '-foo' + flag: '-bar' + + Args: + *flags: values to be emitted to the command line + + Returns: + a string to be placed into the CROSSTOOL + """ + return [flag(f) for f in flags] + + +def _to_proto_value(boolean): + if boolean: + return "true" + else: + return "false" -- cgit v1.2.3