From 9e529a9ef6e58f9997ce8cae16fc45d6bf0cc9c3 Mon Sep 17 00:00:00 2001 From: Tony Allevato Date: Fri, 30 Sep 2022 13:57:16 -0700 Subject: [PATCH] Support `swift_{binary,test}` generating a `.dSYM` bundle as an output when `--apple_generate_dsym` is set PiperOrigin-RevId: 478074024 (cherry picked from commit 98de95c5712f4afcb4ad0040425b32ee4686014e) Signed-off-by: Brentley Jones --- doc/providers.md | 10 +++++---- swift/internal/linking.bzl | 17 +++++++++++---- swift/providers.bzl | 10 +++++++++ swift/swift_binary.bzl | 16 +++++++++++++++ swift/swift_test.bzl | 18 +++++++++++++++- swift/toolchains/swift_toolchain.bzl | 1 + swift/toolchains/xcode_swift_toolchain.bzl | 24 ++++++++++++++++++++++ 7 files changed, 87 insertions(+), 9 deletions(-) diff --git a/doc/providers.md b/doc/providers.md index f9472df37..7ea144ffd 100644 --- a/doc/providers.md +++ b/doc/providers.md @@ -84,10 +84,11 @@ Propagates Swift-specific information about a `proto_library`.
 SwiftToolchainInfo(action_configs, cc_toolchain_info, clang_implicit_deps_providers,
-                   const_protocols_to_gather, developer_dirs, entry_point_linkopts_provider,
-                   feature_allowlists, generated_header_module_implicit_deps_providers,
-                   implicit_deps_providers, package_configurations, requested_features, root_dir,
-                   swift_worker, test_configuration, tool_configs, unsupported_features)
+                   const_protocols_to_gather, debug_outputs_provider, developer_dirs,
+                   entry_point_linkopts_provider, feature_allowlists,
+                   generated_header_module_implicit_deps_providers, implicit_deps_providers,
+                   package_configurations, requested_features, root_dir, swift_worker,
+                   test_configuration, tool_configs, unsupported_features)
 
Propagates information about a Swift toolchain to compilation and linking rules @@ -102,6 +103,7 @@ that use the toolchain. | cc_toolchain_info | The `cc_common.CcToolchainInfo` provider from the Bazel C++ toolchain that this Swift toolchain depends on. | | clang_implicit_deps_providers | A `struct` with the following fields, which represent providers from targets that should be added as implicit dependencies of any precompiled explicit C/Objective-C modules:

* `cc_infos`: A list of `CcInfo` providers from targets specified as the toolchain's implicit dependencies. * `objc_infos`: A list of `apple_common.Objc` providers from targets specified as the toolchain's implicit dependencies. * `swift_infos`: A list of `SwiftInfo` providers from targets specified as the toolchain's implicit dependencies.

For ease of use, this field is never `None`; it will always be a valid `struct` containing the fields described above, even if those lists are empty. | | const_protocols_to_gather | `File`. A JSON file specifying a list of protocols for extraction of conformances' const values. | +| debug_outputs_provider | An optional function that provides toolchain-specific logic around the handling of additional debug outputs for `swift_binary` and `swift_test` targets. If specified, this function must take the following keyword arguments: * `ctx`: The rule context of the calling binary or test rule. It must return a `struct` with the following fields: * `additional_outputs`: Additional outputs expected from the linking action. * `variables_extension`: A dictionary of additional crosstool variables to pass to the linking action. | | developer_dirs | A list of `structs` containing the following fields:* `developer_path_label`: A `string` representing the type of developer path. * `path`: A `string` representing the path to the developer framework. | | entry_point_linkopts_provider | A function that returns flags that should be passed to the linker to control the name of the entry point of a linked binary for rules that customize their entry point. This function must take the following keyword arguments: * `entry_point_name`: The name of the entry point function, as was passed to the Swift compiler using the `-entry-point-function-name` flag. It must return a `struct` with the following fields: * `linkopts`: A list of strings that will be passed as additional linker flags when linking a binary with a custom entry point. | | feature_allowlists | A list of `SwiftFeatureAllowlistInfo` providers that allow or prohibit packages from requesting or disabling features. | diff --git a/swift/internal/linking.bzl b/swift/internal/linking.bzl index d0d9dea06..f1b4b2758 100644 --- a/swift/internal/linking.bzl +++ b/swift/internal/linking.bzl @@ -568,19 +568,22 @@ def new_objc_provider( return apple_common.new_objc_provider(**kwargs) def register_link_binary_action( + *, actions, - additional_inputs, - additional_linking_contexts, + additional_inputs = [], + additional_linking_contexts = [], + additional_outputs = [], compilation_outputs, deps, feature_configuration, name, - module_contexts, + module_contexts = [], output_type, owner, stamp, swift_toolchain, - user_link_flags): + user_link_flags = [], + variables_extension = {}): """Registers an action that invokes the linker to produce a binary. Args: @@ -590,6 +593,8 @@ def register_link_binary_action( scripts, and so forth. additional_linking_contexts: Additional linking contexts that provide libraries or flags that should be linked into the executable. + additional_outputs: Additional files that are outputs of the linking + action but which are not among the return value of `cc_common.link`. compilation_outputs: A `CcCompilationOutputs` object containing object files that will be passed to the linker. deps: A list of targets representing additional libraries that will be @@ -611,6 +616,8 @@ def register_link_binary_action( user_link_flags: Additional flags passed to the linker. Any `$(location ...)` placeholders are assumed to have already been expanded. + variables_extension: A dictionary containing additional crosstool + variables that should be set for the linking action. Returns: A `CcLinkingOutputs` object that contains the `executable` or @@ -749,6 +756,7 @@ def register_link_binary_action( return cc_common.link( actions = actions, additional_inputs = additional_inputs, + additional_outputs = additional_outputs, cc_toolchain = swift_toolchain.cc_toolchain_info, compilation_outputs = compilation_outputs, feature_configuration = get_cc_feature_configuration( @@ -760,4 +768,5 @@ def register_link_binary_action( link_deps_statically = True, output_type = output_type, stamp = stamp, + variables_extension = variables_extension, ) diff --git a/swift/providers.bzl b/swift/providers.bzl index 99f87768b..e7f97f6f7 100644 --- a/swift/providers.bzl +++ b/swift/providers.bzl @@ -223,6 +223,16 @@ containing the fields described above, even if those lists are empty. "const_protocols_to_gather": """\ `File`. A JSON file specifying a list of protocols for extraction of conformances' const values. +""", + "debug_outputs_provider": """\ +An optional function that provides toolchain-specific logic around the handling +of additional debug outputs for `swift_binary` and `swift_test` targets. +If specified, this function must take the following keyword arguments: +* `ctx`: The rule context of the calling binary or test rule. +It must return a `struct` with the following fields: +* `additional_outputs`: Additional outputs expected from the linking action. +* `variables_extension`: A dictionary of additional crosstool variables to + pass to the linking action. """, "developer_dirs": """ A list of `structs` containing the following fields:\ diff --git a/swift/swift_binary.bzl b/swift/swift_binary.bzl index 567ac5f71..fcf6614bb 100644 --- a/swift/swift_binary.bzl +++ b/swift/swift_binary.bzl @@ -116,6 +116,17 @@ def _swift_binary_impl(ctx): additional_linking_contexts.append(malloc_linking_context(ctx)) + # Apply the optional debugging outputs extension if the toolchain defines + # one. + debug_outputs_provider = swift_toolchain.debug_outputs_provider + if debug_outputs_provider: + debug_extension = debug_outputs_provider(ctx = ctx) + additional_debug_outputs = debug_extension.additional_outputs + variables_extension = debug_extension.variables_extension + else: + additional_debug_outputs = [] + variables_extension = {} + if swift_common.is_enabled( feature_configuration = feature_configuration, feature_name = SWIFT_FEATURE_ADD_TARGET_NAME_TO_OUTPUT, @@ -128,6 +139,7 @@ def _swift_binary_impl(ctx): actions = ctx.actions, additional_inputs = ctx.files.swiftc_inputs, additional_linking_contexts = additional_linking_contexts, + additional_outputs = additional_debug_outputs, feature_configuration = feature_configuration, compilation_outputs = compilation_outputs, deps = ctx.attr.deps, @@ -142,11 +154,15 @@ def _swift_binary_impl(ctx): ctx.attr.linkopts, ctx.attr.swiftc_inputs, ) + ctx.fragments.cpp.linkopts, + variables_extension = variables_extension, ) return [ DefaultInfo( executable = linking_outputs.executable, + files = depset( + [linking_outputs.executable] + additional_debug_outputs, + ), runfiles = ctx.runfiles( collect_data = True, collect_default = True, diff --git a/swift/swift_test.bzl b/swift/swift_test.bzl index 2cb603d6d..ede3a350b 100644 --- a/swift/swift_test.bzl +++ b/swift/swift_test.bzl @@ -494,6 +494,17 @@ def _swift_test_impl(ctx): # Mach-O type `MH_BUNDLE` instead of `MH_EXECUTE`. extra_linkopts = ["-Wl,-bundle"] if is_bundled else [] + # Apply the optional debugging outputs extension if the toolchain defines + # one. + debug_outputs_provider = swift_toolchain.debug_outputs_provider + if debug_outputs_provider: + debug_extension = debug_outputs_provider(ctx = ctx) + additional_debug_outputs = debug_extension.additional_outputs + variables_extension = debug_extension.variables_extension + else: + additional_debug_outputs = [] + variables_extension = {} + if swift_common.is_enabled( feature_configuration = feature_configuration, feature_name = SWIFT_FEATURE_ADD_TARGET_NAME_TO_OUTPUT, @@ -506,6 +517,7 @@ def _swift_test_impl(ctx): actions = ctx.actions, additional_inputs = ctx.files.swiftc_inputs, additional_linking_contexts = additional_linking_contexts, + additional_outputs = additional_debug_outputs, compilation_outputs = compilation_outputs, deps = all_deps, feature_configuration = feature_configuration, @@ -520,6 +532,7 @@ def _swift_test_impl(ctx): ctx.attr.linkopts, ctx.attr.swiftc_inputs, ) + extra_linkopts + ctx.fragments.cpp.linkopts, + variables_extension = variables_extension, ) # If the tests are to be bundled, create the bundle and the test runner @@ -552,7 +565,10 @@ def _swift_test_impl(ctx): return [ DefaultInfo( executable = executable, - files = depset(direct = [executable] + additional_test_outputs), + files = depset( + [executable] + additional_test_outputs + + additional_debug_outputs, + ), runfiles = ctx.runfiles( collect_data = True, collect_default = True, diff --git a/swift/toolchains/swift_toolchain.bzl b/swift/toolchains/swift_toolchain.bzl index 64a8e2bbb..9f20d4a8c 100644 --- a/swift/toolchains/swift_toolchain.bzl +++ b/swift/toolchains/swift_toolchain.bzl @@ -519,6 +519,7 @@ def _swift_toolchain_impl(ctx): clang_implicit_deps_providers = ( collect_implicit_deps_providers([]) ), + debug_outputs_provider = None, developer_dirs = [], entry_point_linkopts_provider = _entry_point_linkopts_provider, feature_allowlists = [ diff --git a/swift/toolchains/xcode_swift_toolchain.bzl b/swift/toolchains/xcode_swift_toolchain.bzl index 53daaf376..0f91f48f2 100644 --- a/swift/toolchains/xcode_swift_toolchain.bzl +++ b/swift/toolchains/xcode_swift_toolchain.bzl @@ -630,6 +630,25 @@ def _entry_point_linkopts_provider(*, entry_point_name): linkopts = ["-Wl,-alias,_{},_main".format(entry_point_name)], ) +def _dsym_provider(*, ctx): + """Apple-specific linking extension to generate .dSYM binaries. + + This extension generates a minimal dSYM bundle that LLDB can find next to + the built binary. + """ + dsym_file = ctx.actions.declare_file( + "{name}.dSYM/Contents/Resources/DWARF/{name}".format( + name = ctx.label.name, + ), + ) + variables_extension = { + "dsym_path": dsym_file.path, + } + return struct( + additional_outputs = [dsym_file], + variables_extension = variables_extension, + ) + def _xcode_swift_toolchain_impl(ctx): cpp_fragment = ctx.fragments.cpp apple_toolchain = apple_common.apple_toolchain() @@ -778,6 +797,11 @@ def _xcode_swift_toolchain_impl(ctx): target[SwiftFeatureAllowlistInfo] for target in ctx.attr.feature_allowlists ], + debug_outputs_provider = ( + # This function unconditionally declares the output file, so we + # should only use it if a .dSYM is being requested during the build. + _dsym_provider if cpp_fragment.apple_generate_dsym else None + ), generated_header_module_implicit_deps_providers = ( collect_implicit_deps_providers( ctx.attr.generated_header_module_implicit_deps,