From 407becabb204c20a82e12f62818a1793ff36d853 Mon Sep 17 00:00:00 2001 From: Tony Allevato Date: Fri, 27 May 2022 10:48:19 -0700 Subject: [PATCH] Separate toolchain configuration logic from the rest of the rules' business logic The tool/action config logic had previously been exported as a single module. Since I wanted to separate that out, it required updating all the call sites, so I took the opportunity to remove the tool/action config function wrappers and just expose the actual "providers" that back them, using new provider initializers to massage/validate the arguments before they are set as fields. I also removed the `swift_action_names` struct and just made those names top-level constants. PiperOrigin-RevId: 451429760 (cherry picked from commit 699ffd5b1997a28aa4e5f18e4dc4b04bab786d34) Signed-off-by: Brentley Jones --- swift/internal/BUILD | 66 +- swift/internal/action_names.bzl | 60 + swift/internal/actions.bzl | 73 +- swift/internal/autolinking.bzl | 17 +- swift/internal/compiling.bzl | 2085 +---------------- swift/internal/debugging.bzl | 84 +- swift/internal/linking.bzl | 5 +- swift/internal/symbol_graph_extracting.bzl | 53 +- swift/internal/toolchain_config.bzl | 335 --- swift/internal/wmo.bzl | 132 ++ swift/toolchains/BUILD | 28 +- swift/toolchains/config/BUILD | 60 +- swift/toolchains/config/action_config.bzl | 191 ++ .../toolchains/config/all_actions_config.bzl | 37 + swift/toolchains/config/compile_config.bzl | 1887 +++++++++++++++ .../compile_module_interface_config.bzl | 33 +- swift/toolchains/config/modulewrap_config.bzl | 48 + .../toolchains/config/symbol_graph_config.bzl | 64 + swift/toolchains/config/tool_config.bzl | 159 ++ swift/toolchains/swift_toolchain.bzl | 208 +- swift/toolchains/xcode_swift_toolchain.bzl | 148 +- 21 files changed, 2996 insertions(+), 2777 deletions(-) create mode 100644 swift/internal/action_names.bzl delete mode 100644 swift/internal/toolchain_config.bzl create mode 100644 swift/internal/wmo.bzl create mode 100644 swift/toolchains/config/action_config.bzl create mode 100644 swift/toolchains/config/all_actions_config.bzl create mode 100644 swift/toolchains/config/compile_config.bzl create mode 100644 swift/toolchains/config/modulewrap_config.bzl create mode 100644 swift/toolchains/config/symbol_graph_config.bzl create mode 100644 swift/toolchains/config/tool_config.bzl diff --git a/swift/internal/BUILD b/swift/internal/BUILD index 67d51fb8d..3153598a3 100644 --- a/swift/internal/BUILD +++ b/swift/internal/BUILD @@ -20,13 +20,19 @@ cc_library( # Starlark libraries +bzl_library( + name = "action_names", + srcs = ["action_names.bzl"], + visibility = ["//swift:__subpackages__"], +) + bzl_library( name = "actions", srcs = ["actions.bzl"], visibility = ["//swift:__subpackages__"], deps = [ ":features", - ":toolchain_config", + "//swift/toolchains/config:action_config", "@bazel_skylib//lib:types", ], ) @@ -49,8 +55,9 @@ bzl_library( srcs = ["autolinking.bzl"], visibility = ["//swift:__subpackages__"], deps = [ + ":action_names", ":actions", - ":toolchain_config", + "//swift/toolchains/config:action_config", ], ) @@ -69,20 +76,19 @@ bzl_library( "//swift:__subpackages__", ], deps = [ + ":action_names", ":actions", - ":autolinking", ":debugging", - ":developer_dirs", ":explicit_module_map_file", ":feature_names", ":features", + ":module_maps", ":providers", - ":toolchain_config", ":utils", ":vfsoverlay", - "//swift/toolchains/config:compile_module_interface_config", - "@bazel_skylib//lib:collections", + ":wmo", "@bazel_skylib//lib:paths", + "@bazel_skylib//lib:sets", "@bazel_skylib//lib:types", ], ) @@ -92,9 +98,10 @@ bzl_library( srcs = ["debugging.bzl"], visibility = ["//swift:__subpackages__"], deps = [ + ":action_names", ":actions", ":feature_names", - ":toolchain_config", + ":features", ], ) @@ -111,6 +118,12 @@ bzl_library( visibility = ["//swift:__subpackages__"], ) +bzl_library( + name = "explicit_module_map_file", + srcs = ["explicit_module_map_file.bzl"], + visibility = ["//swift:__subpackages__"], +) + bzl_library( name = "feature_names", srcs = ["feature_names.bzl"], @@ -137,6 +150,7 @@ bzl_library( "//swift:__subpackages__", ], deps = [ + ":action_names", ":actions", ":attrs", ":autolinking", @@ -147,6 +161,7 @@ bzl_library( ":utils", "//swift:swift_clang_module_aspect", "@bazel_skylib//lib:collections", + "@bazel_skylib//lib:dicts", "@bazel_tools//tools/build_defs/cc:action_names.bzl", ], ) @@ -167,6 +182,12 @@ bzl_library( ], ) +bzl_library( + name = "package_specs", + srcs = ["package_specs.bzl"], + visibility = ["//swift:__subpackages__"], +) + bzl_library( name = "providers", srcs = ["providers.bzl"], @@ -209,21 +230,17 @@ bzl_library( srcs = ["symbol_graph_extracting.bzl"], visibility = ["//swift:__subpackages__"], deps = [ + ":action_names", ":actions", ":providers", - ":toolchain_config", ":utils", ], ) bzl_library( - name = "toolchain_config", - srcs = ["toolchain_config.bzl"], + name = "target_triples", + srcs = ["target_triples.bzl"], visibility = ["//swift:__subpackages__"], - deps = [ - "@bazel_skylib//lib:paths", - "@bazel_skylib//lib:types", - ], ) bzl_library( @@ -243,21 +260,12 @@ bzl_library( ) bzl_library( - name = "explicit_module_map_file", - srcs = ["explicit_module_map_file.bzl"], - visibility = ["//swift:__subpackages__"], -) - -bzl_library( - name = "package_specs", - srcs = ["package_specs.bzl"], - visibility = ["//swift:__subpackages__"], -) - -bzl_library( - name = "target_triples", - srcs = ["target_triples.bzl"], + name = "wmo", + srcs = ["wmo.bzl"], visibility = ["//swift:__subpackages__"], + deps = [ + ":feature_names", + ], ) bzl_library( diff --git a/swift/internal/action_names.bzl b/swift/internal/action_names.bzl new file mode 100644 index 000000000..d87b7068c --- /dev/null +++ b/swift/internal/action_names.bzl @@ -0,0 +1,60 @@ +# 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. + +"""Constants representing the names of actions spawned by the Swift rules.""" + +# Extracts a linker input file containing libraries to link from a compiled +# object file to provide autolink functionality based on `import` directives on +# ELF platforms. +SWIFT_ACTION_AUTOLINK_EXTRACT = "SwiftAutolinkExtract" + +# Compiles one or more `.swift` source files into a `.swiftmodule` and +# object files. +SWIFT_ACTION_COMPILE = "SwiftCompile" + +# Compiles a `.swiftinterface` file into a `.swiftmodule` file. +SWIFT_ACTION_COMPILE_MODULE_INTERFACE = "SwiftCompileModuleInterface" + +# Produces files that are usually fallout of the compilation such as +# .swiftmodule, -Swift.h and more. +SWIFT_ACTION_DERIVE_FILES = "SwiftDeriveFiles" + +# Produces an AST file for each swift source file in a module. +SWIFT_ACTION_DUMP_AST = "SwiftDumpAST" + +# Wraps a `.swiftmodule` in a `.o` file on ELF platforms so that it can be +# linked into a binary for debugging. +SWIFT_ACTION_MODULEWRAP = "SwiftModuleWrap" + +# Precompiles an explicit module for a C/Objective-C module map and its +# headers, emitting a `.pcm` file. +SWIFT_ACTION_PRECOMPILE_C_MODULE = "SwiftPrecompileCModule" + +# Extracts a JSON-formatted symbol graph from a module, which can be used as +# an input to documentation generating tools like `docc` or analyzed with +# other tooling. +SWIFT_ACTION_SYMBOL_GRAPH_EXTRACT = "SwiftSymbolGraphExtract" + +def all_action_names(): + """A convenience function to return all actions defined by this rule set.""" + return ( + SWIFT_ACTION_AUTOLINK_EXTRACT, + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_COMPILE_MODULE_INTERFACE, + SWIFT_ACTION_DERIVE_FILES, + SWIFT_ACTION_DUMP_AST, + SWIFT_ACTION_MODULEWRAP, + SWIFT_ACTION_PRECOMPILE_C_MODULE, + SWIFT_ACTION_SYMBOL_GRAPH_EXTRACT, + ) diff --git a/swift/internal/actions.bzl b/swift/internal/actions.bzl index 38fa6cee0..302af77e0 100644 --- a/swift/internal/actions.bzl +++ b/swift/internal/actions.bzl @@ -15,53 +15,13 @@ """Functions for registering actions that invoke Swift tools.""" load("@bazel_skylib//lib:types.bzl", "types") +load("//swift/toolchains/config:action_config.bzl", "ConfigResultInfo") load(":features.bzl", "are_all_features_enabled") -load(":toolchain_config.bzl", "swift_toolchain_config") -load(":utils.bzl", "struct_fields") # This is a proxy for being on bazel 7.x which has # --incompatible_merge_fixed_and_default_shell_env enabled by default USE_DEFAULT_SHELL_ENV = not hasattr(apple_common, "apple_crosstool_transition") -# The names of actions currently supported by the Swift build rules. -swift_action_names = struct( - # Extracts a linker input file containing libraries to link from a compiled - # object file to provide autolink functionality based on `import` directives - # on ELF platforms. - AUTOLINK_EXTRACT = "SwiftAutolinkExtract", - - # Compiles one or more `.swift` source files into a `.swiftmodule` and - # object files. - COMPILE = "SwiftCompile", - - # Compiles a `.swiftinterface` file into a `.swiftmodule` file. - COMPILE_MODULE_INTERFACE = "SwiftCompileModuleInterface", - - # Wraps a `.swiftmodule` in a `.o` file on ELF platforms so that it can be - # linked into a binary for debugging. - MODULEWRAP = "SwiftModuleWrap", - - # Precompiles an explicit module for a C/Objective-C module map and its - # headers, emitting a `.pcm` file. - PRECOMPILE_C_MODULE = "SwiftPrecompileCModule", - - # Extracts a JSON-formatted symbol graph from a module, which can be used as - # an input to documentation generating tools like `docc` or analyzed with - # other tooling. - SYMBOL_GRAPH_EXTRACT = "SwiftSymbolGraphExtract", - - # Produces files that are usually fallout of the compilation such as - # .swiftmodule, -Swift.h and more. - DERIVE_FILES = "SwiftDeriveFiles", - - # Produces an AST file for each swift source file in a module. - DUMP_AST = "SwiftDumpAST", -) - -def _all_action_names(): - """A convenience function to return all actions defined by this rule set.""" - return struct_fields(swift_action_names).values() - def _apply_action_configs( action_name, args, @@ -81,9 +41,8 @@ def _apply_action_configs( swift_toolchain: The Swift toolchain being used to build. Returns: - A `swift_toolchain_config.action_inputs` value that contains the files - that are required inputs of the action, as determined by the - configurators. + A `ConfigResultInfo` value that contains the files that are required + inputs of the action, as determined by the configurators. """ inputs = [] transitive_inputs = [] @@ -135,15 +94,14 @@ def _apply_action_configs( # object for chaining. We can guard against this (and possibly # other errors) by checking that the value is a struct. If it # is, then it's not `None` and it probably came from the - # provider used by `swift_toolchain_config.config_result`. If - # it's some other kind of struct, then we'll error out trying to - # access the fields. + # provider used by `ConfigResultInfo`. If it's some other kind + # of struct, then we'll error out trying to access the fields. if type(action_inputs) == "struct": inputs.extend(action_inputs.inputs) transitive_inputs.extend(action_inputs.transitive_inputs) # Merge the action results into a single result that we return. - return swift_toolchain_config.config_result( + return ConfigResultInfo( inputs = inputs, transitive_inputs = transitive_inputs, ) @@ -228,9 +186,7 @@ def run_toolchain_action( tools.append(tool_config.executable) else: executable = tool_config.executable - - if tool_config.tools: - tools.extend(tool_config.tools) + tools.extend(tool_config.additional_tools) # If the tool configuration has any required arguments, add those first. if tool_config.args: @@ -262,18 +218,3 @@ def run_toolchain_action( use_default_shell_env = USE_DEFAULT_SHELL_ENV, **kwargs ) - -def _target_label_configurator(prerequisites, args): - """Adds the Bazel target label to the action command line.""" - label = getattr(prerequisites, "target_label", None) - if label: - args.add(str(label), format = "-Xwrapped-swift=-bazel-target-label=%s") - -def target_label_action_configs(): - """Returns action configs that add the target label to the command line.""" - return [ - swift_toolchain_config.action_config( - actions = _all_action_names(), - configurators = [_target_label_configurator], - ), - ] diff --git a/swift/internal/autolinking.bzl b/swift/internal/autolinking.bzl index 0710e0e48..70794cd1c 100644 --- a/swift/internal/autolinking.bzl +++ b/swift/internal/autolinking.bzl @@ -14,15 +14,20 @@ """Implementation of autolink logic for Swift.""" -load(":actions.bzl", "run_toolchain_action", "swift_action_names") -load(":toolchain_config.bzl", "swift_toolchain_config") +load( + "//swift/toolchains/config:action_config.bzl", + "ActionConfigInfo", + "ConfigResultInfo", +) +load(":action_names.bzl", "SWIFT_ACTION_AUTOLINK_EXTRACT") +load(":actions.bzl", "run_toolchain_action") def _autolink_extract_input_configurator(prerequisites, args): """Configures the inputs of the autolink-extract action.""" object_files = prerequisites.object_files args.add_all(object_files) - return swift_toolchain_config.config_result(inputs = object_files) + return ConfigResultInfo(inputs = object_files) def _autolink_extract_output_configurator(prerequisites, args): """Configures the outputs of the autolink-extract action.""" @@ -38,8 +43,8 @@ def autolink_extract_action_configs(): The list of action configs needed to perform autolink extraction. """ return [ - swift_toolchain_config.action_config( - actions = [swift_action_names.AUTOLINK_EXTRACT], + ActionConfigInfo( + actions = [SWIFT_ACTION_AUTOLINK_EXTRACT], configurators = [ _autolink_extract_input_configurator, _autolink_extract_output_configurator, @@ -77,7 +82,7 @@ def register_autolink_extract_action( ) run_toolchain_action( actions = actions, - action_name = swift_action_names.AUTOLINK_EXTRACT, + action_name = SWIFT_ACTION_AUTOLINK_EXTRACT, feature_configuration = feature_configuration, outputs = [autolink_file], prerequisites = prerequisites, diff --git a/swift/internal/compiling.bzl b/swift/internal/compiling.bzl index cc714bd64..1a655848b 100644 --- a/swift/internal/compiling.bzl +++ b/swift/internal/compiling.bzl @@ -14,75 +14,40 @@ """Implementation of compilation logic for Swift.""" -load("@bazel_skylib//lib:collections.bzl", "collections") load("@bazel_skylib//lib:paths.bzl", "paths") load("@bazel_skylib//lib:sets.bzl", "sets") load("@bazel_skylib//lib:types.bzl", "types") load( - "//swift/toolchains/config:compile_module_interface_config.bzl", - "compile_module_interface_action_configs", -) -load( - ":actions.bzl", - "is_action_enabled", - "run_toolchain_action", - "swift_action_names", -) -load( - ":developer_dirs.bzl", - "platform_developer_framework_dir", - "swift_developer_lib_dir", + ":action_names.bzl", + "SWIFT_ACTION_COMPILE", + "SWIFT_ACTION_COMPILE_MODULE_INTERFACE", + "SWIFT_ACTION_DERIVE_FILES", + "SWIFT_ACTION_DUMP_AST", + "SWIFT_ACTION_PRECOMPILE_C_MODULE", ) +load(":actions.bzl", "is_action_enabled", "run_toolchain_action") load(":explicit_module_map_file.bzl", "write_explicit_swift_module_map_file") load( ":feature_names.bzl", "SWIFT_FEATURE_ADD_TARGET_NAME_TO_OUTPUT", - "SWIFT_FEATURE_CACHEABLE_SWIFTMODULES", - "SWIFT_FEATURE_CODEVIEW_DEBUG_INFO", - "SWIFT_FEATURE_COVERAGE", - "SWIFT_FEATURE_COVERAGE_PREFIX_MAP", - "SWIFT_FEATURE_DBG", - "SWIFT_FEATURE_DEBUG_PREFIX_MAP", - "SWIFT_FEATURE_DISABLE_SWIFT_SANDBOX", - "SWIFT_FEATURE_DISABLE_SYSTEM_INDEX", "SWIFT_FEATURE_EMIT_BC", "SWIFT_FEATURE_EMIT_C_MODULE", "SWIFT_FEATURE_EMIT_PRIVATE_SWIFTINTERFACE", "SWIFT_FEATURE_EMIT_SWIFTDOC", "SWIFT_FEATURE_EMIT_SWIFTINTERFACE", "SWIFT_FEATURE_EMIT_SWIFTSOURCEINFO", - "SWIFT_FEATURE_ENABLE_BATCH_MODE", "SWIFT_FEATURE_ENABLE_LIBRARY_EVOLUTION", - "SWIFT_FEATURE_ENABLE_SKIP_FUNCTION_BODIES", - "SWIFT_FEATURE_ENABLE_TESTING", - "SWIFT_FEATURE_FASTBUILD", - "SWIFT_FEATURE_FILE_PREFIX_MAP", - "SWIFT_FEATURE_FULL_DEBUG_INFO", "SWIFT_FEATURE_FULL_LTO", - "SWIFT_FEATURE_GLOBAL_MODULE_CACHE_USES_TMPDIR", "SWIFT_FEATURE_INDEX_WHILE_BUILDING", - "SWIFT_FEATURE_LAYERING_CHECK", - "SWIFT_FEATURE_MODULE_MAP_HOME_IS_CWD", - "SWIFT_FEATURE_NO_ASAN_VERSION_CHECK", "SWIFT_FEATURE_NO_GENERATED_MODULE_MAP", "SWIFT_FEATURE_OPT", - "SWIFT_FEATURE_OPT_USES_OSIZE", "SWIFT_FEATURE_OPT_USES_WMO", "SWIFT_FEATURE_PROPAGATE_GENERATED_MODULE_MAP", - "SWIFT_FEATURE_REWRITE_GENERATED_HEADER", "SWIFT_FEATURE_SPLIT_DERIVED_FILES_GENERATION", - "SWIFT_FEATURE_SUPPORTS_BARE_SLASH_REGEX", "SWIFT_FEATURE_SUPPORTS_LIBRARY_EVOLUTION", - "SWIFT_FEATURE_SUPPORTS_SYSTEM_MODULE_FLAG", "SWIFT_FEATURE_SYSTEM_MODULE", "SWIFT_FEATURE_THIN_LTO", - "SWIFT_FEATURE_TREAT_WARNINGS_AS_ERRORS", - "SWIFT_FEATURE_USE_C_MODULES", "SWIFT_FEATURE_USE_EXPLICIT_SWIFT_MODULE_MAP", - "SWIFT_FEATURE_USE_GLOBAL_INDEX_STORE", - "SWIFT_FEATURE_USE_GLOBAL_MODULE_CACHE", - "SWIFT_FEATURE_USE_OLD_DRIVER", - "SWIFT_FEATURE_USE_PCH_OUTPUT_DIR", "SWIFT_FEATURE_VFSOVERLAY", "SWIFT_FEATURE__NUM_THREADS_0_IN_SWIFTCOPTS", "SWIFT_FEATURE__SUPPORTS_CONST_VALUE_EXTRACTION", @@ -103,7 +68,6 @@ load( "create_swift_info", "create_swift_module", ) -load(":toolchain_config.bzl", "swift_toolchain_config") load( ":utils.bzl", "compact", @@ -113,1924 +77,12 @@ load( "struct_fields", ) load(":vfsoverlay.bzl", "write_vfsoverlay") +load(":wmo.bzl", "find_num_threads_flag_value", "is_wmo_manually_requested") # VFS root where all .swiftmodule files will be placed when # SWIFT_FEATURE_VFSOVERLAY is enabled. _SWIFTMODULES_VFS_ROOT = "/__build_bazel_rules_swift/swiftmodules" -# The number of threads to use for WMO builds, using the same number of cores -# that is on a Mac Pro for historical reasons. -# TODO(b/32571265): Generalize this based on platform and core count -# when an API to obtain this is available. -_DEFAULT_WMO_THREAD_COUNT = 12 - -# Swift command line flags that enable whole module optimization. (This -# dictionary is used as a set for quick lookup; the values are irrelevant.) -_WMO_FLAGS = { - "-force-single-frontend-invocation": True, - "-whole-module-optimization": True, - "-wmo": True, -} - -def compile_action_configs( - *, - os = None, - arch = None, - sdkroot = None, - xctest_version = None, - additional_objc_copts = [], - additional_swiftc_copts = [], - generated_header_rewriter = None): - """Returns the list of action configs needed to perform Swift compilation. - - Toolchains must add these to their own list of action configs so that - compilation actions will be correctly configured. - - Args: - os: The OS that we are bulding for. - arch: The architecture that we are building for. - sdkroot: An optional path to the SDK to build against. - xctest_version: The version of XCTest to build against. - additional_objc_copts: An optional list of additional Objective-C - compiler flags that should be passed (preceded by `-Xcc`) to Swift - compile actions *and* Swift explicit module precompile actions after - any other toolchain- or user-provided flags. - additional_swiftc_copts: An optional list of additional Swift compiler - flags that should be passed to Swift compile actions only after any - other toolchain- or user-provided flags. - generated_header_rewriter: An executable that will be invoked after - compilation to rewrite the generated header, or None if this is not - desired. - - Returns: - The list of action configs needed to perform compilation. - """ - - #### Flags that control the driver - action_configs = [ - # Use the legacy driver if requested. - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.COMPILE_MODULE_INTERFACE, - swift_action_names.DERIVE_FILES, - swift_action_names.DUMP_AST, - swift_action_names.PRECOMPILE_C_MODULE, - ], - configurators = [ - swift_toolchain_config.add_arg("-disallow-use-new-driver"), - ], - features = [SWIFT_FEATURE_USE_OLD_DRIVER], - ), - ] - - if sdkroot: - action_configs.append( - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.COMPILE_MODULE_INTERFACE, - swift_action_names.DERIVE_FILES, - swift_action_names.DUMP_AST, - swift_action_names.PRECOMPILE_C_MODULE, - ], - configurators = [ - swift_toolchain_config.add_arg( - "-sdk", - sdkroot, - ), - ], - ), - ) - - if os and xctest_version: - action_configs.append( - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.COMPILE_MODULE_INTERFACE, - swift_action_names.DERIVE_FILES, - swift_action_names.DUMP_AST, - swift_action_names.PRECOMPILE_C_MODULE, - ], - configurators = [ - swift_toolchain_config.add_arg( - paths.join(sdkroot, "..", "..", "Library", "XCTest-{}".format(xctest_version), "usr", "lib", "swift", os), - format = "-I%s", - ), - ], - ), - ) - - # Compatibility with older builds of the Swift SDKs - if arch: - action_configs.append( - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.COMPILE_MODULE_INTERFACE, - swift_action_names.DERIVE_FILES, - swift_action_names.DUMP_AST, - swift_action_names.PRECOMPILE_C_MODULE, - ], - configurators = [ - swift_toolchain_config.add_arg( - paths.join(sdkroot, "..", "..", "Library", "XCTest-{}".format(xctest_version), "usr", "lib", "swift", os, arch), - format = "-I%s", - ), - ], - ), - ) - - #### Flags that control compilation outputs - action_configs += [ - # Emit object file(s). - swift_toolchain_config.action_config( - actions = [swift_action_names.COMPILE], - configurators = [ - swift_toolchain_config.add_arg("-emit-object"), - ], - not_features = [SWIFT_FEATURE_EMIT_BC], - ), - - # Emit llvm bc file(s). - swift_toolchain_config.action_config( - actions = [swift_action_names.COMPILE], - configurators = [ - swift_toolchain_config.add_arg("-emit-bc"), - ], - features = [SWIFT_FEATURE_EMIT_BC], - ), - - # Add the single object file or object file map, whichever is needed. - swift_toolchain_config.action_config( - actions = [swift_action_names.COMPILE], - configurators = [_output_object_or_file_map_configurator], - ), - swift_toolchain_config.action_config( - actions = [swift_action_names.DERIVE_FILES], - configurators = [_output_swiftmodule_or_file_map_configurator], - ), - - # Dump ast files - swift_toolchain_config.action_config( - actions = [swift_action_names.DUMP_AST], - configurators = [ - swift_toolchain_config.add_arg("-dump-ast"), - swift_toolchain_config.add_arg("-suppress-warnings"), - ], - ), - swift_toolchain_config.action_config( - actions = [swift_action_names.DUMP_AST], - configurators = [_output_ast_path_or_file_map_configurator], - ), - - # Emit precompiled Clang modules, and embed all files that were read - # during compilation into the PCM. - swift_toolchain_config.action_config( - actions = [swift_action_names.PRECOMPILE_C_MODULE], - configurators = [ - swift_toolchain_config.add_arg("-emit-pcm"), - swift_toolchain_config.add_arg("-Xcc", "-Xclang"), - swift_toolchain_config.add_arg( - "-Xcc", - "-fmodules-embed-all-files", - ), - ], - ), - - # Don't embed Clang module breadcrumbs in debug info. - swift_toolchain_config.action_config( - actions = [swift_action_names.COMPILE], - configurators = [ - swift_toolchain_config.add_arg( - "-Xfrontend", - "-no-clang-module-breadcrumbs", - ), - ], - features = [ - SWIFT_FEATURE_CACHEABLE_SWIFTMODULES, - ], - ), - - # Add the output precompiled module file path to the command line. - swift_toolchain_config.action_config( - actions = [swift_action_names.PRECOMPILE_C_MODULE], - configurators = [_output_pcm_file_configurator], - ), - - # Configure the path to the emitted .swiftmodule file. - swift_toolchain_config.action_config( - actions = [swift_action_names.COMPILE], - configurators = [_emit_module_path_configurator], - not_features = [SWIFT_FEATURE_SPLIT_DERIVED_FILES_GENERATION], - ), - swift_toolchain_config.action_config( - actions = [swift_action_names.DERIVE_FILES], - configurators = [_emit_module_path_configurator], - ), - - # Configure library evolution and the path to the .swiftinterface file. - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.DERIVE_FILES, - ], - configurators = [ - swift_toolchain_config.add_arg("-enable-library-evolution"), - ], - features = [ - SWIFT_FEATURE_SUPPORTS_LIBRARY_EVOLUTION, - SWIFT_FEATURE_ENABLE_LIBRARY_EVOLUTION, - ], - ), - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.COMPILE_MODULE_INTERFACE, - swift_action_names.DERIVE_FILES, - ], - configurators = [ - swift_toolchain_config.add_arg("-enable-bare-slash-regex"), - ], - features = [ - SWIFT_FEATURE_SUPPORTS_BARE_SLASH_REGEX, - ], - ), - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.DERIVE_FILES, - ], - configurators = [_emit_module_interface_path_configurator], - features = [ - SWIFT_FEATURE_SUPPORTS_LIBRARY_EVOLUTION, - SWIFT_FEATURE_EMIT_SWIFTINTERFACE, - ], - ), - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.DERIVE_FILES, - ], - configurators = [_emit_private_module_interface_path_configurator], - features = [ - SWIFT_FEATURE_SUPPORTS_LIBRARY_EVOLUTION, - SWIFT_FEATURE_EMIT_PRIVATE_SWIFTINTERFACE, - ], - ), - - # Configure the path to the emitted *-Swift.h file. - swift_toolchain_config.action_config( - actions = [swift_action_names.COMPILE], - configurators = [_emit_objc_header_path_configurator], - not_features = [ - SWIFT_FEATURE_SPLIT_DERIVED_FILES_GENERATION, - ], - ), - swift_toolchain_config.action_config( - actions = [swift_action_names.DERIVE_FILES], - configurators = [_emit_objc_header_path_configurator], - ), - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - ], - configurators = [_constant_value_extraction_configurator], - features = [SWIFT_FEATURE__SUPPORTS_CONST_VALUE_EXTRACTION], - ), - - # Link Time Optimization (LTO) - swift_toolchain_config.action_config( - actions = [swift_action_names.COMPILE], - configurators = [ - swift_toolchain_config.add_arg("-lto=llvm-thin"), - ], - features = [SWIFT_FEATURE_THIN_LTO], - ), - swift_toolchain_config.action_config( - actions = [swift_action_names.COMPILE], - configurators = [ - swift_toolchain_config.add_arg("-lto=llvm-full"), - ], - features = [SWIFT_FEATURE_FULL_LTO], - ), - ] - - if generated_header_rewriter: - # Only add the generated header rewriter to the command line only if the - # toolchain provides one, the relevant feature is requested, and the - # particular compilation action is generating a header. - def generated_header_rewriter_configurator(prerequisites, args): - if prerequisites.generated_header_file: - args.add( - generated_header_rewriter, - format = "-Xwrapped-swift=-generated-header-rewriter=%s", - ) - - action_configs.append( - swift_toolchain_config.action_config( - actions = [swift_action_names.COMPILE], - configurators = [generated_header_rewriter_configurator], - features = [SWIFT_FEATURE_REWRITE_GENERATED_HEADER], - ), - ) - - #### Compilation-mode-related flags - # - # These configs set flags based on the current compilation mode. They mirror - # the descriptions of these compilation modes given in the Bazel - # documentation: - # https://docs.bazel.build/versions/master/user-manual.html#flag--compilation_mode - action_configs += [ - # Define appropriate conditional compilation symbols depending on the - # build mode. - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.DERIVE_FILES, - swift_action_names.DUMP_AST, - ], - configurators = [ - swift_toolchain_config.add_arg("-DDEBUG"), - ], - features = [[SWIFT_FEATURE_DBG], [SWIFT_FEATURE_FASTBUILD]], - ), - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.DERIVE_FILES, - swift_action_names.DUMP_AST, - ], - configurators = [ - swift_toolchain_config.add_arg("-DNDEBUG"), - ], - features = [SWIFT_FEATURE_OPT], - ), - - # Set the optimization mode. For dbg/fastbuild, use `-O0`. For opt, use - # `-O` unless the `swift.opt_uses_osize` feature is enabled, then use - # `-Osize`. - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.COMPILE_MODULE_INTERFACE, - swift_action_names.DERIVE_FILES, - ], - configurators = [ - swift_toolchain_config.add_arg("-Onone"), - ], - features = [[SWIFT_FEATURE_DBG], [SWIFT_FEATURE_FASTBUILD]], - ), - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.COMPILE_MODULE_INTERFACE, - swift_action_names.DERIVE_FILES, - ], - configurators = [ - swift_toolchain_config.add_arg("-O"), - ], - features = [SWIFT_FEATURE_OPT], - not_features = [SWIFT_FEATURE_OPT_USES_OSIZE], - ), - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.COMPILE_MODULE_INTERFACE, - swift_action_names.DERIVE_FILES, - ], - configurators = [ - swift_toolchain_config.add_arg("-Osize"), - ], - features = [SWIFT_FEATURE_OPT, SWIFT_FEATURE_OPT_USES_OSIZE], - ), - - # If the `swift.opt_uses_wmo` feature is enabled, opt builds should also - # automatically imply whole-module optimization. - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.DERIVE_FILES, - ], - configurators = [ - swift_toolchain_config.add_arg("-whole-module-optimization"), - ], - features = [ - [SWIFT_FEATURE_OPT, SWIFT_FEATURE_OPT_USES_WMO], - [SWIFT_FEATURE__WMO_IN_SWIFTCOPTS], - ], - ), - - # Enable or disable serialization of debugging options into - # swiftmodules. - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.DERIVE_FILES, - ], - configurators = [ - swift_toolchain_config.add_arg( - "-Xfrontend", - "-no-serialize-debugging-options", - ), - ], - features = [SWIFT_FEATURE_CACHEABLE_SWIFTMODULES], - ), - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.DERIVE_FILES, - ], - configurators = [ - swift_toolchain_config.add_arg( - "-Xfrontend", - "-serialize-debugging-options", - ), - ], - not_features = [ - [SWIFT_FEATURE_OPT], - [SWIFT_FEATURE_CACHEABLE_SWIFTMODULES], - ], - ), - - # Enable testability if requested. - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.DERIVE_FILES, - swift_action_names.DUMP_AST, - ], - configurators = [ - swift_toolchain_config.add_arg("-enable-testing"), - ], - features = [SWIFT_FEATURE_ENABLE_TESTING], - ), - - # Enable warnings-as-errors if requested. - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.DERIVE_FILES, - swift_action_names.DUMP_AST, - ], - configurators = [ - swift_toolchain_config.add_arg("-warnings-as-errors"), - ], - features = [SWIFT_FEATURE_TREAT_WARNINGS_AS_ERRORS], - ), - - # Disable Swift sandbox. - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.DERIVE_FILES, - swift_action_names.DUMP_AST, - ], - configurators = [ - swift_toolchain_config.add_arg("-disable-sandbox"), - ], - features = [SWIFT_FEATURE_DISABLE_SWIFT_SANDBOX], - ), - - # Set Developer Framework search paths - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.DERIVE_FILES, - swift_action_names.DUMP_AST, - ], - configurators = [_non_pcm_developer_framework_paths_configurator], - ), - swift_toolchain_config.action_config( - actions = [ - swift_action_names.PRECOMPILE_C_MODULE, - swift_action_names.SYMBOL_GRAPH_EXTRACT, - ], - configurators = [_pcm_developer_framework_paths_configurator], - ), - - # Emit appropriate levels of debug info. On Apple platforms, requesting - # dSYMs (regardless of compilation mode) forces full debug info because - # `dsymutil` produces spurious warnings about symbols in the debug map - # when run on DI emitted by `-gline-tables-only`. - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.DERIVE_FILES, - ], - configurators = [swift_toolchain_config.add_arg("-g")], - features = [[SWIFT_FEATURE_DBG], [SWIFT_FEATURE_FULL_DEBUG_INFO]], - ), - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.DERIVE_FILES, - ], - configurators = [ - swift_toolchain_config.add_arg("-g"), - swift_toolchain_config.add_arg("-debug-info-format=codeview"), - ], - features = [ - [SWIFT_FEATURE_DBG, SWIFT_FEATURE_CODEVIEW_DEBUG_INFO], - [SWIFT_FEATURE_FASTBUILD, SWIFT_FEATURE_CODEVIEW_DEBUG_INFO], - [SWIFT_FEATURE_FULL_DEBUG_INFO, SWIFT_FEATURE_CODEVIEW_DEBUG_INFO], - ], - ), - swift_toolchain_config.action_config( - actions = [swift_action_names.PRECOMPILE_C_MODULE], - configurators = [swift_toolchain_config.add_arg("-Xcc", "-gmodules")], - features = [[SWIFT_FEATURE_DBG], [SWIFT_FEATURE_FULL_DEBUG_INFO]], - ), - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.DERIVE_FILES, - ], - configurators = [ - swift_toolchain_config.add_arg("-gline-tables-only"), - ], - features = [SWIFT_FEATURE_FASTBUILD], - not_features = [ - [SWIFT_FEATURE_FULL_DEBUG_INFO], - [SWIFT_FEATURE_CODEVIEW_DEBUG_INFO], - ], - ), - - # Make paths written into debug info workspace-relative. - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.DERIVE_FILES, - swift_action_names.PRECOMPILE_C_MODULE, - ], - configurators = [ - swift_toolchain_config.add_arg( - "-Xwrapped-swift=-debug-prefix-pwd-is-dot", - ), - ], - features = [ - [SWIFT_FEATURE_DEBUG_PREFIX_MAP, SWIFT_FEATURE_DBG], - [SWIFT_FEATURE_DEBUG_PREFIX_MAP, SWIFT_FEATURE_FASTBUILD], - [SWIFT_FEATURE_DEBUG_PREFIX_MAP, SWIFT_FEATURE_FULL_DEBUG_INFO], - ], - ), - - # Make paths written into coverage info workspace-relative. - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.DERIVE_FILES, - ], - configurators = [ - swift_toolchain_config.add_arg( - "-Xwrapped-swift=-coverage-prefix-pwd-is-dot", - ), - ], - features = [ - [SWIFT_FEATURE_COVERAGE_PREFIX_MAP, SWIFT_FEATURE_COVERAGE], - ], - ), - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.DERIVE_FILES, - ], - configurators = [ - swift_toolchain_config.add_arg( - "-Xwrapped-swift=-file-prefix-pwd-is-dot", - ), - ], - features = [ - [SWIFT_FEATURE_FILE_PREFIX_MAP], - ], - ), - ] - - #### Coverage and sanitizer instrumentation flags - # - # Note that for the sanitizer flags, we don't define Swift-specific ones; - # if the underlying C++ toolchain doesn't define them, we don't bother - # supporting them either. - action_configs += [ - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.DERIVE_FILES, - ], - configurators = [ - swift_toolchain_config.add_arg("-profile-generate"), - swift_toolchain_config.add_arg("-profile-coverage-mapping"), - ], - features = [SWIFT_FEATURE_COVERAGE], - ), - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.DERIVE_FILES, - ], - configurators = [ - swift_toolchain_config.add_arg("-sanitize=address"), - ], - features = ["asan"], - ), - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.DERIVE_FILES, - ], - configurators = [ - swift_toolchain_config.add_arg( - "-Xllvm", - "-asan-guard-against-version-mismatch=0", - ), - ], - features = [ - "asan", - SWIFT_FEATURE_NO_ASAN_VERSION_CHECK, - ], - ), - swift_toolchain_config.action_config( - actions = [swift_action_names.COMPILE], - configurators = [ - swift_toolchain_config.add_arg("-sanitize=thread"), - ], - features = ["tsan"], - ), - swift_toolchain_config.action_config( - actions = [swift_action_names.COMPILE], - configurators = [ - swift_toolchain_config.add_arg("-sanitize=undefined"), - ], - features = ["ubsan"], - ), - ] - - #### Flags controlling how Swift/Clang modular inputs are processed - - action_configs += [ - # Treat paths in .modulemap files as workspace-relative, not modulemap- - # relative. - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.COMPILE_MODULE_INTERFACE, - swift_action_names.DERIVE_FILES, - swift_action_names.DUMP_AST, - swift_action_names.PRECOMPILE_C_MODULE, - swift_action_names.SYMBOL_GRAPH_EXTRACT, - ], - configurators = [ - swift_toolchain_config.add_arg("-Xcc", "-Xclang"), - swift_toolchain_config.add_arg( - "-Xcc", - "-fmodule-map-file-home-is-cwd", - ), - ], - features = [SWIFT_FEATURE_MODULE_MAP_HOME_IS_CWD], - ), - - # Configure how implicit modules are handled--either using the module - # cache, or disabled completely when using explicit modules. - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.COMPILE_MODULE_INTERFACE, - swift_action_names.DERIVE_FILES, - swift_action_names.DUMP_AST, - ], - configurators = [_global_module_cache_configurator], - features = [SWIFT_FEATURE_USE_GLOBAL_MODULE_CACHE], - not_features = [ - [SWIFT_FEATURE_USE_C_MODULES], - [SWIFT_FEATURE_GLOBAL_MODULE_CACHE_USES_TMPDIR], - ], - ), - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.DERIVE_FILES, - swift_action_names.DUMP_AST, - ], - configurators = [_tmpdir_module_cache_configurator], - features = [ - SWIFT_FEATURE_USE_GLOBAL_MODULE_CACHE, - SWIFT_FEATURE_GLOBAL_MODULE_CACHE_USES_TMPDIR, - ], - not_features = [SWIFT_FEATURE_USE_C_MODULES], - ), - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.COMPILE_MODULE_INTERFACE, - swift_action_names.DERIVE_FILES, - swift_action_names.DUMP_AST, - ], - configurators = [ - swift_toolchain_config.add_arg( - "-Xwrapped-swift=-ephemeral-module-cache", - ), - ], - not_features = [ - [SWIFT_FEATURE_USE_C_MODULES], - [SWIFT_FEATURE_USE_GLOBAL_MODULE_CACHE], - ], - ), - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.DERIVE_FILES, - swift_action_names.DUMP_AST, - ], - configurators = [_pch_output_dir_configurator], - features = [ - SWIFT_FEATURE_USE_PCH_OUTPUT_DIR, - ], - ), - - # When using C modules, disable the implicit search for module map files - # because all of them, including system dependencies, will be provided - # explicitly. - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.COMPILE_MODULE_INTERFACE, - swift_action_names.DERIVE_FILES, - swift_action_names.DUMP_AST, - swift_action_names.PRECOMPILE_C_MODULE, - swift_action_names.SYMBOL_GRAPH_EXTRACT, - ], - configurators = [ - swift_toolchain_config.add_arg( - "-Xcc", - "-fno-implicit-module-maps", - ), - ], - features = [SWIFT_FEATURE_USE_C_MODULES], - ), - # When using C modules, disable the implicit module cache. - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.COMPILE_MODULE_INTERFACE, - swift_action_names.PRECOMPILE_C_MODULE, - swift_action_names.SYMBOL_GRAPH_EXTRACT, - ], - configurators = [ - swift_toolchain_config.add_arg( - "-Xcc", - "-fno-implicit-modules", - ), - ], - features = [SWIFT_FEATURE_USE_C_MODULES], - ), - swift_toolchain_config.action_config( - actions = [swift_action_names.PRECOMPILE_C_MODULE], - configurators = [_c_layering_check_configurator], - features = [SWIFT_FEATURE_LAYERING_CHECK], - not_features = [SWIFT_FEATURE_SYSTEM_MODULE], - ), - swift_toolchain_config.action_config( - actions = [swift_action_names.PRECOMPILE_C_MODULE], - configurators = [ - # Before Swift 5.4, ClangImporter doesn't currently handle the - # IsSystem bit correctly for the input file and ignores the - # `-fsystem-module` flag, which causes the module map to be - # treated as a user input. We can work around this by disabling - # diagnostics for system modules. However, this also disables - # behavior in ClangImporter that causes system APIs that use - # `UInt` to be imported to use `Int` instead. The only solution - # here is to use Xcode 12.5 or higher. - swift_toolchain_config.add_arg("-Xcc", "-w"), - swift_toolchain_config.add_arg( - "-Xcc", - "-Wno-nullability-declspec", - ), - ], - features = [SWIFT_FEATURE_SYSTEM_MODULE], - not_features = [SWIFT_FEATURE_SUPPORTS_SYSTEM_MODULE_FLAG], - ), - swift_toolchain_config.action_config( - actions = [swift_action_names.PRECOMPILE_C_MODULE], - configurators = [ - # `-Xclang -emit-module` ought to be unnecessary if `-emit-pcm` - # is present because ClangImporter configures the invocation to - # use the `GenerateModule` action. However, it does so *after* - # creating the invocation by parsing the command line via a - # helper shared by `-emit-pcm` and other operations, so the - # changing of the action to `GenerateModule` occurs too late; - # the argument parser doesn't know that this will be the - # intended action and it emits a spurious diagnostic: - # "'-fsystem-module' only allowed with '-emit-module'". So, for - # system modules we'll pass `-emit-module` as well; it gets rid - # of the diagnostic and doesn't appear to cause other issues. - swift_toolchain_config.add_arg("-Xcc", "-Xclang"), - swift_toolchain_config.add_arg("-Xcc", "-emit-module"), - swift_toolchain_config.add_arg("-Xcc", "-Xclang"), - swift_toolchain_config.add_arg("-Xcc", "-fsystem-module"), - ], - features = [ - SWIFT_FEATURE_SUPPORTS_SYSTEM_MODULE_FLAG, - SWIFT_FEATURE_SYSTEM_MODULE, - ], - ), - ] - - #### Search paths for Swift module dependencies - action_configs.extend([ - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.COMPILE_MODULE_INTERFACE, - swift_action_names.DERIVE_FILES, - swift_action_names.DUMP_AST, - swift_action_names.SYMBOL_GRAPH_EXTRACT, - ], - configurators = [_dependencies_swiftmodules_configurator], - not_features = [ - [SWIFT_FEATURE_VFSOVERLAY], - [SWIFT_FEATURE_USE_EXPLICIT_SWIFT_MODULE_MAP], - ], - ), - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.DERIVE_FILES, - swift_action_names.DUMP_AST, - ], - configurators = [ - _dependencies_swiftmodules_vfsoverlay_configurator, - ], - features = [SWIFT_FEATURE_VFSOVERLAY], - ), - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE_MODULE_INTERFACE, - ], - configurators = [ - lambda prerequisites, args: _dependencies_swiftmodules_vfsoverlay_configurator( - prerequisites, - args, - is_frontend = True, - ), - ], - features = [SWIFT_FEATURE_VFSOVERLAY], - ), - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.DERIVE_FILES, - swift_action_names.DUMP_AST, - ], - configurators = [ - _explicit_swift_module_map_configurator, - ], - features = [SWIFT_FEATURE_USE_EXPLICIT_SWIFT_MODULE_MAP], - ), - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE_MODULE_INTERFACE, - ], - configurators = [ - lambda prerequisites, args: _explicit_swift_module_map_configurator( - prerequisites, - args, - is_frontend = True, - ), - ], - features = [SWIFT_FEATURE_USE_EXPLICIT_SWIFT_MODULE_MAP], - ), - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.DERIVE_FILES, - ], - configurators = [_plugins_configurator], - ), - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.DERIVE_FILES, - ], - configurators = [_macro_expansion_configurator], - features = [SWIFT_FEATURE__SUPPORTS_MACROS], - ), - ]) - - #### Search paths for framework dependencies - action_configs.extend([ - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.COMPILE_MODULE_INTERFACE, - swift_action_names.DERIVE_FILES, - swift_action_names.DUMP_AST, - swift_action_names.SYMBOL_GRAPH_EXTRACT, - ], - configurators = [ - lambda prereqs, args: _framework_search_paths_configurator( - prereqs, - args, - is_swift = True, - ), - ], - ), - swift_toolchain_config.action_config( - actions = [swift_action_names.PRECOMPILE_C_MODULE], - configurators = [ - lambda prereqs, args: _framework_search_paths_configurator( - prereqs, - args, - is_swift = False, - ), - ], - ), - ]) - - #### Other ClangImporter flags - action_configs.extend([ - # Pass flags to Clang for search paths and propagated defines. - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.COMPILE_MODULE_INTERFACE, - swift_action_names.DERIVE_FILES, - swift_action_names.DUMP_AST, - swift_action_names.PRECOMPILE_C_MODULE, - swift_action_names.SYMBOL_GRAPH_EXTRACT, - ], - configurators = [ - _clang_search_paths_configurator, - _dependencies_clang_defines_configurator, - ], - ), - - # Pass flags to Clang for dependencies' module maps or explicit modules, - # whichever are being used for this build. - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.COMPILE_MODULE_INTERFACE, - swift_action_names.DERIVE_FILES, - swift_action_names.DUMP_AST, - swift_action_names.PRECOMPILE_C_MODULE, - swift_action_names.SYMBOL_GRAPH_EXTRACT, - ], - configurators = [_dependencies_clang_modules_configurator], - features = [SWIFT_FEATURE_USE_C_MODULES], - ), - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.COMPILE_MODULE_INTERFACE, - swift_action_names.DERIVE_FILES, - swift_action_names.DUMP_AST, - swift_action_names.PRECOMPILE_C_MODULE, - swift_action_names.SYMBOL_GRAPH_EXTRACT, - ], - configurators = [_dependencies_clang_modulemaps_configurator], - not_features = [SWIFT_FEATURE_USE_C_MODULES], - ), - ]) - - #### Various other Swift compilation flags - action_configs += [ - # Request color diagnostics, since Bazel pipes the output and causes the - # driver's TTY check to fail. - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.DERIVE_FILES, - swift_action_names.PRECOMPILE_C_MODULE, - ], - configurators = [ - swift_toolchain_config.add_arg( - "-Xfrontend", - "-color-diagnostics", - ), - ], - ), - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE_MODULE_INTERFACE, - ], - configurators = [ - swift_toolchain_config.add_arg("-color-diagnostics"), - ], - ), - - # Request batch mode if the compiler supports it. We only do this if the - # user hasn't requested WMO in some fashion, because otherwise an - # annoying warning message is emitted. At this level, we can disable the - # configurator if the `swift.opt` and `swift.opt_uses_wmo` features are - # both present. Inside the configurator, we also check the user compile - # flags themselves, since some Swift users enable it there as a build - # performance hack. - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.DERIVE_FILES, - ], - configurators = [_batch_mode_configurator], - features = [SWIFT_FEATURE_ENABLE_BATCH_MODE], - not_features = [ - [SWIFT_FEATURE_OPT, SWIFT_FEATURE_OPT_USES_WMO], - [SWIFT_FEATURE__WMO_IN_SWIFTCOPTS], - ], - ), - - # Set the number of threads to use for WMO. (We can skip this if we know - # we'll already be applying `-num-threads` via `--swiftcopt` flags.) - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.DERIVE_FILES, - ], - configurators = [ - _make_wmo_thread_count_configurator( - # WMO is implied by features, so don't check the user - # compile flags. - False, - ), - ], - features = [ - [SWIFT_FEATURE_OPT, SWIFT_FEATURE_OPT_USES_WMO], - [SWIFT_FEATURE__WMO_IN_SWIFTCOPTS], - ], - not_features = [SWIFT_FEATURE__NUM_THREADS_0_IN_SWIFTCOPTS], - ), - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.DERIVE_FILES, - ], - configurators = [ - _make_wmo_thread_count_configurator( - # WMO is not implied by features, so check the user compile - # flags in case they enabled it there. - True, - ), - ], - not_features = [ - [SWIFT_FEATURE_OPT, SWIFT_FEATURE_OPT_USES_WMO], - [SWIFT_FEATURE__NUM_THREADS_0_IN_SWIFTCOPTS], - ], - ), - - # Set the module name. - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.DERIVE_FILES, - swift_action_names.DUMP_AST, - swift_action_names.PRECOMPILE_C_MODULE, - swift_action_names.SYMBOL_GRAPH_EXTRACT, - ], - configurators = [_module_name_configurator], - ), - # Set the package name. - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.DERIVE_FILES, - swift_action_names.DUMP_AST, - swift_action_names.PRECOMPILE_C_MODULE, - ], - configurators = [_package_name_configurator], - ), - - # Pass extra flags for swiftmodule only compilations - swift_toolchain_config.action_config( - actions = [swift_action_names.DERIVE_FILES], - configurators = [ - swift_toolchain_config.add_arg( - "-experimental-skip-non-inlinable-function-bodies", - ), - ], - features = [SWIFT_FEATURE_ENABLE_SKIP_FUNCTION_BODIES], - ), - swift_toolchain_config.action_config( - actions = [swift_action_names.COMPILE], - configurators = [_global_index_store_configurator], - features = [ - SWIFT_FEATURE_INDEX_WHILE_BUILDING, - SWIFT_FEATURE_USE_GLOBAL_INDEX_STORE, - ], - ), - - # Configure index-while-building. - swift_toolchain_config.action_config( - actions = [swift_action_names.COMPILE], - configurators = [_index_while_building_configurator], - features = [SWIFT_FEATURE_INDEX_WHILE_BUILDING], - ), - swift_toolchain_config.action_config( - actions = [swift_action_names.COMPILE], - configurators = [ - swift_toolchain_config.add_arg( - "-index-ignore-system-modules", - ), - ], - features = [ - SWIFT_FEATURE_INDEX_WHILE_BUILDING, - SWIFT_FEATURE_DISABLE_SYSTEM_INDEX, - ], - ), - - # User-defined conditional compilation flags (defined for Swift; those - # passed directly to ClangImporter are handled above). - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.DERIVE_FILES, - swift_action_names.DUMP_AST, - ], - configurators = [_conditional_compilation_flag_configurator], - ), - - # Disable auto-linking for prebuilt static frameworks. - swift_toolchain_config.action_config( - actions = [swift_action_names.COMPILE], - configurators = [_frameworks_disable_autolink_configurator], - ), - ] - - # NOTE: The positions of these action configs in the list are important, - # because it places the `copts` attribute ("user compile flags") after flags - # added by the rules, and then the "additional objc" and "additional swift" - # flags follow those, which are `--objccopt` and `--swiftcopt` flags from - # the command line that should override even the flags specified in the - # `copts` attribute. - action_configs.append( - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.COMPILE_MODULE_INTERFACE, - swift_action_names.DERIVE_FILES, - swift_action_names.DUMP_AST, - ], - configurators = [_user_compile_flags_configurator], - ), - ) - if additional_objc_copts: - action_configs.append( - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.COMPILE_MODULE_INTERFACE, - swift_action_names.DERIVE_FILES, - swift_action_names.DUMP_AST, - swift_action_names.PRECOMPILE_C_MODULE, - ], - configurators = [ - lambda _, args: args.add_all( - additional_objc_copts, - before_each = "-Xcc", - ), - ], - ), - ) - if additional_swiftc_copts: - action_configs.append( - swift_toolchain_config.action_config( - # TODO(allevato): Determine if there are any uses of - # `-Xcc`-prefixed flags that need to be added to explicit module - # actions, or if we should advise against/forbid that. - actions = [ - swift_action_names.COMPILE, - swift_action_names.COMPILE_MODULE_INTERFACE, - swift_action_names.DERIVE_FILES, - swift_action_names.DUMP_AST, - ], - configurators = [ - lambda _, args: args.add_all(additional_swiftc_copts), - ], - ), - ) - - action_configs.append( - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.COMPILE_MODULE_INTERFACE, - swift_action_names.DERIVE_FILES, - swift_action_names.DUMP_AST, - swift_action_names.PRECOMPILE_C_MODULE, - ], - configurators = [_source_files_configurator], - ), - ) - - # Add additional input files to the sandbox (does not modify flags). - action_configs.append( - swift_toolchain_config.action_config( - actions = [ - swift_action_names.COMPILE, - swift_action_names.DERIVE_FILES, - swift_action_names.DUMP_AST, - ], - configurators = [_additional_inputs_configurator], - ), - ) - - action_configs.extend(compile_module_interface_action_configs()) - return action_configs - -def _output_or_file_map(output_file_map, outputs, args): - """Adds the output file map or single file to the command line.""" - if output_file_map: - args.add("-output-file-map", output_file_map) - return swift_toolchain_config.config_result( - inputs = [output_file_map], - ) - - if len(outputs) != 1: - fail( - "Internal error: If not using an output file map, there should " + - "only be a single object file expected as the output, but we " + - "found: {}".format(outputs), - ) - - args.add("-o", outputs[0]) - return None - -def _output_object_or_file_map_configurator(prerequisites, args): - """Adds the output file map or single object file to the command line.""" - return _output_or_file_map( - output_file_map = prerequisites.output_file_map, - outputs = prerequisites.object_files, - args = args, - ) - -def _output_swiftmodule_or_file_map_configurator(prerequisites, args): - """Adds the output file map or single object file to the command line.""" - return _output_or_file_map( - output_file_map = prerequisites.derived_files_output_file_map, - outputs = [prerequisites.swiftmodule_file], - args = args, - ) - -def _output_ast_path_or_file_map_configurator(prerequisites, args): - """Adds the output file map or single AST file to the command line.""" - return _output_or_file_map( - output_file_map = prerequisites.output_file_map, - outputs = prerequisites.ast_files, - args = args, - ) - -def _output_pcm_file_configurator(prerequisites, args): - """Adds the `.pcm` output path to the command line.""" - args.add("-o", prerequisites.pcm_file) - -def _emit_module_path_configurator(prerequisites, args): - """Adds the `.swiftmodule` output path to the command line.""" - args.add("-emit-module-path", prerequisites.swiftmodule_file) - -def _emit_module_interface_path_configurator(prerequisites, args): - """Adds the `.swiftinterface` output path to the command line.""" - args.add("-emit-module-interface-path", prerequisites.swiftinterface_file) - -def _emit_private_module_interface_path_configurator(prerequisites, args): - """Adds the `.private.swiftinterface` output path to the command line.""" - args.add("-emit-private-module-interface-path", prerequisites.private_swiftinterface_file) - -def _emit_objc_header_path_configurator(prerequisites, args): - """Adds the generated header output path to the command line.""" - if prerequisites.generated_header_file: - args.add("-emit-objc-header-path", prerequisites.generated_header_file) - -def _global_module_cache_configurator(prerequisites, args): - """Adds flags to enable the global module cache.""" - - # If bin_dir is not provided, then we don't pass any special flags to - # the compiler, letting it decide where the cache should live. This is - # usually somewhere in the system temporary directory. - if prerequisites.bin_dir: - args.add( - "-module-cache-path", - paths.join(prerequisites.bin_dir.path, "_swift_module_cache"), - ) - -def _tmpdir_module_cache_configurator(prerequisites, args): - """Adds flags to enable a stable tmp directory module cache.""" - - args.add( - "-module-cache-path", - paths.join( - "/tmp/__build_bazel_rules_swift", - "swift_module_cache", - prerequisites.workspace_name, - ), - ) - -def _batch_mode_configurator(prerequisites, args): - """Adds flags to enable batch compilation mode.""" - if not _is_wmo_manually_requested(prerequisites.user_compile_flags): - args.add("-enable-batch-mode") - -def _c_layering_check_configurator(prerequisites, args): - # We do not enforce layering checks for the Objective-C header generated by - # Swift, because we don't have predictable control over the imports that it - # generates. Due to modular re-exports (which are especially common among - # system frameworks), it may generate an import declaration for a particular - # symbol from a different module than the Swift code imported it from. - if not prerequisites.is_swift_generated_header: - args.add("-Xcc", "-fmodules-strict-decluse") - return None - -# The platform developer framework directory contains XCTest.swiftmodule -# with Swift extensions to XCTest, so it needs to be added to the search -# path on platforms where it exists. -def _add_developer_swift_imports(developer_dirs, args): - platform_developer_framework = platform_developer_framework_dir( - developer_dirs, - ) - if platform_developer_framework: - swift_developer_lib_dir_path = swift_developer_lib_dir( - developer_dirs, - ) - args.add(swift_developer_lib_dir_path, format = "-I%s") - -def _non_pcm_developer_framework_paths_configurator(prerequisites, args): - """ Adds developer frameworks flags to the command line. """ - if prerequisites.include_dev_srch_paths: - args.add_all( - [ - developer_dir.path - for developer_dir in prerequisites.developer_dirs - ], - format_each = "-F%s", - ) - _add_developer_swift_imports( - prerequisites.developer_dirs, - args, - ) - -# PCM version of the logic above -def _pcm_developer_framework_paths_configurator(prerequisites, args): - """ Adds developer frameworks flags to the command line. """ - if prerequisites.include_dev_srch_paths: - args.add_all( - [ - developer_dir.path - for developer_dir in prerequisites.developer_dirs - ], - before_each = "-Xcc", - format_each = "-F%s", - ) - _add_developer_swift_imports( - prerequisites.developer_dirs, - args, - ) - -def _clang_module_strict_includes(module_context): - """Returns the strict Clang include paths for a module context.""" - if not module_context.clang: - return None - strict_includes = module_context.clang.strict_includes - if not strict_includes: - return None - return strict_includes.to_list() - -def _clang_search_paths_configurator(prerequisites, args): - """Adds Clang search paths to the command line.""" - args.add_all( - prerequisites.cc_compilation_context.includes, - before_each = "-Xcc", - format_each = "-I%s", - ) - args.add_all( - prerequisites.transitive_modules, - before_each = "-Xcc", - format_each = "-I%s", - map_each = _clang_module_strict_includes, - uniquify = True, - ) - - # Add Clang search paths for the workspace root and Bazel output roots. The - # first allows ClangImporter to find headers included using - # workspace-relative paths when they are referenced from within other - # headers. The latter allows ClangImporter to find generated headers in - # `bazel-{bin,genfiles}` even when included using their workspace-relative - # path, matching the behavior used when compiling C/C++/Objective-C. - # - # Note that when `--incompatible_merge_genfiles_directory` is specified, - # `bin_dir` and `genfiles_dir` will have the same path; the depset will - # ensure that the `-iquote` flags are deduped. - direct_quote_includes = ["."] - if prerequisites.bin_dir: - direct_quote_includes.append(prerequisites.bin_dir.path) - if prerequisites.genfiles_dir: - direct_quote_includes.append(prerequisites.genfiles_dir.path) - - args.add_all( - depset( - direct_quote_includes, - transitive = [ - prerequisites.cc_compilation_context.quote_includes, - ], - ), - before_each = "-Xcc", - format_each = "-iquote%s", - ) - - args.add_all( - prerequisites.cc_compilation_context.system_includes, - before_each = "-Xcc", - format_each = "-isystem%s", - ) - -def _dependencies_clang_defines_configurator(prerequisites, args): - """Adds C/C++ dependencies' preprocessor defines to the command line.""" - all_clang_defines = depset(transitive = [ - prerequisites.cc_compilation_context.defines, - ]) - args.add_all(all_clang_defines, before_each = "-Xcc", format_each = "-D%s") - -def _collect_clang_module_inputs( - explicit_module_compilation_context, - modules, - prefer_precompiled_modules): - """Collects Clang module-related inputs to pass to an action. - - Args: - explicit_module_compilation_context: The `CcCompilationContext` of the - target being compiled, if the inputs are being collected for an - explicit module compilation action. This parameter should be `None` - if inputs are being collected for Swift compilation. - modules: A list of module structures (as returned by - `swift_common.create_module`). The precompiled Clang modules or the - textual module maps and headers of these modules (depending on the - value of `prefer_precompiled_modules`) will be collected as inputs. - prefer_precompiled_modules: If True, precompiled module artifacts should - be preferred over textual module map files and headers for modules - that have them. If False, textual module map files and headers - should always be used. - - Returns: - A toolchain configuration result (i.e., - `swift_toolchain_config.config_result`) that contains the input - artifacts for the action. - """ - direct_inputs = [] - transitive_inputs = [] - - if explicit_module_compilation_context: - # This is a `SwiftPrecompileCModule` action, so by definition we're - # only here in a build with explicit modules enabled. We should only - # need the direct headers of the module being compiled and its - # direct dependencies (the latter because Clang needs them present - # on the file system to map them to the module that contains them.) - # However, we may also need some of the transitive headers, if the - # module has dependencies that aren't recognized as modules (e.g., - # `cc_library` targets without an aspect hint) and the module's - # headers include those. This will likely over-estimate the needed - # inputs, but we can't do better without include scanning in - # Starlark. - transitive_inputs.append(explicit_module_compilation_context.headers) - transitive_inputs.append( - depset(explicit_module_compilation_context.direct_textual_headers), - ) - - for module in modules: - clang_module = module.clang - - # Add the module map, which we use for both implicit and explicit module - # builds. - module_map = clang_module.module_map - if not module.is_system and type(module_map) == "File": - direct_inputs.append(module_map) - - precompiled_module = clang_module.precompiled_module - - if prefer_precompiled_modules and precompiled_module: - # For builds preferring explicit modules, use it if we have it - # and don't include any headers as inputs. - direct_inputs.append(precompiled_module) - else: - # If we don't have an explicit module (or we're not using it), we - # need the transitive headers from the compilation context - # associated with the module. This will likely overestimate the - # headers that will actually be used in the action, but until we can - # use include scanning from Starlark, we can't compute a more - # precise input set. - compilation_context = clang_module.compilation_context - transitive_inputs.append(compilation_context.headers) - transitive_inputs.append( - depset(compilation_context.direct_textual_headers), - ) - - return swift_toolchain_config.config_result( - inputs = direct_inputs, - transitive_inputs = transitive_inputs, - ) - -def _clang_modulemap_dependency_args(module, ignore_system = True): - """Returns a `swiftc` argument for the module map of a Clang module. - - Args: - module: A struct containing information about the module, as defined by - `swift_common.create_module`. - ignore_system: If `True` and the module is a system module, no flag - should be returned. Defaults to `True`. - - Returns: - A list of arguments, possibly empty, to pass to `swiftc` (without the - `-Xcc` prefix). - """ - module_map = module.clang.module_map - - if (module.is_system and ignore_system) or not module_map: - return [] - - if type(module_map) == "File": - module_map_path = module_map.path - else: - module_map_path = module_map - - return ["-fmodule-map-file={}".format(module_map_path)] - -def _clang_module_dependency_args(module): - """Returns `swiftc` arguments for a precompiled Clang module, if possible. - - If a precompiled module is present for this module, then flags for both it - and the module map are returned (the latter is required in order to map - headers to modules in some scenarios, since the precompiled modules are - passed by name). If no precompiled module is present for this module, then - this function falls back to the textual module map alone. - - Args: - module: A struct containing information about the module, as defined by - `swift_common.create_module`. - - Returns: - A list of arguments, possibly empty, to pass to `swiftc` (without the - `-Xcc` prefix). - """ - if module.clang.precompiled_module: - # If we're consuming an explicit module, we must also provide the - # textual module map, whether or not it's a system module. - return [ - "-fmodule-file={}={}".format( - module.name, - module.clang.precompiled_module.path, - ), - ] + _clang_modulemap_dependency_args(module, ignore_system = False) - else: - # If we have no explicit module, then only include module maps for - # non-system modules. - return _clang_modulemap_dependency_args(module) - -def _dependencies_clang_modulemaps_configurator(prerequisites, args): - """Configures Clang module maps from dependencies.""" - modules = [ - module - for module in prerequisites.transitive_modules - if module.clang - ] - - # Uniquify the arguments because different modules might be defined in the - # same module map file, so it only needs to be present once on the command - # line. - args.add_all( - modules, - before_each = "-Xcc", - map_each = _clang_modulemap_dependency_args, - uniquify = True, - ) - - if prerequisites.is_swift: - compilation_context = None - else: - compilation_context = prerequisites.cc_compilation_context - - return _collect_clang_module_inputs( - explicit_module_compilation_context = compilation_context, - modules = modules, - prefer_precompiled_modules = False, - ) - -def _dependencies_clang_modules_configurator(prerequisites, args): - """Configures precompiled Clang modules from dependencies.""" - modules = [ - module - for module in prerequisites.transitive_modules - if module.clang - ] - - # Uniquify the arguments because different modules might be defined in the - # same module map file, so it only needs to be present once on the command - # line. - args.add_all( - modules, - before_each = "-Xcc", - map_each = _clang_module_dependency_args, - uniquify = True, - ) - - if prerequisites.is_swift: - compilation_context = None - else: - compilation_context = prerequisites.cc_compilation_context - - return _collect_clang_module_inputs( - explicit_module_compilation_context = compilation_context, - modules = modules, - prefer_precompiled_modules = True, - ) - -def _framework_search_paths_configurator(prerequisites, args, is_swift): - """Add search paths for prebuilt frameworks to the command line.""" - - # Swift doesn't automatically propagate its `-F` flag to ClangImporter, so - # we add it manually with `-Xcc` below (for both regular compilations, in - # case they're using implicit modules, and Clang module compilations). We - # don't need to add regular `-F` if this is a Clang module compilation, - # though, since it won't be used. - if is_swift: - args.add_all( - prerequisites.cc_compilation_context.framework_includes, - format_each = "-F%s", - ) - args.add_all( - prerequisites.cc_compilation_context.framework_includes, - format_each = "-F%s", - before_each = "-Xcc", - ) - -def _frameworks_disable_autolink_configurator(prerequisites, args): - """Add flags to disable auto-linking for static prebuilt frameworks. - - This disables the `LC_LINKER_OPTION` load commands for auto-linking when - importing a static framework. This is needed to avoid potential linker - errors since when linking the framework it will be passed directly as a - library. - """ - if hasattr(prerequisites.objc_info, "dynamic_framework_file"): - args.add_all( - depset(transitive = [prerequisites.objc_info.imported_library, prerequisites.objc_info.dynamic_framework_file]), - map_each = _disable_autolink_framework_copts, - ) - else: - libraries = [] - inputs = prerequisites.cc_linking_context.linker_inputs.to_list() - for linker_input in inputs: - for library in linker_input.libraries: - if library.dynamic_library: - libraries.append(library.dynamic_library) - if library.static_library: - libraries.append(library.static_library) - if library.pic_static_library: - libraries.append(library.pic_static_library) - - args.add_all( - depset(transitive = [depset(libraries)]), - map_each = _disable_autolink_framework_copts, - ) - -def _dependencies_swiftmodules_configurator(prerequisites, args): - """Adds `.swiftmodule` files from deps to search paths and action inputs.""" - args.add_all( - prerequisites.transitive_modules, - format_each = "-I%s", - map_each = _swift_module_search_path_map_fn, - uniquify = True, - ) - - return swift_toolchain_config.config_result( - inputs = prerequisites.transitive_swiftmodules, - ) - -def _dependencies_swiftmodules_vfsoverlay_configurator(prerequisites, args, is_frontend = False): - """Provides a single `.swiftmodule` search path using a VFS overlay.""" - swiftmodules = prerequisites.transitive_swiftmodules - - # Bug: `swiftc` doesn't pass its `-vfsoverlay` arg to the frontend. - # Workaround: Pass `-vfsoverlay` directly via `-Xfrontend`. - if not is_frontend: - args.add("-Xfrontend") - - args.add( - "-vfsoverlay{}".format(prerequisites.vfsoverlay_file.path), - "-I{}".format(prerequisites.vfsoverlay_search_path), - ) - - return swift_toolchain_config.config_result( - inputs = swiftmodules + [prerequisites.vfsoverlay_file], - ) - -def _load_executable_plugin_map_fn(plugin): - """Returns frontend flags to load compiler plugins.""" - return [ - "-load-plugin-executable", - "{executable}#{module_names}".format( - executable = plugin.executable.path, - module_names = ",".join(plugin.module_names.to_list()), - ), - ] - -def _plugins_configurator(prerequisites, args): - """Adds `-load-plugin-executable` flags for required plugins, if any.""" - args.add_all( - prerequisites.plugins, - before_each = "-Xfrontend", - map_each = _load_executable_plugin_map_fn, - ) - - return swift_toolchain_config.config_result( - inputs = [p.executable for p in prerequisites.plugins.to_list()], - ) - -def _macro_expansion_configurator(prerequisites, args): - """Adds flags to control where macro expansions are generated.""" - if prerequisites.macro_expansion_directory: - args.add( - prerequisites.macro_expansion_directory.path, - format = "-Xwrapped-swift=-macro-expansion-dir=%s", - ) - -def _explicit_swift_module_map_configurator(prerequisites, args, is_frontend = False): - """Adds the explicit Swift module map file to the command line.""" - if is_frontend: - args.add( - "-explicit-swift-module-map-file", - prerequisites.explicit_swift_module_map_file, - ) - else: - args.add_all( - [ - "-explicit-swift-module-map-file", - prerequisites.explicit_swift_module_map_file, - ], - before_each = "-Xfrontend", - ) - return swift_toolchain_config.config_result( - inputs = prerequisites.transitive_swiftmodules + [ - prerequisites.explicit_swift_module_map_file, - ], - ) - -def _module_name_configurator(prerequisites, args): - """Adds the module name flag to the command line.""" - args.add("-module-name", prerequisites.module_name) - -def _package_name_configurator(prerequisites, args): - if prerequisites.package_name: - args.add("-package-name", prerequisites.package_name) - -def _source_files_configurator(prerequisites, args): - """Adds source files to the command line and required inputs.""" - args.add_all(prerequisites.source_files) - - # Only add source files to the input file set if they are not strings (for - # example, the module map of a system framework will be passed in as a file - # path relative to the SDK root, not as a `File` object). - return swift_toolchain_config.config_result( - inputs = [ - source_file - for source_file in prerequisites.source_files - if not types.is_string(source_file) - ], - ) - -def _user_compile_flags_configurator(prerequisites, args): - """Adds user compile flags to the command line.""" - args.add_all(prerequisites.user_compile_flags) - -def _make_wmo_thread_count_configurator(should_check_flags): - """Adds thread count flags for WMO compiles to the command line. - - Args: - should_check_flags: If `True`, WMO wasn't enabled by a feature so the - user compile flags should be checked for an explicit WMO option. If - `False`, unconditionally apply the flags, because it is assumed that - the configurator was triggered by feature satisfaction. - - Returns: - A function used to configure the `-num-threads` flag for WMO. - """ - - def _add_num_threads(args): - args.add("-num-threads", str(_DEFAULT_WMO_THREAD_COUNT)) - - if not should_check_flags: - return lambda _prerequisites, args: _add_num_threads(args) - - def _flag_checking_wmo_thread_count_configurator(prerequisites, args): - if _is_wmo_manually_requested(prerequisites.user_compile_flags): - _add_num_threads(args) - - return _flag_checking_wmo_thread_count_configurator - -def _is_wmo_manually_requested(user_compile_flags): - """Returns `True` if a WMO flag is in the given list of compiler flags. - - Args: - user_compile_flags: A list of compiler flags to scan for WMO usage. - - Returns: - True if WMO is enabled in the given list of flags. - """ - for copt in user_compile_flags: - if copt in _WMO_FLAGS: - return True - return False - -def features_from_swiftcopts(swiftcopts): - """Returns a list of features to enable based on `--swiftcopt` flags. - - Since `--swiftcopt` flags are hooked into the action configuration when the - toolchain is configured, it's not possible for individual actions to query - them easily if those flags may determine the nature of outputs (for example, - single- vs. multi-threaded WMO). The toolchain can call this function to map - those flags to private features that can be queried instead. - - Args: - swiftcopts: The list of command line flags that were passed using - `--swiftcopt`. - - Returns: - A list (possibly empty) of strings denoting feature names that should be - enabled on the toolchain. - """ - features = [] - if _is_wmo_manually_requested(user_compile_flags = swiftcopts): - features.append(SWIFT_FEATURE__WMO_IN_SWIFTCOPTS) - if _find_num_threads_flag_value(user_compile_flags = swiftcopts) == 0: - features.append(SWIFT_FEATURE__NUM_THREADS_0_IN_SWIFTCOPTS) - return features - -def _index_while_building_configurator(prerequisites, args): - """Adds flags for index-store generation to the command line.""" - if not _index_store_path_overridden(prerequisites.user_compile_flags): - args.add("-index-store-path", prerequisites.indexstore_directory.path) - -def _pch_output_dir_configurator(prerequisites, args): - """Adds flags for pch-output-dir configuration to the command line. - - This is a directory to persist automatically created precompiled bridging headers - - Note: that like the global index store and module cache, we expect clang - to namespace these correctly per arch / os version / etc by the hash in - the path. However, it is also put into the bin_dir for an added layer of - safety. - """ - args.add( - "-pch-output-dir", - paths.join(prerequisites.bin_dir.path, "_pch_output_dir"), - ) - -def _global_index_store_configurator(prerequisites, args): - """Adds flags for index-store generation to the command line.""" - out_dir = prerequisites.indexstore_directory.dirname.split("/")[0] - path = out_dir + "/_global_index_store" - args.add("-Xwrapped-swift=-global-index-store-import-path=" + path) - -def _conditional_compilation_flag_configurator(prerequisites, args): - """Adds (non-Clang) conditional compilation flags to the command line.""" - all_defines = depset( - prerequisites.defines, - transitive = [ - # Take any Swift-compatible defines from Objective-C dependencies - # and define them for Swift. - prerequisites.cc_compilation_context.defines, - ], - ) - args.add_all( - all_defines, - map_each = _exclude_swift_incompatible_define, - format_each = "-D%s", - uniquify = True, - ) - -def _constant_value_extraction_configurator(prerequisites, args): - """Adds flags related to constant value extraction to the command line.""" - if not prerequisites.const_protocols_to_gather_file: - return None - - args.add("-emit-const-values-path", prerequisites.const_values_files[0]) - args.add_all( - [ - "-const-gather-protocols-file", - prerequisites.const_protocols_to_gather_file, - ], - before_each = "-Xfrontend", - ) - return swift_toolchain_config.config_result( - inputs = [prerequisites.const_protocols_to_gather_file], - ) - -def _additional_inputs_configurator(prerequisites, _args): - """Propagates additional input files to the action. - - This configurator does not add any flags to the command line, but ensures - that any additional input files requested by the caller of the action are - available in the sandbox. - """ - return swift_toolchain_config.config_result( - inputs = prerequisites.additional_inputs, - ) - def _module_name_safe(string): """Returns a transformation of `string` that is safe for module names.""" result = "" @@ -2277,7 +329,7 @@ def compile_module_interface( run_toolchain_action( actions = actions, - action_name = swift_action_names.COMPILE_MODULE_INTERFACE, + action_name = SWIFT_ACTION_COMPILE_MODULE_INTERFACE, feature_configuration = feature_configuration, outputs = [swiftmodule_file], prerequisites = prerequisites, @@ -2639,7 +691,7 @@ to use swift_common.compile(include_dev_srch_paths = ...) instead.\ if split_derived_file_generation: run_toolchain_action( actions = actions, - action_name = swift_action_names.DERIVE_FILES, + action_name = SWIFT_ACTION_DERIVE_FILES, feature_configuration = feature_configuration, outputs = all_derived_outputs, prerequisites = prerequisites, @@ -2649,7 +701,7 @@ to use swift_common.compile(include_dev_srch_paths = ...) instead.\ run_toolchain_action( actions = actions, - action_name = swift_action_names.COMPILE, + action_name = SWIFT_ACTION_COMPILE, feature_configuration = feature_configuration, outputs = all_compile_outputs, prerequisites = prerequisites, @@ -2665,7 +717,7 @@ to use swift_common.compile(include_dev_srch_paths = ...) instead.\ # a reasonable tradeoff for the additional action. run_toolchain_action( actions = actions, - action_name = swift_action_names.DUMP_AST, + action_name = SWIFT_ACTION_DUMP_AST, feature_configuration = feature_configuration, outputs = compile_outputs.ast_files, prerequisites = prerequisites, @@ -2872,7 +924,7 @@ def _precompile_clang_module( # feature configuration for the target being built does not want a module to # be emitted. if not is_action_enabled( - action_name = swift_action_names.PRECOMPILE_C_MODULE, + action_name = SWIFT_ACTION_PRECOMPILE_C_MODULE, swift_toolchain = swift_toolchain, ): return None @@ -2928,7 +980,7 @@ def _precompile_clang_module( run_toolchain_action( actions = actions, - action_name = swift_action_names.PRECOMPILE_C_MODULE, + action_name = SWIFT_ACTION_PRECOMPILE_C_MODULE, feature_configuration = feature_configuration, outputs = [precompiled_module], prerequisites = prerequisites, @@ -3243,7 +1295,7 @@ def _declare_compile_outputs( ) if ( index_while_building and - not _index_store_path_overridden(user_compile_flags) + not _is_index_store_path_overridden(user_compile_flags) ): indexstore_directory = actions.declare_directory( "{}.indexstore".format(target_name), @@ -3573,7 +1625,7 @@ def swift_library_output_map(name): "archive": "lib{}.a".format(name), } -def _index_store_path_overridden(copts): +def _is_index_store_path_overridden(copts): """Checks if index_while_building must be disabled. Index while building is disabled when the copts include a custom @@ -3590,69 +1642,6 @@ def _index_store_path_overridden(copts): return True return False -def _swift_module_search_path_map_fn(module): - """Returns the path to the directory containing a `.swiftmodule` file. - - This function is intended to be used as a mapping function for modules - passed into `Args.add_all`. - - Args: - module: The module structure (as returned by - `swift_common.create_module`) extracted from the transitive - modules of a `SwiftInfo` provider. - - Returns: - The dirname of the module's `.swiftmodule` file. - """ - if module.swift: - return module.swift.swiftmodule.dirname - else: - return None - -def _disable_autolink_framework_copts(library_path): - """A `map_each` helper that potentially disables autolinking for the given library. - - Args: - library_path: The path to an imported library that is potentially a static framework. - - Returns: - The list of `swiftc` flags needed to disable autolinking for the given - framework. - """ - if not library_path.dirname.endswith(".framework"): - return [] - - return collections.before_each( - "-Xfrontend", - [ - "-disable-autolink-framework", - library_path.basename, - ], - ) - -def _find_num_threads_flag_value(user_compile_flags): - """Finds the value of the `-num-threads` flag. - - This function looks for the `-num-threads` flag and returns the - corresponding value if found. If the flag is present multiple times, the - last value is the one returned. - - Args: - user_compile_flags: The options passed into the compile action. - - Returns: - The numeric value of the `-num-threads` flag if found, otherwise `None`. - """ - num_threads = None - saw_num_threads = False - for copt in user_compile_flags: - if saw_num_threads: - saw_num_threads = False - num_threads = _safe_int(copt) - elif copt == "-num-threads": - saw_num_threads = True - return num_threads - def _emitted_output_nature(feature_configuration, user_compile_flags): """Returns information about the nature of emitted compilation outputs. @@ -3684,7 +1673,7 @@ def _emitted_output_nature(feature_configuration, user_compile_flags): feature_configuration = feature_configuration, feature_names = [SWIFT_FEATURE_OPT, SWIFT_FEATURE_OPT_USES_WMO], ) or - _is_wmo_manually_requested(user_compile_flags) + is_wmo_manually_requested(user_compile_flags) ) # We check the feature first because that implies that `-num-threads 0` was @@ -3694,47 +1683,9 @@ def _emitted_output_nature(feature_configuration, user_compile_flags): is_single_threaded = is_feature_enabled( feature_configuration = feature_configuration, feature_name = SWIFT_FEATURE__NUM_THREADS_0_IN_SWIFTCOPTS, - ) or _find_num_threads_flag_value(user_compile_flags) == 0 + ) or find_num_threads_flag_value(user_compile_flags) == 0 return struct( emits_multiple_objects = not (is_wmo and is_single_threaded), is_wmo = is_wmo, ) - -def _exclude_swift_incompatible_define(define): - """A `map_each` helper that excludes a define if it is not Swift-compatible. - - This function rejects any defines that are not of the form `FOO=1` or `FOO`. - Note that in C-family languages, the option `-DFOO` is equivalent to - `-DFOO=1` so we must preserve both. - - Args: - define: A string of the form `FOO` or `FOO=BAR` that represents an - Objective-C define. - - Returns: - The token portion of the define it is Swift-compatible, or `None` - otherwise. - """ - token, equal, value = define.partition("=") - if (not equal and not value) or (equal == "=" and value == "1"): - return token - return None - -def _safe_int(s): - """Returns the base-10 integer value of `s` or `None` if it is invalid. - - This function is needed because `int()` fails the build when passed a string - that isn't a valid integer, with no way to recover - (https://github.com/bazelbuild/bazel/issues/5940). - - Args: - s: The string to be converted to an integer. - - Returns: - The integer value of `s`, or `None` if was not a valid base 10 integer. - """ - for i in range(len(s)): - if s[i] < "0" or s[i] > "9": - return None - return int(s) diff --git a/swift/internal/debugging.bzl b/swift/internal/debugging.bzl index 3afc50c4b..19305231b 100644 --- a/swift/internal/debugging.bzl +++ b/swift/internal/debugging.bzl @@ -14,11 +14,11 @@ """Functions relating to debugging support during compilation and linking.""" +load(":action_names.bzl", "SWIFT_ACTION_MODULEWRAP") load( ":actions.bzl", "is_action_enabled", "run_toolchain_action", - "swift_action_names", ) load( ":feature_names.bzl", @@ -27,7 +27,6 @@ load( "SWIFT_FEATURE_NO_EMBED_DEBUG_MODULE", ) load(":features.bzl", "is_feature_enabled") -load(":toolchain_config.bzl", "swift_toolchain_config") def ensure_swiftmodule_is_embedded( actions, @@ -54,7 +53,7 @@ def ensure_swiftmodule_is_embedded( information in the binary. """ if is_action_enabled( - action_name = swift_action_names.MODULEWRAP, + action_name = SWIFT_ACTION_MODULEWRAP, swift_toolchain = swift_toolchain, ): # For ELF-format binaries, we need to invoke a Swift modulewrap action @@ -63,11 +62,20 @@ def ensure_swiftmodule_is_embedded( modulewrap_obj = actions.declare_file( "{}.modulewrap.o".format(label.name), ) - _register_modulewrap_action( + prerequisites = struct( + object_file = modulewrap_obj, + swiftmodule_file = swiftmodule, + target_label = feature_configuration._label, + ) + run_toolchain_action( actions = actions, + action_name = SWIFT_ACTION_MODULEWRAP, feature_configuration = feature_configuration, - object = modulewrap_obj, - swiftmodule = swiftmodule, + outputs = [modulewrap_obj], + prerequisites = prerequisites, + progress_message = ( + "Wrapping {} for debugging".format(swiftmodule.short_path) + ), swift_toolchain = swift_toolchain, ) @@ -89,25 +97,6 @@ def ensure_swiftmodule_is_embedded( additional_inputs = depset([swiftmodule]), ) -def modulewrap_action_configs(): - """Returns the list of action configs needed to perform module wrapping. - - If a toolchain supports module wrapping, it should add these to its list of - action configs so that those actions will be correctly configured. - - Returns: - The list of action configs needed to perform module wrapping. - """ - return [ - swift_toolchain_config.action_config( - actions = [swift_action_names.MODULEWRAP], - configurators = [ - _modulewrap_input_configurator, - _modulewrap_output_configurator, - ], - ), - ] - def should_embed_swiftmodule_for_debugging( feature_configuration, module_context): @@ -153,48 +142,3 @@ def _is_debugging(feature_configuration): feature_name = SWIFT_FEATURE_FASTBUILD, ) ) - -def _modulewrap_input_configurator(prerequisites, args): - """Configures the inputs of the modulewrap action.""" - swiftmodule_file = prerequisites.swiftmodule_file - - args.add(swiftmodule_file) - return swift_toolchain_config.config_result(inputs = [swiftmodule_file]) - -def _modulewrap_output_configurator(prerequisites, args): - """Configures the outputs of the modulewrap action.""" - args.add("-o", prerequisites.object_file) - -def _register_modulewrap_action( - actions, - feature_configuration, - object, - swiftmodule, - swift_toolchain): - """Wraps a Swift module in a `.o` file that can be linked into a binary. - - This step (invoking `swift -modulewrap`) is required for the `.swiftmodule` - of the main module of an executable on platforms with ELF-format object - files; otherwise, debuggers will not be able to see those symbols. - - Args: - actions: The object used to register actions. - feature_configuration: The Swift feature configuration. - object: The object file that will be produced by the modulewrap task. - swiftmodule: The `.swiftmodule` file to be wrapped. - swift_toolchain: The `SwiftToolchainInfo` provider of the toolchain. - """ - prerequisites = struct( - object_file = object, - swiftmodule_file = swiftmodule, - target_label = feature_configuration._label, - ) - run_toolchain_action( - actions = actions, - action_name = swift_action_names.MODULEWRAP, - feature_configuration = feature_configuration, - outputs = [object], - prerequisites = prerequisites, - progress_message = "Wrapping Swift module %{label} for debugging", - swift_toolchain = swift_toolchain, - ) diff --git a/swift/internal/linking.bzl b/swift/internal/linking.bzl index 30515640d..c76d43be2 100644 --- a/swift/internal/linking.bzl +++ b/swift/internal/linking.bzl @@ -20,7 +20,8 @@ load( "//swift:swift_clang_module_aspect.bzl", "swift_clang_module_aspect", ) -load(":actions.bzl", "is_action_enabled", "swift_action_names") +load(":action_names.bzl", "SWIFT_ACTION_AUTOLINK_EXTRACT") +load(":actions.bzl", "is_action_enabled") load(":attrs.bzl", "swift_compilation_attrs") load(":autolinking.bzl", "register_autolink_extract_action") load( @@ -261,7 +262,7 @@ def create_linking_context_from_compilation_outputs( # Invoke an autolink-extract action for toolchains that require it. if is_action_enabled( - action_name = swift_action_names.AUTOLINK_EXTRACT, + action_name = SWIFT_ACTION_AUTOLINK_EXTRACT, swift_toolchain = swift_toolchain, ): autolink_file = actions.declare_file( diff --git a/swift/internal/symbol_graph_extracting.bzl b/swift/internal/symbol_graph_extracting.bzl index def9b10f1..78867b4d2 100644 --- a/swift/internal/symbol_graph_extracting.bzl +++ b/swift/internal/symbol_graph_extracting.bzl @@ -14,58 +14,11 @@ """Functions relating to symbol graph extraction.""" -load(":actions.bzl", "run_toolchain_action", "swift_action_names") +load(":action_names.bzl", "SWIFT_ACTION_SYMBOL_GRAPH_EXTRACT") +load(":actions.bzl", "run_toolchain_action") load(":providers.bzl", "create_swift_info") -load(":toolchain_config.bzl", "swift_toolchain_config") load(":utils.bzl", "merge_compilation_contexts") -def symbol_graph_action_configs(): - """Returns the list of action configs needed to extract symbol graphs. - - If a toolchain supports symbol graph extraction, it should add these to its - list of action configs so that those actions will be correctly configured. - (Other required configuration is provided by `compile_action_configs`.) - - Returns: - The list of action configs needed to extract symbol graphs. - """ - return [ - swift_toolchain_config.action_config( - actions = [swift_action_names.SYMBOL_GRAPH_EXTRACT], - configurators = [ - _symbol_graph_emit_extension_block_symbols_configurator, - ], - ), - swift_toolchain_config.action_config( - actions = [swift_action_names.SYMBOL_GRAPH_EXTRACT], - configurators = [ - _symbol_graph_minimum_access_level_configurator, - ], - ), - swift_toolchain_config.action_config( - actions = [swift_action_names.SYMBOL_GRAPH_EXTRACT], - configurators = [ - _symbol_graph_output_configurator, - ], - ), - ] - -def _symbol_graph_emit_extension_block_symbols_configurator(prerequisites, args): - """Configures whether `extension` block information should be emitted in the symbol graph.""" - - # TODO: update to use `bool` once https://github.com/bazelbuild/bazel/issues/22809 is resolved. - if prerequisites.emit_extension_block_symbols == "1": - args.add("-emit-extension-block-symbols") - -def _symbol_graph_minimum_access_level_configurator(prerequisites, args): - """Configures the minimum access level of the symbol graph extraction.""" - if prerequisites.minimum_access_level: - args.add("-minimum-access-level", prerequisites.minimum_access_level) - -def _symbol_graph_output_configurator(prerequisites, args): - """Configures the outputs of the symbol graph extract action.""" - args.add("-output-dir", prerequisites.output_dir.path) - def extract_symbol_graph( *, actions, @@ -151,7 +104,7 @@ def extract_symbol_graph( run_toolchain_action( actions = actions, - action_name = swift_action_names.SYMBOL_GRAPH_EXTRACT, + action_name = SWIFT_ACTION_SYMBOL_GRAPH_EXTRACT, feature_configuration = feature_configuration, outputs = [output_dir], prerequisites = prerequisites, diff --git a/swift/internal/toolchain_config.bzl b/swift/internal/toolchain_config.bzl deleted file mode 100644 index b24c3cee3..000000000 --- a/swift/internal/toolchain_config.bzl +++ /dev/null @@ -1,335 +0,0 @@ -# Copyright 2020 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. - -"""Definitions used to configure toolchains and actions.""" - -load("@bazel_skylib//lib:paths.bzl", "paths") -load("@bazel_skylib//lib:types.bzl", "types") - -_ActionConfigInfo = provider( - doc = "An action configuration in the Swift toolchain.", - fields = [ - "actions", - "configurators", - "features", - "not_features", - ], -) - -_ConfigResultInfo = provider( - doc = "The inputs required by an action configurator.", - fields = [ - "inputs", - "transitive_inputs", - ], -) - -_ToolConfigInfo = provider( - doc = "A tool used by the Swift toolchain and its requirements.", - fields = [ - "args", - "env", - "executable", - "execution_requirements", - "resource_set", - "tools", - "use_param_file", - "worker_mode", - ], -) - -def _normalize_action_config_features(features): - """Validates and normalizes the `features` of an `action_config`. - - This method validates that the argument is either `None`, a non-empty - list of strings, or a non-empty list of lists of strings. If the argument is - the shorthand form (a list of strings), it is normalized by wrapping it in - an outer list so that action building code does not need to be concerned - about the distinction. - - Args: - features: The `features` argument passed to `action_config`. - - Returns: - The `features` argument, normalized if necessary. - """ - if features == None: - return features - - failure_message = ( - "The 'features' argument passed to " + - "'swift_toolchain_config.action_config' must be either None, a list " + - "of strings, or a list of lists of strings.", - ) - - # Fail if the argument is not a list, or if it is but it is empty. - if not types.is_list(features) or not features: - fail(failure_message) - - outer_list_has_strings = False - outer_list_has_lists = False - - # Check each element in the list to determine if it is a list of lists - # or a list of strings. - for element in features: - if types.is_list(element): - outer_list_has_lists = True - elif types.is_string(element) and element: - outer_list_has_strings = True - else: - fail(failure_message) - - # Forbid mixing lists and strings at the top-level. - if outer_list_has_strings and outer_list_has_lists: - fail(failure_message) - - # If the original list was a list of strings, wrap it before returning it - # to the caller. - if outer_list_has_strings: - return [features] - - # Otherwise, return the original list of lists. - return features - -def _action_config( - actions, - configurators, - features = None, - not_features = None): - """Returns a new Swift toolchain action configuration. - - This function validates the inputs, causing the build to fail if they have - incorrect types or are otherwise invalid. - - Args: - actions: A `list` of strings denoting the names of the actions for - which the configurators should be invoked. - configurators: A `list` of functions or that will be invoked to add - command line arguments and collect inputs for the actions. These - functions take two arguments---a `prerequisites` struct and an - `Args` object---and return a either a struct via `config_result` - that describes that `File`s that should be used as inputs to the - action, or `None` if the configurator does not add any inputs. - features: The `list` of features that must be enabled for the - configurators to be applied to the action. This argument can take - one of three forms: `None` (the default), in which case the - configurators are unconditionally applied; a non-empty `list` of - `list`s of feature names (strings), in which case *all* features - mentioned in *one* of the inner lists must be enabled; or a single - non-empty `list` of feature names, which is a shorthand form - equivalent to that single list wrapped in another list. - not_features: The `list` of features that must be disabled for the - configurators to be applied to the action. Like `features`, this - argument can take one of three forms: `None` (the default), in - which case the configurators are applied if `features` was - satisfied; a non-empty `list` of `list`s of feature names (strings), - in which case *all* features mentioned in *one* of the inner lists - must be disabled, otherwise the configurators will not be applied, - even if `features` was satisfied; or a single non-empty `list` of - feature names, which is a shorthand form equivalent to that single - list wrapped in another list. - - Returns: - A validated action configuration. - """ - return _ActionConfigInfo( - actions = actions, - configurators = configurators, - features = _normalize_action_config_features(features), - not_features = _normalize_action_config_features(not_features), - ) - -def _add_arg(arg_name_or_value, value = None, format = None): - """Returns a configurator that adds a simple argument to the command line. - - This is provided as a convenience for the simple case where a configurator - wishes to add a flag to the command line, perhaps based on the enablement - of a feature, without writing a separate function solely for that one flag. - - Args: - arg_name_or_value: The `arg_name_or_value` argument that will be passed - to `Args.add`. - value: The `value` argument that will be passed to `Args.add` (`None` - by default). - format: The `format` argument that will be passed to `Args.add` (`None` - by default). - - Returns: - A function that can be added to the `configurators` list of an - `action_config`. - """ - - # `Args.add` doesn't permit the `value` argument to be `None`, only - # "unbound", so we have to check for this and not pass it *at all* if it - # wasn't specified when the function was created. - if value == None: - return lambda _prerequisites, args: args.add( - arg_name_or_value, - format = format, - ) - - return lambda _prerequisites, args: args.add( - arg_name_or_value, - value, - format = format, - ) - -def _config_result(inputs = [], transitive_inputs = []): - """Returns a value that can be returned from an action configurator. - - Args: - inputs: A list of `File`s that should be passed as inputs to the action - being configured. - transitive_inputs: A list of `depset`s of `File`s that should be passed - as inputs to the action being configured. - - Returns: - A new config result that can be returned from a configurator. - """ - return _ConfigResultInfo( - inputs = inputs, - transitive_inputs = transitive_inputs, - ) - -def _driver_tool_config( - driver_mode, - args = [], - swift_executable = None, - toolchain_root = None, - tool_executable_suffix = "", - **kwargs): - """Returns a new Swift toolchain tool configuration for the Swift driver. - - This is a convenience function that supports the various ways that the Swift - driver can have its location specified or overridden by the build rules, - such as by providing a toolchain root directory or a custom executable. It - supports three kinds of "dispatch": - - 1. If the toolchain provides a custom driver executable, the returned tool - config invokes it with the requested mode passed via the `--driver_mode` - argument. - 2. If the toolchain provides a root directory, then the returned tool - config will use an executable that is a string with the same name as the - driver mode in the `bin` directory of that toolchain. - 3. If the toolchain does not provide a root, then the returned tool config - simply uses the driver mode as the executable, assuming that it will be - available by invoking that alone (e.g., it will be found on the system - path or by another delegating tool like `xcrun` from Xcode). - - Args: - driver_mode: The mode in which to invoke the Swift driver. In other - words, this is the name of the executable of symlink that you want - to execute (e.g., `swift`, `swiftc`, `swift-autolink-extract`). - args: A list of arguments that are always passed to the driver. - swift_executable: A custom Swift driver executable, if provided by the - toolchain. - toolchain_root: The root directory of the Swift toolchain, if the - toolchain provides it. - tool_executable_suffix: The suffix for executable tools. - **kwargs: Additional arguments that will be passed unmodified to - `swift_toolchain_config.tool_config`. - - Returns: - A new tool configuration. - """ - if swift_executable: - executable = swift_executable.path - args = ["--driver-mode={}".format(driver_mode)] + args - elif toolchain_root: - executable = paths.join(toolchain_root, "bin", driver_mode) - else: - executable = driver_mode - - if not executable.endswith(tool_executable_suffix): - executable = "{}{}".format(executable, tool_executable_suffix) - return _tool_config(args = args, executable = executable, **kwargs) - -def _validate_worker_mode(worker_mode): - """Validates the `worker_mode` argument of `tool_config`. - - This function fails the build if the worker mode is not None, "persistent", - or "wrap". - - Args: - worker_mode: The worker mode to validate. - - Returns: - The original worker mode, if it was valid. - """ - if worker_mode != None and worker_mode not in ("persistent", "wrap"): - fail( - "The 'worker_mode' argument of " + - "'swift_toolchain_config.tool_config' must be either None, " + - "'persistent', or 'wrap'.", - ) - - return worker_mode - -def _tool_config( - executable, - args = [], - env = {}, - execution_requirements = {}, - resource_set = None, - tools = [], - use_param_file = False, - worker_mode = None): - """Returns a new Swift toolchain tool configuration. - - Args: - executable: The `File` or `string` denoting the tool that should be - executed. This will be used as the `executable` argument of spawned - actions unless `worker_mode` is set, in which case it will be used - as the first argument to the worker. - args: A list of arguments that are always passed to the tool. - env: A dictionary of environment variables that should be set when - invoking actions using this tool. - execution_requirements: A dictionary of execution requirements that - should be passed when creating actions with this tool. - resource_set: The function which build resource set (mem, cpu) for local - invocation of the action. - tools: A list of additional tools to pass to spawned actions, in a - format suitable for the `tools` argument to `ctx.actions.run`. - use_param_file: If True, actions invoked using this tool will have their - arguments written to a param file. - worker_mode: A string, or `None`, describing how the tool is invoked - using the build rules' worker, if at all. If `None`, the tool will - be invoked directly. If `"wrap"`, the tool will be wrapped in an - invocation of the worker but otherwise run as a single process. If - `"persistent"`, then the action will be launched with execution - requirements that indicate that Bazel should attempt to use a - persistent worker if the spawn strategy allows for it (starting a - new instance if necessary, or connecting to an existing one). - - Returns: - A new tool configuration. - """ - return _ToolConfigInfo( - args = args, - env = env, - executable = executable, - execution_requirements = execution_requirements, - resource_set = resource_set, - tools = tools, - use_param_file = use_param_file, - worker_mode = _validate_worker_mode(worker_mode), - ) - -swift_toolchain_config = struct( - action_config = _action_config, - add_arg = _add_arg, - config_result = _config_result, - driver_tool_config = _driver_tool_config, - tool_config = _tool_config, -) diff --git a/swift/internal/wmo.bzl b/swift/internal/wmo.bzl new file mode 100644 index 000000000..50fc8b272 --- /dev/null +++ b/swift/internal/wmo.bzl @@ -0,0 +1,132 @@ +# Copyright 2022 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. + +"""Functionality releated to detecting whole-module optimization.""" + +load( + ":feature_names.bzl", + "SWIFT_FEATURE__NUM_THREADS_0_IN_SWIFTCOPTS", + "SWIFT_FEATURE__WMO_IN_SWIFTCOPTS", +) + +# Swift command line flags that enable whole module optimization. (This +# dictionary is used as a set for quick lookup; the values are irrelevant.) +_WMO_FLAGS = { + "-wmo": True, + "-whole-module-optimization": True, + "-force-single-frontend-invocation": True, +} + +def features_from_swiftcopts(swiftcopts): + """Returns a list of features to enable based on `--swiftcopt` flags. + + Since `--swiftcopt` flags are hooked into the action configuration when the + toolchain is configured, it's not possible for individual actions to query + them easily if those flags may determine the nature of outputs (for example, + single- vs. multi-threaded WMO). The toolchain can call this function to map + those flags to private features that can be queried instead. + + Args: + swiftcopts: The list of command line flags that were passed using + `--swiftcopt`. + + Returns: + A list (possibly empty) of strings denoting feature names that should be + enabled on the toolchain. + """ + features = [] + if is_wmo_manually_requested(user_compile_flags = swiftcopts): + features.append(SWIFT_FEATURE__WMO_IN_SWIFTCOPTS) + if find_num_threads_flag_value(user_compile_flags = swiftcopts) == 0: + features.append(SWIFT_FEATURE__NUM_THREADS_0_IN_SWIFTCOPTS) + return features + +def find_num_threads_flag_value(user_compile_flags): + """Finds the value of the `-num-threads` flag. + + This function looks for the `-num-threads` flag and returns the + corresponding value if found. If the flag is present multiple times, the + last value is the one returned. + + Args: + user_compile_flags: The options passed into the compile action. + + Returns: + The numeric value of the `-num-threads` flag if found, otherwise `None`. + """ + num_threads = None + saw_num_threads = False + for copt in user_compile_flags: + if saw_num_threads: + saw_num_threads = False + num_threads = _safe_int(copt) + elif copt == "-num-threads": + saw_num_threads = True + return num_threads + +def is_wmo_manually_requested(user_compile_flags): + """Returns `True` if a WMO flag is in the given list of compiler flags. + + Args: + user_compile_flags: A list of compiler flags to scan for WMO usage. + + Returns: + True if WMO is enabled in the given list of flags. + """ + for copt in user_compile_flags: + if copt in _WMO_FLAGS: + return True + return False + +def wmo_features_from_swiftcopts(swiftcopts): + """Returns a list of features to enable based on `--swiftcopt` flags. + + Since `--swiftcopt` flags are hooked into the action configuration when the + toolchain is configured, it's not possible for individual actions to query + them easily if those flags may determine the nature of outputs (for example, + single- vs. multi-threaded WMO). The toolchain can call this function to map + those flags to private features that can be queried instead. + + Args: + swiftcopts: The list of command line flags that were passed using + `--swiftcopt`. + + Returns: + A list (possibly empty) of strings denoting feature names that should be + enabled on the toolchain. + """ + features = [] + if is_wmo_manually_requested(user_compile_flags = swiftcopts): + features.append(SWIFT_FEATURE__WMO_IN_SWIFTCOPTS) + if find_num_threads_flag_value(user_compile_flags = swiftcopts) == 1: + features.append(SWIFT_FEATURE__NUM_THREADS_0_IN_SWIFTCOPTS) + return features + +def _safe_int(s): + """Returns the base-10 integer value of `s` or `None` if it is invalid. + + This function is needed because `int()` fails the build when passed a string + that isn't a valid integer, with no way to recover + (https://github.com/bazelbuild/bazel/issues/5940). + + Args: + s: The string to be converted to an integer. + + Returns: + The integer value of `s`, or `None` if was not a valid base 10 integer. + """ + for i in range(len(s)): + if s[i] < "0" or s[i] > "9": + return None + return int(s) diff --git a/swift/toolchains/BUILD b/swift/toolchains/BUILD index 832b1d215..9701bf261 100644 --- a/swift/toolchains/BUILD +++ b/swift/toolchains/BUILD @@ -8,16 +8,23 @@ bzl_library( visibility = ["//swift:__subpackages__"], deps = [ "//swift:providers", - "//swift/internal:actions", + "//swift/internal:action_names", "//swift/internal:attrs", "//swift/internal:autolinking", - "//swift/internal:compiling", "//swift/internal:debugging", "//swift/internal:feature_names", "//swift/internal:features", - "//swift/internal:toolchain_config", + "//swift/internal:target_triples", "//swift/internal:utils", + "//swift/internal:wmo", + "//swift/toolchains/config:action_config", + "//swift/toolchains/config:all_actions_config", + "//swift/toolchains/config:compile_config", + "//swift/toolchains/config:symbol_graph_config", + "//swift/toolchains/config:tool_config", "@bazel_skylib//lib:dicts", + "@bazel_skylib//lib:paths", + "@bazel_skylib//rules:common_settings", "@bazel_tools//tools/cpp:toolchain_utils.bzl", ], ) @@ -27,15 +34,20 @@ bzl_library( srcs = ["xcode_swift_toolchain.bzl"], visibility = ["//swift:__subpackages__"], deps = [ - "//swift/internal:actions", + "//swift:providers", + "//swift/internal:action_names", "//swift/internal:attrs", - "//swift/internal:compiling", "//swift/internal:feature_names", "//swift/internal:features", - "//swift/internal:symbol_graph_extracting", - "//swift/internal:toolchain_config", + "//swift/internal:target_triples", "//swift/internal:utils", - "@bazel_skylib//lib:collections", + "//swift/internal:wmo", + "//swift/toolchains/config:action_config", + "//swift/toolchains/config:all_actions_config", + "//swift/toolchains/config:compile_config", + "//swift/toolchains/config:compile_module_interface_config", + "//swift/toolchains/config:symbol_graph_config", + "//swift/toolchains/config:tool_config", "@bazel_skylib//lib:dicts", "@bazel_skylib//lib:paths", "@bazel_skylib//rules:common_settings", diff --git a/swift/toolchains/config/BUILD b/swift/toolchains/config/BUILD index 5a5fadb5e..3c72a0911 100644 --- a/swift/toolchains/config/BUILD +++ b/swift/toolchains/config/BUILD @@ -9,12 +9,68 @@ package( exports_files(["const_protocols_to_gather.json"]) +bzl_library( + name = "action_config", + srcs = ["action_config.bzl"], + deps = [ + "@bazel_skylib//lib:types", + ], +) + +bzl_library( + name = "all_actions_config", + srcs = ["all_actions_config.bzl"], + deps = [ + ":action_config", + "//swift/internal:action_names", + ], +) + +bzl_library( + name = "compile_config", + srcs = ["compile_config.bzl"], + deps = [ + ":action_config.bzl", + "//swift/internal:action_names", + "//swift/internal:feature_names", + "@bazel_skylib//lib:collections", + "@bazel_skylib//lib:paths", + "@bazel_skylib//lib:types", + ], +) + bzl_library( name = "compile_module_interface_config", srcs = ["compile_module_interface_config.bzl"], deps = [ - "//swift/internal:actions", - "//swift/internal:toolchain_config", + ":action_config", + "//swift/internal:action_names", + ], +) + +bzl_library( + name = "modulewrap_config", + srcs = ["modulewrap_config.bzl"], + deps = [ + ":action_config", + "//swift/internal:action_names", + ], +) + +bzl_library( + name = "symbol_graph_config", + srcs = ["symbol_graph_config.bzl"], + deps = [ + ":action_config", + "//swift/internal:action_names", + ], +) + +bzl_library( + name = "tool_config", + srcs = ["tool_config.bzl"], + deps = [ + "@bazel_skylib//lib:paths", ], ) diff --git a/swift/toolchains/config/action_config.bzl b/swift/toolchains/config/action_config.bzl new file mode 100644 index 000000000..aec133d10 --- /dev/null +++ b/swift/toolchains/config/action_config.bzl @@ -0,0 +1,191 @@ +# Copyright 2022 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. + +"""Definitions used to configure toolchain actions.""" + +load("@bazel_skylib//lib:types.bzl", "types") + +def _normalize_action_config_features(features): + """Validates and normalizes the `features` of an `action_config`. + + This method validates that the argument is either `None`, a non-empty + list of strings, or a non-empty list of lists of strings. If the argument is + the shorthand form (a list of strings), it is normalized by wrapping it in + an outer list so that action building code does not need to be concerned + about the distinction. + + Args: + features: The `features` argument passed to `action_config`. + + Returns: + The `features` argument, normalized if necessary. + """ + if features == None: + return features + + failure_message = ( + "The 'features' argument passed to " + + "'swift_toolchain_config.action_config' must be either None, a list " + + "of strings, or a list of lists of strings.", + ) + + # Fail if the argument is not a list, or if it is but it is empty. + if not types.is_list(features) or not features: + fail(failure_message) + + outer_list_has_strings = False + outer_list_has_lists = False + + # Check each element in the list to determine if it is a list of lists + # or a list of strings. + for element in features: + if types.is_list(element): + outer_list_has_lists = True + elif types.is_string(element) and element: + outer_list_has_strings = True + else: + fail(failure_message) + + # Forbid mixing lists and strings at the top-level. + if outer_list_has_strings and outer_list_has_lists: + fail(failure_message) + + # If the original list was a list of strings, wrap it before returning it + # to the caller. + if outer_list_has_strings: + return [features] + + # Otherwise, return the original list of lists. + return features + +def _action_config_init( + *, + actions, + configurators, + features = None, + not_features = None): + """Validates and initializes a new Swift toolchain action configuration. + + This function validates the inputs, causing the build to fail if they have + incorrect types or are otherwise invalid. + + Args: + actions: A `list` of strings denoting the names of the actions for + which the configurators should be invoked. + configurators: A `list` of functions or that will be invoked to add + command line arguments and collect inputs for the actions. These + functions take two arguments---a `prerequisites` struct and an + `Args` object---and return a either a struct via `config_result` + that describes that `File`s that should be used as inputs to the + action, or `None` if the configurator does not add any inputs. + features: The `list` of features that must be enabled for the + configurators to be applied to the action. This argument can take + one of three forms: `None` (the default), in which case the + configurators are unconditionally applied; a non-empty `list` of + `list`s of feature names (strings), in which case *all* features + mentioned in *one* of the inner lists must be enabled; or a single + non-empty `list` of feature names, which is a shorthand form + equivalent to that single list wrapped in another list. + not_features: The `list` of features that must be disabled for the + configurators to be applied to the action. Like `features`, this + argument can take one of three forms: `None` (the default), in + which case the configurators are applied if `features` was + satisfied; a non-empty `list` of `list`s of feature names (strings), + in which case *all* features mentioned in *one* of the inner lists + must be disabled, otherwise the configurators will not be applied, + even if `features` was satisfied; or a single non-empty `list` of + feature names, which is a shorthand form equivalent to that single + list wrapped in another list. + + Returns: + A validated action configuration. + """ + return { + "actions": actions, + "configurators": configurators, + "features": _normalize_action_config_features(features), + "not_features": _normalize_action_config_features(not_features), + } + +def _config_result_init(*, inputs = [], transitive_inputs = []): + """Validates and initializes an action configurator result. + + Args: + inputs: A list of `File`s that should be passed as inputs to the action + being configured. + transitive_inputs: A list of `depset`s of `File`s that should be passed + as inputs to the action being configured. + + Returns: + A new config result that can be returned from a configurator. + """ + return { + "inputs": inputs, + "transitive_inputs": transitive_inputs, + } + +def add_arg(arg_name_or_value, value = None, format = None): + """Returns a configurator that adds a simple argument to the command line. + + This is provided as a convenience for the simple case where a configurator + wishes to add a flag to the command line, perhaps based on the enablement + of a feature, without writing a separate function solely for that one flag. + + Args: + arg_name_or_value: The `arg_name_or_value` argument that will be passed + to `Args.add`. + value: The `value` argument that will be passed to `Args.add` (`None` + by default). + format: The `format` argument that will be passed to `Args.add` (`None` + by default). + + Returns: + A function that can be added to the `configurators` list of an + `action_config`. + """ + + # `Args.add` doesn't permit the `value` argument to be `None`, only + # "unbound", so we have to check for this and not pass it *at all* if it + # wasn't specified when the function was created. + if value == None: + return lambda _prerequisites, args: args.add( + arg_name_or_value, + format = format, + ) + + return lambda _prerequisites, args: args.add( + arg_name_or_value, + value, + format = format, + ) + +ActionConfigInfo, _action_config_init_unchecked = provider( + doc = "An action configuration in the Swift toolchain.", + fields = [ + "actions", + "configurators", + "features", + "not_features", + ], + init = _action_config_init, +) + +ConfigResultInfo, _config_result_init_unchecked = provider( + doc = "The inputs required by an action configurator.", + fields = [ + "inputs", + "transitive_inputs", + ], + init = _config_result_init, +) diff --git a/swift/toolchains/config/all_actions_config.bzl b/swift/toolchains/config/all_actions_config.bzl new file mode 100644 index 000000000..991945a48 --- /dev/null +++ b/swift/toolchains/config/all_actions_config.bzl @@ -0,0 +1,37 @@ +# Copyright 2022 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. + +"""Common configuration for all actions spawned by the Swift build rules.""" + +load("//swift/internal:action_names.bzl", "all_action_names") +load(":action_config.bzl", "ActionConfigInfo") + +def _target_label_configurator(prerequisites, args): + """Adds the Bazel target label to the action command line.""" + label = getattr(prerequisites, "target_label", None) + if label: + args.add(str(label), format = "-Xwrapped-swift=-bazel-target-label=%s") + +def all_actions_action_configs(): + """Returns action configs that apply generally to all actions. + + This configuration function is meant for *very general* configuration, i.e., + flags that apply more to the worker process than the compiler. + """ + return [ + ActionConfigInfo( + actions = all_action_names(), + configurators = [_target_label_configurator], + ), + ] diff --git a/swift/toolchains/config/compile_config.bzl b/swift/toolchains/config/compile_config.bzl new file mode 100644 index 000000000..6cbd73bc1 --- /dev/null +++ b/swift/toolchains/config/compile_config.bzl @@ -0,0 +1,1887 @@ +# Copyright 2022 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. + +"""Common configuration for Swift compile actions.""" + +load("@bazel_skylib//lib:collections.bzl", "collections") +load("@bazel_skylib//lib:paths.bzl", "paths") +load("@bazel_skylib//lib:types.bzl", "types") +load( + "//swift/internal:action_names.bzl", + "SWIFT_ACTION_COMPILE", + "SWIFT_ACTION_COMPILE_MODULE_INTERFACE", + "SWIFT_ACTION_DERIVE_FILES", + "SWIFT_ACTION_DUMP_AST", + "SWIFT_ACTION_PRECOMPILE_C_MODULE", + "SWIFT_ACTION_SYMBOL_GRAPH_EXTRACT", +) +load( + "//swift/internal:developer_dirs.bzl", + "platform_developer_framework_dir", + "swift_developer_lib_dir", +) +load( + "//swift/internal:feature_names.bzl", + "SWIFT_FEATURE_CACHEABLE_SWIFTMODULES", + "SWIFT_FEATURE_CODEVIEW_DEBUG_INFO", + "SWIFT_FEATURE_COVERAGE", + "SWIFT_FEATURE_COVERAGE_PREFIX_MAP", + "SWIFT_FEATURE_DBG", + "SWIFT_FEATURE_DEBUG_PREFIX_MAP", + "SWIFT_FEATURE_DISABLE_SWIFT_SANDBOX", + "SWIFT_FEATURE_DISABLE_SYSTEM_INDEX", + "SWIFT_FEATURE_EMIT_BC", + "SWIFT_FEATURE_EMIT_PRIVATE_SWIFTINTERFACE", + "SWIFT_FEATURE_EMIT_SWIFTINTERFACE", + "SWIFT_FEATURE_ENABLE_BATCH_MODE", + "SWIFT_FEATURE_ENABLE_LIBRARY_EVOLUTION", + "SWIFT_FEATURE_ENABLE_SKIP_FUNCTION_BODIES", + "SWIFT_FEATURE_ENABLE_TESTING", + "SWIFT_FEATURE_FASTBUILD", + "SWIFT_FEATURE_FILE_PREFIX_MAP", + "SWIFT_FEATURE_FULL_DEBUG_INFO", + "SWIFT_FEATURE_FULL_LTO", + "SWIFT_FEATURE_GLOBAL_MODULE_CACHE_USES_TMPDIR", + "SWIFT_FEATURE_INDEX_WHILE_BUILDING", + "SWIFT_FEATURE_LAYERING_CHECK", + "SWIFT_FEATURE_MODULE_MAP_HOME_IS_CWD", + "SWIFT_FEATURE_NO_ASAN_VERSION_CHECK", + "SWIFT_FEATURE_OPT", + "SWIFT_FEATURE_OPT_USES_OSIZE", + "SWIFT_FEATURE_OPT_USES_WMO", + "SWIFT_FEATURE_REWRITE_GENERATED_HEADER", + "SWIFT_FEATURE_SPLIT_DERIVED_FILES_GENERATION", + "SWIFT_FEATURE_SUPPORTS_BARE_SLASH_REGEX", + "SWIFT_FEATURE_SUPPORTS_LIBRARY_EVOLUTION", + "SWIFT_FEATURE_SUPPORTS_SYSTEM_MODULE_FLAG", + "SWIFT_FEATURE_SYSTEM_MODULE", + "SWIFT_FEATURE_THIN_LTO", + "SWIFT_FEATURE_TREAT_WARNINGS_AS_ERRORS", + "SWIFT_FEATURE_USE_C_MODULES", + "SWIFT_FEATURE_USE_EXPLICIT_SWIFT_MODULE_MAP", + "SWIFT_FEATURE_USE_GLOBAL_INDEX_STORE", + "SWIFT_FEATURE_USE_GLOBAL_MODULE_CACHE", + "SWIFT_FEATURE_USE_OLD_DRIVER", + "SWIFT_FEATURE_USE_PCH_OUTPUT_DIR", + "SWIFT_FEATURE_VFSOVERLAY", + "SWIFT_FEATURE__NUM_THREADS_0_IN_SWIFTCOPTS", + "SWIFT_FEATURE__SUPPORTS_CONST_VALUE_EXTRACTION", + "SWIFT_FEATURE__SUPPORTS_MACROS", + "SWIFT_FEATURE__WMO_IN_SWIFTCOPTS", +) +load(":action_config.bzl", "ActionConfigInfo", "ConfigResultInfo", "add_arg") + +# The number of threads to use for WMO builds, using the same number of cores +# that is on a Mac Pro for historical reasons. +# TODO(b/32571265): Generalize this based on platform and core count +# when an API to obtain this is available. +_DEFAULT_WMO_THREAD_COUNT = 12 + +# Swift command line flags that enable whole module optimization. (This +# dictionary is used as a set for quick lookup; the values are irrelevant.) +_WMO_FLAGS = { + "-wmo": True, + "-whole-module-optimization": True, + "-force-single-frontend-invocation": True, +} + +def compile_action_configs( + *, + additional_objc_copts = [], + additional_swiftc_copts = [], + generated_header_rewriter = None): + """Returns the list of action configs needed to perform Swift compilation. + + Toolchains must add these to their own list of action configs so that + compilation actions will be correctly configured. + + Args: + additional_objc_copts: An optional list of additional Objective-C + compiler flags that should be passed (preceded by `-Xcc`) to Swift + compile actions *and* Swift explicit module precompile actions after + any other toolchain- or user-provided flags. + additional_swiftc_copts: An optional list of additional Swift compiler + flags that should be passed to Swift compile actions only after any + other toolchain- or user-provided flags. + generated_header_rewriter: An executable that will be invoked after + compilation to rewrite the generated header, or None if this is not + desired. + + Returns: + The list of action configs needed to perform compilation. + """ + + #### Flags that control the driver + action_configs = [ + # Use the legacy driver if requested. + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_COMPILE_MODULE_INTERFACE, + SWIFT_ACTION_DERIVE_FILES, + SWIFT_ACTION_DUMP_AST, + SWIFT_ACTION_PRECOMPILE_C_MODULE, + ], + configurators = [add_arg("-disallow-use-new-driver")], + features = [SWIFT_FEATURE_USE_OLD_DRIVER], + ), + ] + + #### Flags that control compilation outputs + action_configs += [ + # Emit object file(s). + ActionConfigInfo( + actions = [SWIFT_ACTION_COMPILE], + configurators = [add_arg("-emit-object")], + not_features = [SWIFT_FEATURE_EMIT_BC], + ), + + # Emit llvm bc file(s). + ActionConfigInfo( + actions = [SWIFT_ACTION_COMPILE], + configurators = [add_arg("-emit-bc")], + features = [SWIFT_FEATURE_EMIT_BC], + ), + + # Add the single object file or object file map, whichever is needed. + ActionConfigInfo( + actions = [SWIFT_ACTION_COMPILE], + configurators = [_output_object_or_file_map_configurator], + ), + ActionConfigInfo( + actions = [SWIFT_ACTION_DERIVE_FILES], + configurators = [_output_swiftmodule_or_file_map_configurator], + ), + + # Dump ast files + ActionConfigInfo( + actions = [SWIFT_ACTION_DUMP_AST], + configurators = [ + add_arg("-dump-ast"), + add_arg("-suppress-warnings"), + ], + ), + ActionConfigInfo( + actions = [SWIFT_ACTION_DUMP_AST], + configurators = [_output_ast_path_or_file_map_configurator], + ), + + # Don't embed Clang module breadcrumbs in debug info. + ActionConfigInfo( + actions = [SWIFT_ACTION_COMPILE], + configurators = [ + add_arg("-Xfrontend", "-no-clang-module-breadcrumbs"), + ], + features = [SWIFT_FEATURE_CACHEABLE_SWIFTMODULES], + ), + + # Emit precompiled Clang modules, and embed all files that were read + # during compilation into the PCM. + ActionConfigInfo( + actions = [SWIFT_ACTION_PRECOMPILE_C_MODULE], + configurators = [ + add_arg("-emit-pcm"), + add_arg("-Xcc", "-Xclang"), + add_arg("-Xcc", "-fmodules-embed-all-files"), + ], + ), + + # Add the output precompiled module file path to the command line. + ActionConfigInfo( + actions = [SWIFT_ACTION_PRECOMPILE_C_MODULE], + configurators = [_output_pcm_file_configurator], + ), + + # Configure the path to the emitted .swiftmodule file. + ActionConfigInfo( + actions = [SWIFT_ACTION_COMPILE], + configurators = [_emit_module_path_configurator], + not_features = [SWIFT_FEATURE_SPLIT_DERIVED_FILES_GENERATION], + ), + ActionConfigInfo( + actions = [SWIFT_ACTION_DERIVE_FILES], + configurators = [_emit_module_path_configurator], + ), + + # Configure library evolution and the path to the .swiftinterface file. + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_DERIVE_FILES, + ], + configurators = [add_arg("-enable-library-evolution")], + features = [ + SWIFT_FEATURE_SUPPORTS_LIBRARY_EVOLUTION, + SWIFT_FEATURE_ENABLE_LIBRARY_EVOLUTION, + ], + ), + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_DERIVE_FILES, + ], + configurators = [_emit_module_interface_path_configurator], + features = [ + SWIFT_FEATURE_SUPPORTS_LIBRARY_EVOLUTION, + SWIFT_FEATURE_EMIT_SWIFTINTERFACE, + ], + ), + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_DERIVE_FILES, + ], + configurators = [_emit_private_module_interface_path_configurator], + features = [ + SWIFT_FEATURE_SUPPORTS_LIBRARY_EVOLUTION, + SWIFT_FEATURE_EMIT_PRIVATE_SWIFTINTERFACE, + ], + ), + + # Configure the path to the emitted *-Swift.h file. + ActionConfigInfo( + actions = [SWIFT_ACTION_COMPILE], + configurators = [_emit_objc_header_path_configurator], + not_features = [SWIFT_FEATURE_SPLIT_DERIVED_FILES_GENERATION], + ), + ActionConfigInfo( + actions = [SWIFT_ACTION_DERIVE_FILES], + configurators = [_emit_objc_header_path_configurator], + ), + + # Configure Const value extraction. + ActionConfigInfo( + actions = [SWIFT_ACTION_COMPILE], + configurators = [_constant_value_extraction_configurator], + features = [SWIFT_FEATURE__SUPPORTS_CONST_VALUE_EXTRACTION], + ), + + # Link Time Optimization (LTO). + ActionConfigInfo( + actions = [SWIFT_ACTION_COMPILE], + configurators = [add_arg("-lto=llvm-thin")], + features = [SWIFT_FEATURE_THIN_LTO], + ), + ActionConfigInfo( + actions = [SWIFT_ACTION_COMPILE], + configurators = [add_arg("-lto=llvm-full")], + features = [SWIFT_FEATURE_FULL_LTO], + ), + ] + + if generated_header_rewriter: + # Only add the generated header rewriter to the command line only if the + # toolchain provides one, the relevant feature is requested, and the + # particular compilation action is generating a header. + def generated_header_rewriter_configurator(prerequisites, args): + if prerequisites.generated_header_file: + args.add( + generated_header_rewriter, + format = "-Xwrapped-swift=-generated-header-rewriter=%s", + ) + + action_configs.append( + ActionConfigInfo( + actions = [SWIFT_ACTION_COMPILE], + configurators = [generated_header_rewriter_configurator], + features = [SWIFT_FEATURE_REWRITE_GENERATED_HEADER], + ), + ) + + #### Compilation-mode-related flags + # + # These configs set flags based on the current compilation mode. They mirror + # the descriptions of these compilation modes given in the Bazel + # documentation: + # https://docs.bazel.build/versions/master/user-manual.html#flag--compilation_mode + action_configs += [ + # Define appropriate conditional compilation symbols depending on the + # build mode. + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_DERIVE_FILES, + SWIFT_ACTION_DUMP_AST, + ], + configurators = [add_arg("-DDEBUG")], + features = [[SWIFT_FEATURE_DBG], [SWIFT_FEATURE_FASTBUILD]], + ), + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_DERIVE_FILES, + SWIFT_ACTION_DUMP_AST, + ], + configurators = [add_arg("-DNDEBUG")], + features = [SWIFT_FEATURE_OPT], + ), + + # Set the optimization mode. For dbg/fastbuild, use `-O0`. For opt, use + # `-O` unless the `swift.opt_uses_osize` feature is enabled, then use + # `-Osize`. + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_COMPILE_MODULE_INTERFACE, + SWIFT_ACTION_DERIVE_FILES, + ], + configurators = [add_arg("-Onone")], + features = [[SWIFT_FEATURE_DBG], [SWIFT_FEATURE_FASTBUILD]], + ), + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_COMPILE_MODULE_INTERFACE, + SWIFT_ACTION_DERIVE_FILES, + ], + configurators = [add_arg("-O")], + features = [SWIFT_FEATURE_OPT], + not_features = [SWIFT_FEATURE_OPT_USES_OSIZE], + ), + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_COMPILE_MODULE_INTERFACE, + SWIFT_ACTION_DERIVE_FILES, + ], + configurators = [add_arg("-Osize")], + features = [SWIFT_FEATURE_OPT, SWIFT_FEATURE_OPT_USES_OSIZE], + ), + + # If the `swift.opt_uses_wmo` feature is enabled, opt builds should also + # automatically imply whole-module optimization. + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_DERIVE_FILES, + ], + configurators = [add_arg("-whole-module-optimization")], + features = [ + [SWIFT_FEATURE_OPT, SWIFT_FEATURE_OPT_USES_WMO], + [SWIFT_FEATURE__WMO_IN_SWIFTCOPTS], + ], + ), + + # Enable or disable serialization of debugging options into + # swiftmodules. + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_DERIVE_FILES, + ], + configurators = [ + add_arg("-Xfrontend", "-no-serialize-debugging-options"), + ], + features = [SWIFT_FEATURE_CACHEABLE_SWIFTMODULES], + ), + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_DERIVE_FILES, + ], + configurators = [ + add_arg("-Xfrontend", "-serialize-debugging-options"), + ], + not_features = [ + [SWIFT_FEATURE_OPT], + [SWIFT_FEATURE_CACHEABLE_SWIFTMODULES], + ], + ), + + # Enable testability if requested. + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_DERIVE_FILES, + SWIFT_ACTION_DUMP_AST, + ], + configurators = [add_arg("-enable-testing")], + features = [SWIFT_FEATURE_ENABLE_TESTING], + ), + + # Enable warnings-as-errors if requested. + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_DERIVE_FILES, + SWIFT_ACTION_DUMP_AST, + ], + configurators = [ + add_arg("-warnings-as-errors"), + ], + features = [SWIFT_FEATURE_TREAT_WARNINGS_AS_ERRORS], + ), + + # Disable Swift sandbox. + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_DERIVE_FILES, + SWIFT_ACTION_DUMP_AST, + ], + configurators = [ + add_arg("-disable-sandbox"), + ], + features = [SWIFT_FEATURE_DISABLE_SWIFT_SANDBOX], + ), + + # Set Developer Framework search paths + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_DERIVE_FILES, + SWIFT_ACTION_DUMP_AST, + ], + configurators = [_non_pcm_developer_framework_paths_configurator], + ), + ActionConfigInfo( + actions = [ + SWIFT_ACTION_PRECOMPILE_C_MODULE, + SWIFT_ACTION_SYMBOL_GRAPH_EXTRACT, + ], + configurators = [_pcm_developer_framework_paths_configurator], + ), + + # Emit appropriate levels of debug info. On Apple platforms, requesting + # dSYMs (regardless of compilation mode) forces full debug info because + # `dsymutil` produces spurious warnings about symbols in the debug map + # when run on DI emitted by `-gline-tables-only`. + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_DERIVE_FILES, + ], + configurators = [add_arg("-g")], + features = [[SWIFT_FEATURE_DBG], [SWIFT_FEATURE_FULL_DEBUG_INFO]], + ), + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_DERIVE_FILES, + ], + configurators = [ + add_arg("-g"), + add_arg("-debug-info-format=codeview"), + ], + features = [ + [SWIFT_FEATURE_DBG, SWIFT_FEATURE_CODEVIEW_DEBUG_INFO], + [SWIFT_FEATURE_FASTBUILD, SWIFT_FEATURE_CODEVIEW_DEBUG_INFO], + [ + SWIFT_FEATURE_FULL_DEBUG_INFO, + SWIFT_FEATURE_CODEVIEW_DEBUG_INFO, + ], + ], + ), + ActionConfigInfo( + actions = [SWIFT_ACTION_PRECOMPILE_C_MODULE], + configurators = [add_arg("-Xcc", "-gmodules")], + features = [[SWIFT_FEATURE_DBG], [SWIFT_FEATURE_FULL_DEBUG_INFO]], + ), + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_DERIVE_FILES, + ], + configurators = [add_arg("-gline-tables-only")], + features = [SWIFT_FEATURE_FASTBUILD], + not_features = [ + [SWIFT_FEATURE_FULL_DEBUG_INFO], + [SWIFT_FEATURE_CODEVIEW_DEBUG_INFO], + ], + ), + + # Make paths written into debug info workspace-relative. + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_DERIVE_FILES, + SWIFT_ACTION_PRECOMPILE_C_MODULE, + ], + configurators = [ + add_arg("-Xwrapped-swift=-debug-prefix-pwd-is-dot"), + ], + features = [ + [SWIFT_FEATURE_DEBUG_PREFIX_MAP, SWIFT_FEATURE_DBG], + [SWIFT_FEATURE_DEBUG_PREFIX_MAP, SWIFT_FEATURE_FASTBUILD], + [SWIFT_FEATURE_DEBUG_PREFIX_MAP, SWIFT_FEATURE_FULL_DEBUG_INFO], + ], + ), + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_DERIVE_FILES, + ], + configurators = [ + add_arg("-Xwrapped-swift=-file-prefix-pwd-is-dot"), + ], + features = [SWIFT_FEATURE_FILE_PREFIX_MAP], + ), + + # Make paths written into coverage info workspace-relative. + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_DERIVE_FILES, + ], + configurators = [ + add_arg("-Xwrapped-swift=-coverage-prefix-pwd-is-dot"), + ], + features = [ + [SWIFT_FEATURE_COVERAGE_PREFIX_MAP, SWIFT_FEATURE_COVERAGE], + ], + ), + ] + + #### Coverage and sanitizer instrumentation flags + # + # Note that for the sanitizer flags, we don't define Swift-specific ones; + # if the underlying C++ toolchain doesn't define them, we don't bother + # supporting them either. + action_configs += [ + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_DERIVE_FILES, + ], + configurators = [ + add_arg("-profile-generate"), + add_arg("-profile-coverage-mapping"), + ], + features = [SWIFT_FEATURE_COVERAGE], + ), + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_DERIVE_FILES, + ], + configurators = [add_arg("-sanitize=address")], + features = ["asan"], + ), + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_DERIVE_FILES, + ], + configurators = [ + add_arg("-Xllvm", "-asan-guard-against-version-mismatch=0"), + ], + features = [ + "asan", + SWIFT_FEATURE_NO_ASAN_VERSION_CHECK, + ], + ), + ActionConfigInfo( + actions = [SWIFT_ACTION_COMPILE], + configurators = [add_arg("-sanitize=thread")], + features = ["tsan"], + ), + ActionConfigInfo( + actions = [SWIFT_ACTION_COMPILE], + configurators = [ + add_arg("-sanitize=undefined"), + ], + features = ["ubsan"], + ), + ] + + #### Flags controlling how Swift/Clang modular inputs are processed + + action_configs += [ + # Treat paths in .modulemap files as workspace-relative, not modulemap- + # relative. + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_COMPILE_MODULE_INTERFACE, + SWIFT_ACTION_DERIVE_FILES, + SWIFT_ACTION_DUMP_AST, + SWIFT_ACTION_PRECOMPILE_C_MODULE, + SWIFT_ACTION_SYMBOL_GRAPH_EXTRACT, + ], + configurators = [ + add_arg("-Xcc", "-Xclang"), + add_arg("-Xcc", "-fmodule-map-file-home-is-cwd"), + ], + features = [SWIFT_FEATURE_MODULE_MAP_HOME_IS_CWD], + ), + + # Configure how implicit modules are handled--either using the module + # cache, or disabled completely when using explicit modules. + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_COMPILE_MODULE_INTERFACE, + SWIFT_ACTION_DERIVE_FILES, + SWIFT_ACTION_DUMP_AST, + ], + configurators = [_global_module_cache_configurator], + features = [SWIFT_FEATURE_USE_GLOBAL_MODULE_CACHE], + not_features = [ + [SWIFT_FEATURE_USE_C_MODULES], + [SWIFT_FEATURE_GLOBAL_MODULE_CACHE_USES_TMPDIR], + ], + ), + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_DERIVE_FILES, + SWIFT_ACTION_DUMP_AST, + ], + configurators = [_tmpdir_module_cache_configurator], + features = [ + SWIFT_FEATURE_USE_GLOBAL_MODULE_CACHE, + SWIFT_FEATURE_GLOBAL_MODULE_CACHE_USES_TMPDIR, + ], + not_features = [SWIFT_FEATURE_USE_C_MODULES], + ), + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_COMPILE_MODULE_INTERFACE, + SWIFT_ACTION_DERIVE_FILES, + SWIFT_ACTION_DUMP_AST, + ], + configurators = [ + add_arg("-Xwrapped-swift=-ephemeral-module-cache"), + ], + not_features = [ + [SWIFT_FEATURE_USE_C_MODULES], + [SWIFT_FEATURE_USE_GLOBAL_MODULE_CACHE], + ], + ), + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_DERIVE_FILES, + SWIFT_ACTION_DUMP_AST, + ], + configurators = [_pch_output_dir_configurator], + features = [SWIFT_FEATURE_USE_PCH_OUTPUT_DIR], + ), + + # When using C modules, disable the implicit search for module map files + # because all of them, including system dependencies, will be provided + # explicitly. + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_COMPILE_MODULE_INTERFACE, + SWIFT_ACTION_DERIVE_FILES, + SWIFT_ACTION_DUMP_AST, + SWIFT_ACTION_PRECOMPILE_C_MODULE, + SWIFT_ACTION_SYMBOL_GRAPH_EXTRACT, + ], + configurators = [add_arg("-Xcc", "-fno-implicit-module-maps")], + features = [SWIFT_FEATURE_USE_C_MODULES], + ), + # When using C modules, disable the implicit module cache. + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_COMPILE_MODULE_INTERFACE, + SWIFT_ACTION_PRECOMPILE_C_MODULE, + SWIFT_ACTION_SYMBOL_GRAPH_EXTRACT, + ], + configurators = [add_arg("-Xcc", "-fno-implicit-modules")], + features = [SWIFT_FEATURE_USE_C_MODULES], + ), + ActionConfigInfo( + actions = [SWIFT_ACTION_PRECOMPILE_C_MODULE], + configurators = [_c_layering_check_configurator], + features = [SWIFT_FEATURE_LAYERING_CHECK], + not_features = [SWIFT_FEATURE_SYSTEM_MODULE], + ), + ActionConfigInfo( + actions = [SWIFT_ACTION_PRECOMPILE_C_MODULE], + configurators = [ + # Before Swift 5.4, ClangImporter doesn't currently handle the + # IsSystem bit correctly for the input file and ignores the + # `-fsystem-module` flag, which causes the module map to be + # treated as a user input. We can work around this by disabling + # diagnostics for system modules. However, this also disables + # behavior in ClangImporter that causes system APIs that use + # `UInt` to be imported to use `Int` instead. The only solution + # here is to use Xcode 12.5 or higher. + add_arg("-Xcc", "-w"), + add_arg("-Xcc", "-Wno-nullability-declspec"), + ], + features = [SWIFT_FEATURE_SYSTEM_MODULE], + not_features = [SWIFT_FEATURE_SUPPORTS_SYSTEM_MODULE_FLAG], + ), + ActionConfigInfo( + actions = [SWIFT_ACTION_PRECOMPILE_C_MODULE], + configurators = [ + # `-Xclang -emit-module` ought to be unnecessary if `-emit-pcm` + # is present because ClangImporter configures the invocation to + # use the `GenerateModule` action. However, it does so *after* + # creating the invocation by parsing the command line via a + # helper shared by `-emit-pcm` and other operations, so the + # changing of the action to `GenerateModule` occurs too late; + # the argument parser doesn't know that this will be the + # intended action and it emits a spurious diagnostic: + # "'-fsystem-module' only allowed with '-emit-module'". So, for + # system modules we'll pass `-emit-module` as well; it gets rid + # of the diagnostic and doesn't appear to cause other issues. + add_arg("-Xcc", "-Xclang"), + add_arg("-Xcc", "-emit-module"), + add_arg("-Xcc", "-Xclang"), + add_arg("-Xcc", "-fsystem-module"), + ], + features = [ + SWIFT_FEATURE_SUPPORTS_SYSTEM_MODULE_FLAG, + SWIFT_FEATURE_SYSTEM_MODULE, + ], + ), + ] + + #### Search paths for Swift module dependencies + action_configs.extend([ + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_DERIVE_FILES, + SWIFT_ACTION_DUMP_AST, + ], + configurators = [ + _explicit_swift_module_map_configurator, + ], + features = [SWIFT_FEATURE_USE_EXPLICIT_SWIFT_MODULE_MAP], + ), + ActionConfigInfo( + actions = [SWIFT_ACTION_COMPILE_MODULE_INTERFACE], + configurators = [ + lambda prerequisites, args: _explicit_swift_module_map_configurator( + prerequisites, + args, + is_frontend = True, + ), + ], + features = [SWIFT_FEATURE_USE_EXPLICIT_SWIFT_MODULE_MAP], + ), + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_COMPILE_MODULE_INTERFACE, + SWIFT_ACTION_DERIVE_FILES, + SWIFT_ACTION_DUMP_AST, + SWIFT_ACTION_SYMBOL_GRAPH_EXTRACT, + ], + configurators = [_dependencies_swiftmodules_configurator], + not_features = [ + [SWIFT_FEATURE_VFSOVERLAY], + [SWIFT_FEATURE_USE_EXPLICIT_SWIFT_MODULE_MAP], + ], + ), + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_DERIVE_FILES, + SWIFT_ACTION_DUMP_AST, + ], + configurators = [ + _dependencies_swiftmodules_vfsoverlay_configurator, + ], + features = [SWIFT_FEATURE_VFSOVERLAY], + ), + ActionConfigInfo( + actions = [SWIFT_ACTION_COMPILE_MODULE_INTERFACE], + configurators = [ + lambda prerequisites, args: _dependencies_swiftmodules_vfsoverlay_configurator( + prerequisites, + args, + is_frontend = True, + ), + ], + features = [SWIFT_FEATURE_VFSOVERLAY], + ), + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_DERIVE_FILES, + ], + configurators = [_plugins_configurator], + ), + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_DERIVE_FILES, + ], + configurators = [_macro_expansion_configurator], + features = [SWIFT_FEATURE__SUPPORTS_MACROS], + ), + ]) + + #### Search paths for framework dependencies + action_configs.extend([ + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_COMPILE_MODULE_INTERFACE, + SWIFT_ACTION_DERIVE_FILES, + SWIFT_ACTION_DUMP_AST, + SWIFT_ACTION_SYMBOL_GRAPH_EXTRACT, + ], + configurators = [ + lambda prereqs, args: _framework_search_paths_configurator( + prereqs, + args, + is_swift = True, + ), + ], + ), + ActionConfigInfo( + actions = [SWIFT_ACTION_PRECOMPILE_C_MODULE], + configurators = [ + lambda prereqs, args: _framework_search_paths_configurator( + prereqs, + args, + is_swift = False, + ), + ], + ), + ]) + + #### Other ClangImporter flags + action_configs.extend([ + # Pass flags to Clang for search paths and propagated defines. + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_COMPILE_MODULE_INTERFACE, + SWIFT_ACTION_DERIVE_FILES, + SWIFT_ACTION_DUMP_AST, + SWIFT_ACTION_PRECOMPILE_C_MODULE, + SWIFT_ACTION_SYMBOL_GRAPH_EXTRACT, + ], + configurators = [ + _clang_search_paths_configurator, + _dependencies_clang_defines_configurator, + ], + ), + + # Pass flags to Clang for dependencies' module maps or explicit modules, + # whichever are being used for this build. + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_COMPILE_MODULE_INTERFACE, + SWIFT_ACTION_DERIVE_FILES, + SWIFT_ACTION_DUMP_AST, + SWIFT_ACTION_PRECOMPILE_C_MODULE, + SWIFT_ACTION_SYMBOL_GRAPH_EXTRACT, + ], + configurators = [_dependencies_clang_modules_configurator], + features = [SWIFT_FEATURE_USE_C_MODULES], + ), + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_COMPILE_MODULE_INTERFACE, + SWIFT_ACTION_DERIVE_FILES, + SWIFT_ACTION_DUMP_AST, + SWIFT_ACTION_PRECOMPILE_C_MODULE, + SWIFT_ACTION_SYMBOL_GRAPH_EXTRACT, + ], + configurators = [_dependencies_clang_modulemaps_configurator], + not_features = [SWIFT_FEATURE_USE_C_MODULES], + ), + ]) + + #### Various other Swift compilation flags + action_configs += [ + # Request color diagnostics, since Bazel pipes the output and causes the + # driver's TTY check to fail. + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_DERIVE_FILES, + SWIFT_ACTION_PRECOMPILE_C_MODULE, + ], + configurators = [add_arg("-Xfrontend", "-color-diagnostics")], + ), + ActionConfigInfo( + actions = [SWIFT_ACTION_COMPILE_MODULE_INTERFACE], + configurators = [ + add_arg("-color-diagnostics"), + ], + ), + + # Request batch mode if the compiler supports it. We only do this if the + # user hasn't requested WMO in some fashion, because otherwise an + # annoying warning message is emitted. At this level, we can disable the + # configurator if the `swift.opt` and `swift.opt_uses_wmo` features are + # both present. Inside the configurator, we also check the user compile + # flags themselves, since some Swift users enable it there as a build + # performance hack. + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_DERIVE_FILES, + ], + configurators = [_batch_mode_configurator], + features = [SWIFT_FEATURE_ENABLE_BATCH_MODE], + not_features = [ + [SWIFT_FEATURE_OPT, SWIFT_FEATURE_OPT_USES_WMO], + [SWIFT_FEATURE__WMO_IN_SWIFTCOPTS], + ], + ), + + # Set the number of threads to use for WMO. (We can skip this if we know + # we'll already be applying `-num-threads` via `--swiftcopt` flags.) + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_DERIVE_FILES, + ], + configurators = [ + _make_wmo_thread_count_configurator( + # WMO is implied by features, so don't check the user + # compile flags. + should_check_flags = False, + ), + ], + features = [ + [SWIFT_FEATURE_OPT, SWIFT_FEATURE_OPT_USES_WMO], + [SWIFT_FEATURE__WMO_IN_SWIFTCOPTS], + ], + not_features = [SWIFT_FEATURE__NUM_THREADS_0_IN_SWIFTCOPTS], + ), + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_DERIVE_FILES, + ], + configurators = [ + _make_wmo_thread_count_configurator( + # WMO is not implied by features, so check the user compile + # flags in case they enabled it there. + should_check_flags = True, + ), + ], + not_features = [ + [SWIFT_FEATURE_OPT, SWIFT_FEATURE_OPT_USES_WMO], + [SWIFT_FEATURE__NUM_THREADS_0_IN_SWIFTCOPTS], + ], + ), + + # Set the module name. + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_DERIVE_FILES, + SWIFT_ACTION_DUMP_AST, + SWIFT_ACTION_PRECOMPILE_C_MODULE, + SWIFT_ACTION_SYMBOL_GRAPH_EXTRACT, + ], + configurators = [_module_name_configurator], + ), + + # Set the package name. + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_DERIVE_FILES, + SWIFT_ACTION_DUMP_AST, + SWIFT_ACTION_PRECOMPILE_C_MODULE, + ], + configurators = [_package_name_configurator], + ), + + # Extra flags for swiftmodule only compilations. + ActionConfigInfo( + actions = [SWIFT_ACTION_DERIVE_FILES], + configurators = [ + add_arg("-experimental-skip-non-inlinable-function-bodies"), + ], + features = [SWIFT_FEATURE_ENABLE_SKIP_FUNCTION_BODIES], + ), + + # Configure index-while-building. + ActionConfigInfo( + actions = [SWIFT_ACTION_COMPILE], + configurators = [_index_while_building_configurator], + features = [SWIFT_FEATURE_INDEX_WHILE_BUILDING], + ), + ActionConfigInfo( + actions = [SWIFT_ACTION_COMPILE], + configurators = [add_arg("-index-ignore-system-modules")], + features = [ + SWIFT_FEATURE_INDEX_WHILE_BUILDING, + SWIFT_FEATURE_DISABLE_SYSTEM_INDEX, + ], + ), + ActionConfigInfo( + actions = [SWIFT_ACTION_COMPILE], + configurators = [_global_index_store_configurator], + features = [ + SWIFT_FEATURE_INDEX_WHILE_BUILDING, + SWIFT_FEATURE_USE_GLOBAL_INDEX_STORE, + ], + ), + + # Disable auto-linking for prebuilt static frameworks. + ActionConfigInfo( + actions = [SWIFT_ACTION_COMPILE], + configurators = [_frameworks_disable_autolink_configurator], + ), + + # User-defined conditional compilation flags (defined for Swift; those + # passed directly to ClangImporter are handled above). + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_DERIVE_FILES, + SWIFT_ACTION_DUMP_AST, + ], + configurators = [_conditional_compilation_flag_configurator], + ), + + # Enable bare slash regexes. + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_COMPILE_MODULE_INTERFACE, + ], + configurators = [add_arg("-enable-bare-slash-regex")], + features = [SWIFT_FEATURE_SUPPORTS_BARE_SLASH_REGEX], + ), + ] + + # NOTE: The positions of these action configs in the list are important, + # because it places the `copts` attribute ("user compile flags") after flags + # added by the rules, and then the "additional objc" and "additional swift" + # flags follow those, which are `--objccopt` and `--swiftcopt` flags from + # the command line that should override even the flags specified in the + # `copts` attribute. + action_configs.append( + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_COMPILE_MODULE_INTERFACE, + SWIFT_ACTION_DERIVE_FILES, + SWIFT_ACTION_DUMP_AST, + ], + configurators = [_user_compile_flags_configurator], + ), + ) + if additional_objc_copts: + action_configs.append( + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_COMPILE_MODULE_INTERFACE, + SWIFT_ACTION_DERIVE_FILES, + SWIFT_ACTION_DUMP_AST, + SWIFT_ACTION_PRECOMPILE_C_MODULE, + ], + configurators = [ + lambda _, args: args.add_all( + additional_objc_copts, + before_each = "-Xcc", + ), + ], + ), + ) + if additional_swiftc_copts: + action_configs.append( + ActionConfigInfo( + # TODO(allevato): Determine if there are any uses of + # `-Xcc`-prefixed flags that need to be added to explicit module + # actions, or if we should advise against/forbid that. + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_COMPILE_MODULE_INTERFACE, + SWIFT_ACTION_DERIVE_FILES, + SWIFT_ACTION_DUMP_AST, + ], + configurators = [ + lambda _, args: args.add_all(additional_swiftc_copts), + ], + ), + ) + + action_configs.append( + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_COMPILE_MODULE_INTERFACE, + SWIFT_ACTION_DERIVE_FILES, + SWIFT_ACTION_DUMP_AST, + SWIFT_ACTION_PRECOMPILE_C_MODULE, + ], + configurators = [_source_files_configurator], + ), + ) + + # Add additional input files to the sandbox (does not modify flags). + action_configs.append( + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_DERIVE_FILES, + SWIFT_ACTION_DUMP_AST, + ], + configurators = [_additional_inputs_configurator], + ), + ) + + return action_configs + +def _output_or_file_map(output_file_map, outputs, args): + """Adds the output file map or single object file to the command line.""" + if output_file_map: + args.add("-output-file-map", output_file_map) + return ConfigResultInfo( + inputs = [output_file_map], + ) + + if len(outputs) != 1: + fail( + "Internal error: If not using an output file map, there should " + + "only be a single object file expected as the output, but we " + + "found: {}".format(outputs), + ) + + args.add("-o", outputs[0]) + return None + +def _output_object_or_file_map_configurator(prerequisites, args): + """Adds the output file map or single object file to the command line.""" + return _output_or_file_map( + output_file_map = prerequisites.output_file_map, + outputs = prerequisites.object_files, + args = args, + ) + +def _output_swiftmodule_or_file_map_configurator(prerequisites, args): + """Adds the output file map or single object file to the command line.""" + return _output_or_file_map( + output_file_map = prerequisites.derived_files_output_file_map, + outputs = [prerequisites.swiftmodule_file], + args = args, + ) + +def _output_ast_path_or_file_map_configurator(prerequisites, args): + """Adds the output file map or single AST file to the command line.""" + return _output_or_file_map( + output_file_map = prerequisites.output_file_map, + outputs = prerequisites.ast_files, + args = args, + ) + +def _output_pcm_file_configurator(prerequisites, args): + """Adds the `.pcm` output path to the command line.""" + args.add("-o", prerequisites.pcm_file) + +def _emit_module_path_configurator(prerequisites, args): + """Adds the `.swiftmodule` output path to the command line.""" + args.add("-emit-module-path", prerequisites.swiftmodule_file) + +def _emit_module_interface_path_configurator(prerequisites, args): + """Adds the `.swiftinterface` output path to the command line.""" + args.add("-emit-module-interface-path", prerequisites.swiftinterface_file) + +def _emit_private_module_interface_path_configurator(prerequisites, args): + """Adds the `.private.swiftinterface` output path to the command line.""" + args.add("-emit-private-module-interface-path", prerequisites.private_swiftinterface_file) + +def _emit_objc_header_path_configurator(prerequisites, args): + """Adds the generated header output path to the command line.""" + if prerequisites.generated_header_file: + args.add("-emit-objc-header-path", prerequisites.generated_header_file) + +def _global_module_cache_configurator(prerequisites, args): + """Adds flags to enable the global module cache.""" + + # If bin_dir is not provided, then we don't pass any special flags to + # the compiler, letting it decide where the cache should live. This is + # usually somewhere in the system temporary directory. + if prerequisites.bin_dir: + args.add( + "-module-cache-path", + paths.join(prerequisites.bin_dir.path, "_swift_module_cache"), + ) + +def _tmpdir_module_cache_configurator(prerequisites, args): + """Adds flags to enable a stable tmp directory module cache.""" + + args.add( + "-module-cache-path", + paths.join( + "/tmp/__build_bazel_rules_swift", + "swift_module_cache", + prerequisites.workspace_name, + ), + ) + +def _pch_output_dir_configurator(prerequisites, args): + """Adds flags for pch-output-dir configuration to the command line. + + This is a directory to persist automatically created precompiled bridging headers + + Note: that like the global index store and module cache, we expect clang + to namespace these correctly per arch / os version / etc by the hash in + the path. However, it is also put into the bin_dir for an added layer of + safety. + """ + args.add( + "-pch-output-dir", + paths.join(prerequisites.bin_dir.path, "_pch_output_dir"), + ) + +# The platform developer framework directory contains XCTest.swiftmodule +# with Swift extensions to XCTest, so it needs to be added to the search +# path on platforms where it exists. +def _add_developer_swift_imports(developer_dirs, args): + platform_developer_framework = platform_developer_framework_dir( + developer_dirs, + ) + if platform_developer_framework: + swift_developer_lib_dir_path = swift_developer_lib_dir( + developer_dirs, + ) + args.add(swift_developer_lib_dir_path, format = "-I%s") + +def _non_pcm_developer_framework_paths_configurator(prerequisites, args): + """ Adds developer frameworks flags to the command line. """ + if prerequisites.include_dev_srch_paths: + args.add_all( + [ + developer_dir.path + for developer_dir in prerequisites.developer_dirs + ], + format_each = "-F%s", + ) + _add_developer_swift_imports( + prerequisites.developer_dirs, + args, + ) + +# PCM version of the logic above +def _pcm_developer_framework_paths_configurator(prerequisites, args): + """ Adds developer frameworks flags to the command line. """ + if prerequisites.include_dev_srch_paths: + args.add_all( + [ + developer_dir.path + for developer_dir in prerequisites.developer_dirs + ], + before_each = "-Xcc", + format_each = "-F%s", + ) + _add_developer_swift_imports( + prerequisites.developer_dirs, + args, + ) + +def _batch_mode_configurator(prerequisites, args): + """Adds flags to enable batch compilation mode.""" + if not _is_wmo_manually_requested(prerequisites.user_compile_flags): + args.add("-enable-batch-mode") + +def _c_layering_check_configurator(prerequisites, args): + # We do not enforce layering checks for the Objective-C header generated by + # Swift, because we don't have predictable control over the imports that it + # generates. Due to modular re-exports (which are especially common among + # system frameworks), it may generate an import declaration for a particular + # symbol from a different module than the Swift code imported it from. + if not prerequisites.is_swift_generated_header: + args.add("-Xcc", "-fmodules-strict-decluse") + return None + +def _clang_module_strict_includes(module_context): + """Returns the strict Clang include paths for a module context.""" + if not module_context.clang: + return None + strict_includes = module_context.clang.strict_includes + if not strict_includes: + return None + return strict_includes.to_list() + +def _clang_search_paths_configurator(prerequisites, args): + """Adds Clang search paths to the command line.""" + args.add_all( + prerequisites.cc_compilation_context.includes, + before_each = "-Xcc", + format_each = "-I%s", + ) + args.add_all( + prerequisites.transitive_modules, + before_each = "-Xcc", + format_each = "-I%s", + map_each = _clang_module_strict_includes, + uniquify = True, + ) + + # Add Clang search paths for the workspace root and Bazel output roots. The + # first allows ClangImporter to find headers included using + # workspace-relative paths when they are referenced from within other + # headers. The latter allows ClangImporter to find generated headers in + # `bazel-{bin,genfiles}` even when included using their workspace-relative + # path, matching the behavior used when compiling C/C++/Objective-C. + # + # Note that when `--incompatible_merge_genfiles_directory` is specified, + # `bin_dir` and `genfiles_dir` will have the same path; the depset will + # ensure that the `-iquote` flags are deduped. + direct_quote_includes = ["."] + if prerequisites.bin_dir: + direct_quote_includes.append(prerequisites.bin_dir.path) + if prerequisites.genfiles_dir: + direct_quote_includes.append(prerequisites.genfiles_dir.path) + + args.add_all( + depset( + direct_quote_includes, + transitive = [prerequisites.cc_compilation_context.quote_includes], + ), + before_each = "-Xcc", + format_each = "-iquote%s", + ) + + args.add_all( + prerequisites.cc_compilation_context.system_includes, + before_each = "-Xcc", + format_each = "-isystem%s", + ) + +def _dependencies_clang_defines_configurator(prerequisites, args): + """Adds C/C++ dependencies' preprocessor defines to the command line.""" + all_clang_defines = depset(transitive = [ + prerequisites.cc_compilation_context.defines, + ]) + args.add_all(all_clang_defines, before_each = "-Xcc", format_each = "-D%s") + +def _collect_clang_module_inputs( + explicit_module_compilation_context, + modules, + prefer_precompiled_modules): + """Collects Clang module-related inputs to pass to an action. + + Args: + explicit_module_compilation_context: The `CcCompilationContext` of the + target being compiled, if the inputs are being collected for an + explicit module compilation action. This parameter should be `None` + if inputs are being collected for Swift compilation. + modules: A list of module structures (as returned by + `swift_common.create_module`). The precompiled Clang modules or the + textual module maps and headers of these modules (depending on the + value of `prefer_precompiled_modules`) will be collected as inputs. + prefer_precompiled_modules: If True, precompiled module artifacts should + be preferred over textual module map files and headers for modules + that have them. If False, textual module map files and headers + should always be used. + + Returns: + A toolchain configuration result (i.e., + `swift_toolchain_config.config_result`) that contains the input + artifacts for the action. + """ + direct_inputs = [] + transitive_inputs = [] + + if explicit_module_compilation_context: + # This is a `SwiftPrecompileCModule` action, so by definition we're + # only here in a build with explicit modules enabled. We should only + # need the direct headers of the module being compiled and its + # direct dependencies (the latter because Clang needs them present + # on the file system to map them to the module that contains them.) + # However, we may also need some of the transitive headers, if the + # module has dependencies that aren't recognized as modules (e.g., + # `cc_library` targets without an aspect hint) and the module's + # headers include those. This will likely over-estimate the needed + # inputs, but we can't do better without include scanning in + # Starlark. + transitive_inputs.append(explicit_module_compilation_context.headers) + transitive_inputs.append( + depset(explicit_module_compilation_context.direct_textual_headers), + ) + + for module in modules: + clang_module = module.clang + + # Add the module map, which we use for both implicit and explicit module + # builds. + module_map = clang_module.module_map + if not module.is_system and type(module_map) == "File": + direct_inputs.append(module_map) + + precompiled_module = clang_module.precompiled_module + + if prefer_precompiled_modules and precompiled_module: + # For builds preferring explicit modules, use it if we have it + # and don't include any headers as inputs. + direct_inputs.append(precompiled_module) + else: + # If we don't have an explicit module (or we're not using it), we + # need the transitive headers from the compilation context + # associated with the module. This will likely overestimate the + # headers that will actually be used in the action, but until we can + # use include scanning from Starlark, we can't compute a more + # precise input set. + compilation_context = clang_module.compilation_context + transitive_inputs.append(compilation_context.headers) + transitive_inputs.append( + depset(compilation_context.direct_textual_headers), + ) + + return ConfigResultInfo( + inputs = direct_inputs, + transitive_inputs = transitive_inputs, + ) + +def _clang_modulemap_dependency_args(module, ignore_system = True): + """Returns a `swiftc` argument for the module map of a Clang module. + + Args: + module: A struct containing information about the module, as defined by + `swift_common.create_module`. + ignore_system: If `True` and the module is a system module, no flag + should be returned. Defaults to `True`. + + Returns: + A list of arguments, possibly empty, to pass to `swiftc` (without the + `-Xcc` prefix). + """ + module_map = module.clang.module_map + + if (module.is_system and ignore_system) or not module_map: + return [] + + if type(module_map) == "File": + module_map_path = module_map.path + else: + module_map_path = module_map + + return ["-fmodule-map-file={}".format(module_map_path)] + +def _clang_module_dependency_args(module): + """Returns `swiftc` arguments for a precompiled Clang module, if possible. + + If a precompiled module is present for this module, then flags for both it + and the module map are returned (the latter is required in order to map + headers to modules in some scenarios, since the precompiled modules are + passed by name). If no precompiled module is present for this module, then + this function falls back to the textual module map alone. + + Args: + module: A struct containing information about the module, as defined by + `swift_common.create_module`. + + Returns: + A list of arguments, possibly empty, to pass to `swiftc` (without the + `-Xcc` prefix). + """ + if module.clang.precompiled_module: + # If we're consuming an explicit module, we must also provide the + # textual module map, whether or not it's a system module. + return [ + "-fmodule-file={}={}".format( + module.name, + module.clang.precompiled_module.path, + ), + ] + _clang_modulemap_dependency_args(module, ignore_system = False) + else: + # If we have no explicit module, then only include module maps for + # non-system modules. + return _clang_modulemap_dependency_args(module) + +def _dependencies_clang_modulemaps_configurator(prerequisites, args): + """Configures Clang module maps from dependencies.""" + modules = [ + module + for module in prerequisites.transitive_modules + if module.clang + ] + + # Uniquify the arguments because different modules might be defined in the + # same module map file, so it only needs to be present once on the command + # line. + args.add_all( + modules, + before_each = "-Xcc", + map_each = _clang_modulemap_dependency_args, + uniquify = True, + ) + + if prerequisites.is_swift: + compilation_context = None + else: + compilation_context = prerequisites.cc_compilation_context + + return _collect_clang_module_inputs( + explicit_module_compilation_context = compilation_context, + modules = modules, + prefer_precompiled_modules = False, + ) + +def _dependencies_clang_modules_configurator(prerequisites, args): + """Configures precompiled Clang modules from dependencies.""" + modules = [ + module + for module in prerequisites.transitive_modules + if module.clang + ] + + # Uniquify the arguments because different modules might be defined in the + # same module map file, so it only needs to be present once on the command + # line. + args.add_all( + modules, + before_each = "-Xcc", + map_each = _clang_module_dependency_args, + uniquify = True, + ) + + if prerequisites.is_swift: + compilation_context = None + + else: + compilation_context = prerequisites.cc_compilation_context + + return _collect_clang_module_inputs( + explicit_module_compilation_context = compilation_context, + modules = modules, + prefer_precompiled_modules = True, + ) + +def _framework_search_paths_configurator(prerequisites, args, is_swift): + """Add search paths for prebuilt frameworks to the command line.""" + + # Swift doesn't automatically propagate its `-F` flag to ClangImporter, so + # we add it manually with `-Xcc` below (for both regular compilations, in + # case they're using implicit modules, and Clang module compilations). We + # don't need to add regular `-F` if this is a Clang module compilation, + # though, since it won't be used. + if is_swift: + args.add_all( + prerequisites.cc_compilation_context.framework_includes, + format_each = "-F%s", + ) + args.add_all( + prerequisites.cc_compilation_context.framework_includes, + format_each = "-F%s", + before_each = "-Xcc", + ) + +def _frameworks_disable_autolink_configurator(prerequisites, args): + """Add flags to disable auto-linking for static prebuilt frameworks. + + This disables the `LC_LINKER_OPTION` load commands for auto-linking when + importing a static framework. This is needed to avoid potential linker + errors since when linking the framework it will be passed directly as a + library. + """ + if hasattr(prerequisites.objc_info, "dynamic_framework_file"): + args.add_all( + depset(transitive = [prerequisites.objc_info.imported_library, prerequisites.objc_info.dynamic_framework_file]), + map_each = _disable_autolink_framework_copts, + ) + else: + libraries = [] + inputs = prerequisites.cc_linking_context.linker_inputs.to_list() + for linker_input in inputs: + for library in linker_input.libraries: + if library.dynamic_library: + libraries.append(library.dynamic_library) + if library.static_library: + libraries.append(library.static_library) + if library.pic_static_library: + libraries.append(library.pic_static_library) + + args.add_all( + depset(transitive = [depset(libraries)]), + map_each = _disable_autolink_framework_copts, + ) + +def _disable_autolink_framework_copts(library_path): + """A `map_each` helper that potentially disables autolinking for the given library. + + Args: + library_path: The path to an imported library that is potentially a static framework. + + Returns: + The list of `swiftc` flags needed to disable autolinking for the given + framework. + """ + if not library_path.dirname.endswith(".framework"): + return [] + + return collections.before_each( + "-Xfrontend", + [ + "-disable-autolink-framework", + library_path.basename, + ], + ) + +def _swift_module_search_path_map_fn(module): + """Returns the path to the directory containing a `.swiftmodule` file. + + This function is intended to be used as a mapping function for modules + passed into `Args.add_all`. + + Args: + module: The module structure (as returned by + `swift_common.create_module`) extracted from the transitive + modules of a `SwiftInfo` provider. + + Returns: + The dirname of the module's `.swiftmodule` file. + """ + if module.swift: + return module.swift.swiftmodule.dirname + else: + return None + +def _dependencies_swiftmodules_configurator(prerequisites, args): + """Adds `.swiftmodule` files from deps to search paths and action inputs.""" + args.add_all( + prerequisites.transitive_modules, + format_each = "-I%s", + map_each = _swift_module_search_path_map_fn, + uniquify = True, + ) + + return ConfigResultInfo( + inputs = prerequisites.transitive_swiftmodules, + ) + +def _load_executable_plugin_map_fn(plugin): + """Returns frontend flags to load compiler plugins.""" + return [ + "-load-plugin-executable", + "{executable}#{module_names}".format( + executable = plugin.executable.path, + module_names = ",".join(plugin.module_names.to_list()), + ), + ] + +def _plugins_configurator(prerequisites, args): + """Adds `-load-plugin-executable` flags for required plugins, if any.""" + args.add_all( + prerequisites.plugins, + before_each = "-Xfrontend", + map_each = _load_executable_plugin_map_fn, + ) + + return ConfigResultInfo( + inputs = [p.executable for p in prerequisites.plugins.to_list()], + ) + +def _macro_expansion_configurator(prerequisites, args): + """Adds flags to control where macro expansions are generated.""" + if prerequisites.macro_expansion_directory: + args.add( + prerequisites.macro_expansion_directory.path, + format = "-Xwrapped-swift=-macro-expansion-dir=%s", + ) + +def _dependencies_swiftmodules_vfsoverlay_configurator(prerequisites, args, is_frontend = False): + """Provides a single `.swiftmodule` search path using a VFS overlay.""" + swiftmodules = prerequisites.transitive_swiftmodules + + # Bug: `swiftc` doesn't pass its `-vfsoverlay` arg to the frontend. + # Workaround: Pass `-vfsoverlay` directly via `-Xfrontend`. + if not is_frontend: + args.add("-Xfrontend") + + args.add( + "-vfsoverlay{}".format(prerequisites.vfsoverlay_file.path), + "-I{}".format(prerequisites.vfsoverlay_search_path), + ) + + return ConfigResultInfo( + inputs = swiftmodules + [prerequisites.vfsoverlay_file], + ) + +def _explicit_swift_module_map_configurator(prerequisites, args, is_frontend = False): + """Adds the explicit Swift module map file to the command line.""" + if is_frontend: + args.add( + "-explicit-swift-module-map-file", + prerequisites.explicit_swift_module_map_file, + ) + else: + args.add_all( + [ + "-explicit-swift-module-map-file", + prerequisites.explicit_swift_module_map_file, + ], + before_each = "-Xfrontend", + ) + return ConfigResultInfo( + inputs = prerequisites.transitive_swiftmodules + [ + prerequisites.explicit_swift_module_map_file, + ], + ) + +def _module_name_configurator(prerequisites, args): + """Adds the module name flag to the command line.""" + args.add("-module-name", prerequisites.module_name) + +def _package_name_configurator(prerequisites, args): + if prerequisites.package_name: + args.add("-package-name", prerequisites.package_name) + +def _index_while_building_configurator(prerequisites, args): + """Adds flags for indexstore generation to the command line.""" + if not _is_index_store_path_overridden(prerequisites.user_compile_flags): + args.add("-index-store-path", prerequisites.indexstore_directory.path) + +def _global_index_store_configurator(prerequisites, args): + """Adds flags for index-store generation to the command line.""" + out_dir = prerequisites.indexstore_directory.dirname.split("/")[0] + path = out_dir + "/_global_index_store" + args.add("-Xwrapped-swift=-global-index-store-import-path=" + path) + +def _source_files_configurator(prerequisites, args): + """Adds source files to the command line and required inputs.""" + args.add_all(prerequisites.source_files) + + # Only add source files to the input file set if they are not strings (for + # example, the module map of a system framework will be passed in as a file + # path relative to the SDK root, not as a `File` object). + return ConfigResultInfo( + inputs = [ + source_file + for source_file in prerequisites.source_files + if not types.is_string(source_file) + ], + ) + +def _user_compile_flags_configurator(prerequisites, args): + """Adds user compile flags to the command line.""" + args.add_all(prerequisites.user_compile_flags) + +def _make_wmo_thread_count_configurator(should_check_flags): + """Adds thread count flags for WMO compiles to the command line. + + Args: + should_check_flags: If `True`, WMO wasn't enabled by a feature so the + user compile flags should be checked for an explicit WMO option. If + `False`, unconditionally apply the flags, because it is assumed that + the configurator was triggered by feature satisfaction. + + Returns: + A function used to configure the `-num-threads` flag for WMO. + """ + + def _add_num_threads(args): + args.add("-num-threads", str(_DEFAULT_WMO_THREAD_COUNT)) + + if not should_check_flags: + return lambda _prerequisites, args: _add_num_threads(args) + + def _flag_checking_wmo_thread_count_configurator(prerequisites, args): + if _is_wmo_manually_requested(prerequisites.user_compile_flags): + _add_num_threads(args) + + return _flag_checking_wmo_thread_count_configurator + +def _is_wmo_manually_requested(user_compile_flags): + """Returns `True` if a WMO flag is in the given list of compiler flags. + + Args: + user_compile_flags: A list of compiler flags to scan for WMO usage. + + Returns: + True if WMO is enabled in the given list of flags. + """ + for copt in user_compile_flags: + if copt in _WMO_FLAGS: + return True + return False + +def _is_index_store_path_overridden(user_compile_flags): + """Returns `True` if `-index-store-path` is in the given list of compiler flags. + + Index while building is disabled when the copts include a custom + `-index-store-path`. + + Args: + user_compile_flags: A list of compiler flags to scan for index store + usage. + + Returns: + True if `-index-store-path` is set in the given list of flags. + """ + for opt in user_compile_flags: + if opt == "-index-store-path": + return True + return False + +def _exclude_swift_incompatible_define(define): + """A `map_each` helper that excludes a define if it is not Swift-compatible. + + This function rejects any defines that are not of the form `FOO=1` or `FOO`. + Note that in C-family languages, the option `-DFOO` is equivalent to + `-DFOO=1` so we must preserve both. + + Args: + define: A string of the form `FOO` or `FOO=BAR` that represents an + Objective-C define. + + Returns: + The token portion of the define it is Swift-compatible, or `None` + otherwise. + """ + token, equal, value = define.partition("=") + if (not equal and not value) or (equal == "=" and value == "1"): + return token + return None + +def _conditional_compilation_flag_configurator(prerequisites, args): + """Adds (non-Clang) conditional compilation flags to the command line.""" + all_defines = depset( + prerequisites.defines, + transitive = [ + # Take any Swift-compatible defines from Objective-C dependencies + # and define them for Swift. + prerequisites.cc_compilation_context.defines, + ], + ) + args.add_all( + all_defines, + map_each = _exclude_swift_incompatible_define, + format_each = "-D%s", + uniquify = True, + ) + +def _constant_value_extraction_configurator(prerequisites, args): + """Adds flags related to constant value extraction to the command line.""" + if not prerequisites.const_protocols_to_gather_file: + return None + + args.add("-emit-const-values-path", prerequisites.const_values_files[0]) + args.add_all( + [ + "-const-gather-protocols-file", + prerequisites.const_protocols_to_gather_file, + ], + before_each = "-Xfrontend", + ) + return ConfigResultInfo( + inputs = [prerequisites.const_protocols_to_gather_file], + ) + +def _additional_inputs_configurator(prerequisites, _args): + """Propagates additional input files to the action. + + This configurator does not add any flags to the command line, but ensures + that any additional input files requested by the caller of the action are + available in the sandbox. + """ + return ConfigResultInfo( + inputs = prerequisites.additional_inputs, + ) diff --git a/swift/toolchains/config/compile_module_interface_config.bzl b/swift/toolchains/config/compile_module_interface_config.bzl index 2e9480ece..a6aa069e7 100644 --- a/swift/toolchains/config/compile_module_interface_config.bzl +++ b/swift/toolchains/config/compile_module_interface_config.bzl @@ -14,33 +14,38 @@ """Common configuration for compile module interface actions.""" -load("//swift/internal:actions.bzl", "swift_action_names") -load("//swift/internal:toolchain_config.bzl", "swift_toolchain_config") +load( + "//swift/internal:action_names.bzl", + "SWIFT_ACTION_COMPILE_MODULE_INTERFACE", +) +load(":action_config.bzl", "ActionConfigInfo", "add_arg") def compile_module_interface_action_configs(): return [ - swift_toolchain_config.action_config( - actions = [swift_action_names.COMPILE_MODULE_INTERFACE], - configurators = [swift_toolchain_config.add_arg("-enable-library-evolution")], + ActionConfigInfo( + actions = [SWIFT_ACTION_COMPILE_MODULE_INTERFACE], + configurators = [add_arg("-enable-library-evolution")], ), - swift_toolchain_config.action_config( - actions = [swift_action_names.COMPILE_MODULE_INTERFACE], - configurators = [_emit_module_path_from_module_interface_configurator], + ActionConfigInfo( + actions = [SWIFT_ACTION_COMPILE_MODULE_INTERFACE], + configurators = [ + _emit_module_path_from_module_interface_configurator, + ], ), - swift_toolchain_config.action_config( - actions = [swift_action_names.COMPILE_MODULE_INTERFACE], + ActionConfigInfo( + actions = [SWIFT_ACTION_COMPILE_MODULE_INTERFACE], configurators = [ - swift_toolchain_config.add_arg("-compile-module-from-interface"), + add_arg("-compile-module-from-interface"), ], ), # Library evolution is implied since we've already produced a # .swiftinterface file. So we want to unconditionally enable the flag # for this action. - swift_toolchain_config.action_config( + ActionConfigInfo( actions = [ - swift_action_names.COMPILE_MODULE_INTERFACE, + SWIFT_ACTION_COMPILE_MODULE_INTERFACE, ], - configurators = [swift_toolchain_config.add_arg("-enable-library-evolution")], + configurators = [add_arg("-enable-library-evolution")], ), ] diff --git a/swift/toolchains/config/modulewrap_config.bzl b/swift/toolchains/config/modulewrap_config.bzl new file mode 100644 index 000000000..9839fc273 --- /dev/null +++ b/swift/toolchains/config/modulewrap_config.bzl @@ -0,0 +1,48 @@ +# Copyright 2022 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. + +"""Common configuration for modulewrap actions.""" + +load("//swift/internal:action_names.bzl", "SWIFT_ACTION_MODULEWRAP") +load(":action_config.bzl", "ActionConfigInfo", "ConfigResultInfo") + +def modulewrap_action_configs(): + """Returns the list of action configs needed to perform module wrapping. + + If a toolchain supports module wrapping, it should add these to its list of + action configs so that those actions will be correctly configured. + + Returns: + The list of action configs needed to perform module wrapping. + """ + return [ + ActionConfigInfo( + actions = [SWIFT_ACTION_MODULEWRAP], + configurators = [ + _modulewrap_input_configurator, + _modulewrap_output_configurator, + ], + ), + ] + +def _modulewrap_input_configurator(prerequisites, args): + """Configures the inputs of the modulewrap action.""" + swiftmodule_file = prerequisites.swiftmodule_file + + args.add(swiftmodule_file) + return ConfigResultInfo(inputs = [swiftmodule_file]) + +def _modulewrap_output_configurator(prerequisites, args): + """Configures the outputs of the modulewrap action.""" + args.add("-o", prerequisites.object_file) diff --git a/swift/toolchains/config/symbol_graph_config.bzl b/swift/toolchains/config/symbol_graph_config.bzl new file mode 100644 index 000000000..3d09ceab3 --- /dev/null +++ b/swift/toolchains/config/symbol_graph_config.bzl @@ -0,0 +1,64 @@ +# Copyright 2022 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. + +"""Common configuration for symbol graph extraction actions.""" + +load( + "//swift/internal:action_names.bzl", + "SWIFT_ACTION_SYMBOL_GRAPH_EXTRACT", +) +load(":action_config.bzl", "ActionConfigInfo") + +def symbol_graph_action_configs(): + """Returns the list of action configs needed to extract symbol graphs. + + If a toolchain supports symbol graph extraction, it should add these to its + list of action configs so that those actions will be correctly configured. + (Other required configuration is provided by `compile_action_configs`.) + + Returns: + The list of action configs needed to extract symbol graphs. + """ + return [ + ActionConfigInfo( + actions = [SWIFT_ACTION_SYMBOL_GRAPH_EXTRACT], + configurators = [_symbol_graph_minimum_access_level_configurator], + ), + ActionConfigInfo( + actions = [SWIFT_ACTION_SYMBOL_GRAPH_EXTRACT], + configurators = [_symbol_graph_output_configurator], + ), + ActionConfigInfo( + actions = [SWIFT_ACTION_SYMBOL_GRAPH_EXTRACT], + configurators = [ + _symbol_graph_emit_extension_block_symbols_configurator, + ], + ), + ] + +def _symbol_graph_minimum_access_level_configurator(prerequisites, args): + """Configures the minimum access level of the symbol graph extraction.""" + if prerequisites.minimum_access_level: + args.add("-minimum-access-level", prerequisites.minimum_access_level) + +def _symbol_graph_output_configurator(prerequisites, args): + """Configures the outputs of the symbol graph extract action.""" + args.add("-output-dir", prerequisites.output_dir.path) + +def _symbol_graph_emit_extension_block_symbols_configurator(prerequisites, args): + """Configures whether `extension` block information should be emitted in the symbol graph.""" + + # TODO: update to use `bool` once https://github.com/bazelbuild/bazel/issues/22809 is resolved. + if prerequisites.emit_extension_block_symbols == "1": + args.add("-emit-extension-block-symbols") diff --git a/swift/toolchains/config/tool_config.bzl b/swift/toolchains/config/tool_config.bzl new file mode 100644 index 000000000..fbeacf8b0 --- /dev/null +++ b/swift/toolchains/config/tool_config.bzl @@ -0,0 +1,159 @@ +# Copyright 2022 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. + +"""Definitions used to configure toolchain tools.""" + +load("@bazel_skylib//lib:paths.bzl", "paths") + +def _tool_config_info_init( + *, + additional_tools = [], + args = [], + driver_config = {}, + env = {}, + executable = None, + execution_requirements = {}, + resource_set = None, + use_param_file = False, + worker_mode = None): + """Validates and initializes a new Swift toolchain tool configuration. + + The `driver_config` argument can be specified as a convenience that supports + the various ways that the Swift driver can have its location specified or + overridden by the build rules, such as by providing a toolchain root + directory or a custom executable. It supports three kinds of "dispatch": + + 1. If the toolchain provides a custom driver executable, the returned tool + config invokes it with the requested mode passed via the `--driver_mode` + argument. + 2. If the toolchain provides a root directory, then the returned tool + config will use an executable that is a string with the same name as the + driver mode in the `bin` directory of that toolchain. + 3. If the toolchain does not provide a root, then the returned tool config + simply uses the driver mode as the executable, assuming that it will be + available by invoking that alone (e.g., it will be found on the system + path or by another delegating tool like `xcrun` from Xcode). + + Args: + additional_tools: A list of `File`s or `FilesToRunProvider`s denoting + additional tools that should be passed as inputs to actions that + use this tool. This should be used if `executable` is, for example, + a symlink that points to another executable or if it is a driver + that launches other executables as subprocesses. + args: A list of arguments that are always passed to the tool. + driver_config: Special configuration for a Swift driver tool. This + dictionary must contain a `mode` key that indicates the Swift driver + mode to launch (e.g., `swift`, `swiftc`, + `swift-symbolgraph-extract`). It may also contain three optional + entries: `swift_executable`, a custom Swift executable that may be + provided by the toolchain; `toolchain_root`, the root directory of a + custom toolchain to use; and `tool_executable_suffix`, the suffix + for executable tools to use (e.g. `.exe` on Windows). This may not + be specified if `executable` is specified. + env: A dictionary of environment variables that should be set when + invoking actions using this tool. + executable: The `File` or `string` denoting the tool that should be + executed. This will be used as the `executable` argument of spawned + actions unless `worker_mode` is set, in which case it will be used + as the first argument to the worker. + execution_requirements: A dictionary of execution requirements that + should be passed when creating actions with this tool. + resource_set: The function which build resource set (mem, cpu) for local + invocation of the action. + use_param_file: If True, actions invoked using this tool will have their + arguments written to a param file. + worker_mode: A string, or `None`, describing how the tool is invoked + using the build rules' worker, if at all. If `None`, the tool will + be invoked directly. If `"wrap"`, the tool will be wrapped in an + invocation of the worker but otherwise run as a single process. If + `"persistent"`, then the action will be launched with execution + requirements that indicate that Bazel should attempt to use a + persistent worker if the spawn strategy allows for it (starting a + new instance if necessary, or connecting to an existing one). + + Returns: + A validated dictionary with the fields of the `ToolConfigInfo` provider. + """ + if driver_config: + if executable: + fail("Both 'driver_config' and 'executable' cannot be specified.") + + driver_mode = driver_config.get("mode", None) + if not driver_mode: + fail( + "When using 'driver_config', the 'mode' key must be specified.", + ) + + swift_executable = driver_config.get("swift_executable", None) + toolchain_root = driver_config.get("toolchain_root", None) + + if swift_executable: + executable = swift_executable + args = ["--driver-mode={}".format(driver_mode)] + args + elif toolchain_root: + executable = paths.join(toolchain_root, "bin", driver_mode) + else: + executable = driver_mode + + tool_executable_suffix = driver_config.get("tool_executable_suffix", "") + + if not executable.endswith(tool_executable_suffix): + executable = "{}{}".format(executable, tool_executable_suffix) + + return { + "additional_tools": additional_tools, + "args": args, + "env": env, + "executable": executable, + "execution_requirements": execution_requirements, + "resource_set": resource_set, + "use_param_file": use_param_file, + "worker_mode": _validate_worker_mode(worker_mode), + } + +ToolConfigInfo, _tool_config_info_init_unchecked = provider( + doc = "A tool used by the Swift toolchain and its requirements.", + fields = [ + "additional_tools", + "args", + "env", + "executable", + "execution_requirements", + "resource_set", + "use_param_file", + "worker_mode", + ], + init = _tool_config_info_init, +) + +def _validate_worker_mode(worker_mode): + """Validates the `worker_mode` argument of `tool_config`. + + This function fails the build if the worker mode is not None, "persistent", + or "wrap". + + Args: + worker_mode: The worker mode to validate. + + Returns: + The original worker mode, if it was valid. + """ + if worker_mode != None and worker_mode not in ("persistent", "wrap"): + fail( + "The 'worker_mode' argument of " + + "'swift_toolchain_config.tool_config' must be either None, " + + "'persistent', or 'wrap'.", + ) + + return worker_mode diff --git a/swift/toolchains/swift_toolchain.bzl b/swift/toolchains/swift_toolchain.bzl index 2e8efa3b6..a79cb84e7 100644 --- a/swift/toolchains/swift_toolchain.bzl +++ b/swift/toolchains/swift_toolchain.bzl @@ -30,15 +30,18 @@ load( "SwiftPackageConfigurationInfo", "SwiftToolchainInfo", ) -load("//swift/internal:actions.bzl", "swift_action_names") -load("//swift/internal:attrs.bzl", "swift_toolchain_driver_attrs") -load("//swift/internal:autolinking.bzl", "autolink_extract_action_configs") load( - "//swift/internal:compiling.bzl", - "compile_action_configs", - "features_from_swiftcopts", + "//swift/internal:action_names.bzl", + "SWIFT_ACTION_AUTOLINK_EXTRACT", + "SWIFT_ACTION_COMPILE", + "SWIFT_ACTION_DERIVE_FILES", + "SWIFT_ACTION_DUMP_AST", + "SWIFT_ACTION_MODULEWRAP", + "SWIFT_ACTION_PRECOMPILE_C_MODULE", + "SWIFT_ACTION_SYMBOL_GRAPH_EXTRACT", ) -load("//swift/internal:debugging.bzl", "modulewrap_action_configs") +load("//swift/internal:attrs.bzl", "swift_toolchain_driver_attrs") +load("//swift/internal:autolinking.bzl", "autolink_extract_action_configs") load( "//swift/internal:feature_names.bzl", "SWIFT_FEATURE_CACHEABLE_SWIFTMODULES", @@ -56,17 +59,32 @@ load( "SWIFT_FEATURE_USE_RESPONSE_FILES", ) load("//swift/internal:features.bzl", "features_for_build_modes") -load( - "//swift/internal:symbol_graph_extracting.bzl", - "symbol_graph_action_configs", -) load("//swift/internal:target_triples.bzl", "target_triples") -load("//swift/internal:toolchain_config.bzl", "swift_toolchain_config") load( "//swift/internal:utils.bzl", "collect_implicit_deps_providers", "get_swift_executable_for_toolchain", ) +load("//swift/internal:wmo.bzl", "features_from_swiftcopts") +load( + "//swift/toolchains/config:action_config.bzl", + "ActionConfigInfo", + "add_arg", +) +load( + "//swift/toolchains/config:all_actions_config.bzl", + "all_actions_action_configs", +) +load("//swift/toolchains/config:compile_config.bzl", "compile_action_configs") +load( + "//swift/toolchains/config:modulewrap_config.bzl", + "modulewrap_action_configs", +) +load( + "//swift/toolchains/config:symbol_graph_config.bzl", + "symbol_graph_action_configs", +) +load("//swift/toolchains/config:tool_config.bzl", "ToolConfigInfo") def _swift_compile_resource_set(_os, inputs_size): # The `os` argument is unused, but the Starlark API requires both @@ -104,60 +122,54 @@ def _all_tool_configs( Returns: A dictionary mapping action name to tool configurations. """ - _swift_driver_tool_config = swift_toolchain_config.driver_tool_config - compile_tool_config = _swift_driver_tool_config( - driver_mode = "swiftc", + def _driver_config(*, mode): + return { + "mode": mode, + "swift_executable": swift_executable, + "tool_executable_suffix": tool_executable_suffix, + "toolchain_root": toolchain_root, + } + + compile_tool_config = ToolConfigInfo( + additional_tools = additional_tools, + driver_config = _driver_config(mode = "swiftc"), resource_set = _swift_compile_resource_set, - swift_executable = swift_executable, - tools = additional_tools, - toolchain_root = toolchain_root, - tool_executable_suffix = tool_executable_suffix, use_param_file = use_param_file, worker_mode = "persistent", env = env, ) - swift_symbolgraph_extract_config = _swift_driver_tool_config( - driver_mode = "swift-symbolgraph-extract", - swift_executable = swift_executable, - tools = additional_tools, - toolchain_root = toolchain_root, - tool_executable_suffix = tool_executable_suffix, - use_param_file = True, - worker_mode = "wrap", - env = env, - ) - - configs = { - swift_action_names.COMPILE: compile_tool_config, - swift_action_names.DERIVE_FILES: compile_tool_config, - swift_action_names.DUMP_AST: compile_tool_config, - swift_action_names.SYMBOL_GRAPH_EXTRACT: swift_symbolgraph_extract_config, + tool_configs = { + SWIFT_ACTION_COMPILE: compile_tool_config, + SWIFT_ACTION_DERIVE_FILES: compile_tool_config, + SWIFT_ACTION_DUMP_AST: compile_tool_config, + SWIFT_ACTION_SYMBOL_GRAPH_EXTRACT: ToolConfigInfo( + additional_tools = additional_tools, + driver_config = _driver_config(mode = "swift-symbolgraph-extract"), + use_param_file = True, + worker_mode = "wrap", + env = env, + ), } if use_autolink_extract: - configs[swift_action_names.AUTOLINK_EXTRACT] = _swift_driver_tool_config( - driver_mode = "swift-autolink-extract", - swift_executable = swift_executable, - tools = additional_tools, - toolchain_root = toolchain_root, - tool_executable_suffix = tool_executable_suffix, + tool_configs[SWIFT_ACTION_AUTOLINK_EXTRACT] = ToolConfigInfo( + additional_tools = additional_tools, + driver_config = _driver_config(mode = "swift-autolink-extract"), worker_mode = "wrap", ) if use_module_wrap: - configs[swift_action_names.MODULEWRAP] = _swift_driver_tool_config( + tool_configs[SWIFT_ACTION_MODULEWRAP] = ToolConfigInfo( + additional_tools = additional_tools, # This must come first after the driver name. args = ["-modulewrap"], - driver_mode = "swift", - swift_executable = swift_executable, - tools = additional_tools, - toolchain_root = toolchain_root, - tool_executable_suffix = tool_executable_suffix, + driver_config = _driver_config(mode = "swift"), worker_mode = "wrap", ) - return configs + + return tool_configs def _all_action_configs(os, arch, target_triple, sdkroot, xctest_version, additional_swiftc_copts): """Returns the action configurations for the Swift toolchain. @@ -175,33 +187,97 @@ def _all_action_configs(os, arch, target_triple, sdkroot, xctest_version, additi A list of action configurations for the toolchain. """ - # Basic compilation flags (target triple). + # Basic compilation flags (target triple and toolchain search paths). action_configs = [ - swift_toolchain_config.action_config( + ActionConfigInfo( actions = [ - swift_action_names.SYMBOL_GRAPH_EXTRACT, + SWIFT_ACTION_SYMBOL_GRAPH_EXTRACT, ], configurators = [ - swift_toolchain_config.add_arg( - "-target", - target_triples.str(target_triple), - ), + add_arg("-target", target_triples.str(target_triple)), ], ), ] - - action_configs.extend(( + if sdkroot: + action_configs = [ + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_DERIVE_FILES, + SWIFT_ACTION_DUMP_AST, + SWIFT_ACTION_PRECOMPILE_C_MODULE, + ], + configurators = [add_arg("-sdk", sdkroot)], + ), + ] + + if os and xctest_version: + action_configs.append( + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_DERIVE_FILES, + SWIFT_ACTION_DUMP_AST, + SWIFT_ACTION_PRECOMPILE_C_MODULE, + ], + configurators = [ + add_arg( + paths.join( + sdkroot, + "..", + "..", + "Library", + "XCTest-{}".format(xctest_version), + "usr", + "lib", + "swift", + os, + ), + format = "-I%s", + ), + ], + ), + ) + + # Compatibility with older builds of the Swift SDKs. + if arch: + action_configs.append( + ActionConfigInfo( + actions = [ + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_DERIVE_FILES, + SWIFT_ACTION_DUMP_AST, + SWIFT_ACTION_PRECOMPILE_C_MODULE, + ], + configurators = [ + add_arg( + paths.join( + sdkroot, + "..", + "..", + "Library", + "XCTest-{}".format(xctest_version), + "usr", + "lib", + "swift", + os, + arch, + ), + format = "-I%s", + ), + ], + ), + ) + + action_configs.extend(all_actions_action_configs()) + action_configs.extend( compile_action_configs( - os = os, - arch = arch, - sdkroot = sdkroot, - xctest_version = xctest_version, additional_swiftc_copts = additional_swiftc_copts, - ) + - modulewrap_action_configs() + - autolink_extract_action_configs() + - symbol_graph_action_configs() - )) + ), + ) + action_configs.extend(modulewrap_action_configs()) + action_configs.extend(autolink_extract_action_configs()) + action_configs.extend(symbol_graph_action_configs()) return action_configs diff --git a/swift/toolchains/xcode_swift_toolchain.bzl b/swift/toolchains/xcode_swift_toolchain.bzl index aebbdf7c8..64d922bf1 100644 --- a/swift/toolchains/xcode_swift_toolchain.bzl +++ b/swift/toolchains/xcode_swift_toolchain.bzl @@ -31,9 +31,16 @@ load( "SwiftPackageConfigurationInfo", "SwiftToolchainInfo", ) -load("//swift/internal:actions.bzl", "swift_action_names", "target_label_action_configs") +load( + "//swift/internal:action_names.bzl", + "SWIFT_ACTION_COMPILE", + "SWIFT_ACTION_COMPILE_MODULE_INTERFACE", + "SWIFT_ACTION_DERIVE_FILES", + "SWIFT_ACTION_DUMP_AST", + "SWIFT_ACTION_PRECOMPILE_C_MODULE", + "SWIFT_ACTION_SYMBOL_GRAPH_EXTRACT", +) load("//swift/internal:attrs.bzl", "swift_toolchain_driver_attrs") -load("//swift/internal:compiling.bzl", "compile_action_configs", "features_from_swiftcopts") load( "//swift/internal:feature_names.bzl", "SWIFT_FEATURE_BUNDLED_XCTESTS", @@ -62,14 +69,32 @@ load( "SWIFT_FEATURE__SUPPORTS_MACROS", ) load("//swift/internal:features.bzl", "features_for_build_modes") -load("//swift/internal:symbol_graph_extracting.bzl", "symbol_graph_action_configs") load("//swift/internal:target_triples.bzl", "target_triples") -load("//swift/internal:toolchain_config.bzl", "swift_toolchain_config") load( "//swift/internal:utils.bzl", "collect_implicit_deps_providers", "get_swift_executable_for_toolchain", ) +load("//swift/internal:wmo.bzl", "wmo_features_from_swiftcopts") +load( + "//swift/toolchains/config:action_config.bzl", + "ActionConfigInfo", + "add_arg", +) +load( + "//swift/toolchains/config:all_actions_config.bzl", + "all_actions_action_configs", +) +load("//swift/toolchains/config:compile_config.bzl", "compile_action_configs") +load( + "//swift/toolchains/config:compile_module_interface_config.bzl", + "compile_module_interface_action_configs", +) +load( + "//swift/toolchains/config:symbol_graph_config.bzl", + "symbol_graph_action_configs", +) +load("//swift/toolchains/config:tool_config.bzl", "ToolConfigInfo") # TODO: Remove once we drop bazel 7.x _OBJC_PROVIDER_LINKING = hasattr(apple_common.new_objc_provider(), "linkopt") @@ -323,37 +348,31 @@ def _all_action_configs( # Basic compilation flags (target triple and toolchain search paths). action_configs = [ - swift_toolchain_config.action_config( + ActionConfigInfo( actions = [ - swift_action_names.COMPILE, - swift_action_names.COMPILE_MODULE_INTERFACE, - swift_action_names.DERIVE_FILES, - swift_action_names.DUMP_AST, - swift_action_names.PRECOMPILE_C_MODULE, - swift_action_names.SYMBOL_GRAPH_EXTRACT, + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_COMPILE_MODULE_INTERFACE, + SWIFT_ACTION_DERIVE_FILES, + SWIFT_ACTION_DUMP_AST, + SWIFT_ACTION_PRECOMPILE_C_MODULE, + SWIFT_ACTION_SYMBOL_GRAPH_EXTRACT, ], configurators = [ - swift_toolchain_config.add_arg( - "-target", - target_triples.str(target_triple), - ), - swift_toolchain_config.add_arg( - "-sdk", - apple_toolchain.sdk_dir(), - ), + add_arg("-target", target_triples.str(target_triple)), + add_arg("-sdk", apple_toolchain.sdk_dir()), ], ), ] action_configs.extend([ # Xcode path remapping - swift_toolchain_config.action_config( + ActionConfigInfo( actions = [ - swift_action_names.COMPILE, - swift_action_names.DERIVE_FILES, + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_DERIVE_FILES, ], configurators = [ - swift_toolchain_config.add_arg( + add_arg( "-debug-prefix-map", "__BAZEL_XCODE_DEVELOPER_DIR__=/PLACEHOLDER_DEVELOPER_DIR", ), @@ -362,14 +381,14 @@ def _all_action_configs( [SWIFT_FEATURE_REMAP_XCODE_PATH, SWIFT_FEATURE_DEBUG_PREFIX_MAP], ], ), - swift_toolchain_config.action_config( + ActionConfigInfo( actions = [ - swift_action_names.COMPILE, - swift_action_names.COMPILE_MODULE_INTERFACE, - swift_action_names.DERIVE_FILES, + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_COMPILE_MODULE_INTERFACE, + SWIFT_ACTION_DERIVE_FILES, ], configurators = [ - swift_toolchain_config.add_arg( + add_arg( "-coverage-prefix-map", "__BAZEL_XCODE_DEVELOPER_DIR__=/PLACEHOLDER_DEVELOPER_DIR", ), @@ -382,13 +401,13 @@ def _all_action_configs( ], ], ), - swift_toolchain_config.action_config( + ActionConfigInfo( actions = [ - swift_action_names.COMPILE, - swift_action_names.DERIVE_FILES, + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_DERIVE_FILES, ], configurators = [ - swift_toolchain_config.add_arg( + add_arg( "-file-prefix-map", "__BAZEL_XCODE_DEVELOPER_DIR__=/PLACEHOLDER_DEVELOPER_DIR", ), @@ -407,13 +426,13 @@ def _all_action_configs( # toolchain, provide the original toolchain's resources as the resource # directory so that modules are found correctly. action_configs.append( - swift_toolchain_config.action_config( + ActionConfigInfo( actions = [ - swift_action_names.COMPILE, - swift_action_names.DERIVE_FILES, - swift_action_names.DUMP_AST, - swift_action_names.PRECOMPILE_C_MODULE, - swift_action_names.SYMBOL_GRAPH_EXTRACT, + SWIFT_ACTION_COMPILE, + SWIFT_ACTION_DERIVE_FILES, + SWIFT_ACTION_DUMP_AST, + SWIFT_ACTION_PRECOMPILE_C_MODULE, + SWIFT_ACTION_SYMBOL_GRAPH_EXTRACT, ], configurators = [ _make_resource_directory_configurator( @@ -423,13 +442,14 @@ def _all_action_configs( ), ) - action_configs.extend(target_label_action_configs()) + action_configs.extend(all_actions_action_configs()) action_configs.extend(compile_action_configs( additional_objc_copts = additional_objc_copts, additional_swiftc_copts = additional_swiftc_copts, generated_header_rewriter = generated_header_rewriter, )) action_configs.extend(symbol_graph_action_configs()) + action_configs.extend(compile_module_interface_action_configs()) return action_configs @@ -471,51 +491,55 @@ def _all_tool_configs( env["SWIFT_AVOID_WARNING_USING_OLD_DRIVER"] = "1" - tool_config = swift_toolchain_config.driver_tool_config( - driver_mode = "swiftc", + def _driver_config(*, mode): + return { + "mode": mode, + "swift_executable": swift_executable, + "toolchain_root": toolchain_root, + } + + tool_config = ToolConfigInfo( + additional_tools = ( + [generated_header_rewriter] if generated_header_rewriter else [] + ), + driver_config = _driver_config(mode = "swiftc"), env = env, execution_requirements = execution_requirements, resource_set = _swift_compile_resource_set, - swift_executable = swift_executable, - tools = [generated_header_rewriter] if generated_header_rewriter else [], - toolchain_root = toolchain_root, use_param_file = True, worker_mode = "persistent", ) tool_configs = { - swift_action_names.COMPILE: tool_config, - swift_action_names.DERIVE_FILES: tool_config, - swift_action_names.DUMP_AST: tool_config, - swift_action_names.PRECOMPILE_C_MODULE: ( - swift_toolchain_config.driver_tool_config( - driver_mode = "swiftc", + SWIFT_ACTION_COMPILE: tool_config, + SWIFT_ACTION_DERIVE_FILES: tool_config, + SWIFT_ACTION_DUMP_AST: tool_config, + SWIFT_ACTION_PRECOMPILE_C_MODULE: ( + ToolConfigInfo( + driver_config = _driver_config(mode = "swiftc"), env = env, execution_requirements = execution_requirements, - swift_executable = swift_executable, - toolchain_root = toolchain_root, use_param_file = True, worker_mode = "wrap", ) ), - swift_action_names.COMPILE_MODULE_INTERFACE: ( - swift_toolchain_config.driver_tool_config( - driver_mode = "swiftc", + SWIFT_ACTION_COMPILE_MODULE_INTERFACE: ( + ToolConfigInfo( args = ["-frontend"], + driver_config = _driver_config(mode = "swiftc"), env = env, execution_requirements = execution_requirements, - swift_executable = swift_executable, - toolchain_root = toolchain_root, use_param_file = True, worker_mode = "wrap", ) ), - swift_action_names.SYMBOL_GRAPH_EXTRACT: ( - swift_toolchain_config.driver_tool_config( - driver_mode = "swift-symbolgraph-extract", + SWIFT_ACTION_SYMBOL_GRAPH_EXTRACT: ( + ToolConfigInfo( + driver_config = _driver_config( + mode = "swift-symbolgraph-extract", + ), env = env, execution_requirements = execution_requirements, - swift_executable = swift_executable, use_param_file = True, worker_mode = "wrap", ) @@ -631,7 +655,7 @@ def _xcode_swift_toolchain_impl(ctx): requested_features = features_for_build_modes( ctx, cpp_fragment = cpp_fragment, - ) + features_from_swiftcopts(swiftcopts = swiftcopts) + ) + wmo_features_from_swiftcopts(swiftcopts = swiftcopts) requested_features.extend(ctx.features) requested_features.extend([ SWIFT_FEATURE_BUNDLED_XCTESTS,