diff --git a/swift/internal/linking.bzl b/swift/internal/linking.bzl index 3b787127c..ce52e4262 100644 --- a/swift/internal/linking.bzl +++ b/swift/internal/linking.bzl @@ -141,6 +141,7 @@ def register_libraries_to_link( def register_link_executable_action( actions, action_environment, + additional_linking_contexts, cc_feature_configuration, clang_executable, deps, @@ -158,6 +159,8 @@ def register_link_executable_action( actions: The object used to register actions. action_environment: A `dict` of environment variables that should be set for the compile action. + additional_linking_contexts: Additional linking contexts that provide libraries or flags + that should be linked into the executable. cc_feature_configuration: The C++ feature configuration to use when constructing the action. clang_executable: The path to the `clang` executable that will be invoked to link, which is @@ -188,17 +191,6 @@ def register_link_executable_action( deps_libraries = [] - if swift_toolchain.stamp: - stamp_libs_to_link = [] - for library in swift_toolchain.stamp[CcInfo].linking_context.libraries_to_link: - if library.pic_static_library: - stamp_libs_to_link.append(library.pic_static_library) - elif library.static_library: - stamp_libs_to_link.append(library.static_library) - - if stamp_libs_to_link: - deps_libraries.extend(stamp_libs_to_link) - additional_input_depsets = [] all_linkopts = list(expanded_linkopts) deps_dynamic_framework_names = [] @@ -239,6 +231,15 @@ def register_link_executable_action( deps_sdk_dylibs.append(objc.sdk_dylib) deps_sdk_frameworks.append(objc.sdk_framework) + for linking_context in additional_linking_contexts: + additional_input_depsets.append(linking_context.additional_inputs) + all_linkopts.extend(linking_context.user_link_flags) + for library in linking_context.libraries_to_link: + if library.pic_static_library: + deps_libraries.append(library.pic_static_library) + elif library.static_library: + deps_libraries.append(library.static_library) + libraries = depset(deps_libraries, order = "topological") link_input_depsets = [ libraries, diff --git a/swift/internal/providers.bzl b/swift/internal/providers.bzl index 4d20fe5d8..839b1e4c3 100644 --- a/swift/internal/providers.bzl +++ b/swift/internal/providers.bzl @@ -145,9 +145,26 @@ they are also passed to the C++ APIs used when linking (so features defined in C here). """, "root_dir": "`String`. The workspace-relative root directory of the toolchain.", - "stamp": """ -`Target`. A `CcInfo`-providing target that should be linked into any binaries that are built with -stamping enabled. + "stamp_producer": """ +Skylib `partial`. A partial function that compiles build data that should be stamped into binaries. +This value may be `None` if the toolchain does not support link stamping. + +The `swift_binary` and `swift_test` rules call this function _whether or not_ link stamping is +enabled for that target. This provides toolchains the option of still linking fixed placeholder +data into the binary if desired, instead of linking nothing at all. Whether stamping is enabled can +be checked by inspecting `ctx.attr.stamp` inside the partial's implementation. + +The rule implementation will call this partial and pass it the following four arguments: + +* `ctx`: The rule context of the target being built. +* `cc_feature_configuration`: The C++ feature configuration to use when compiling the stamp + code. +* `cc_toolchain`: The C++ toolchain (`CcToolchainInfo` provider) to use when compiling the + stamp code. +* `binary`: The `File` object representing the binary being linked. + +The partial should return a `CcLinkingContext` containing the data (such as object files) to be +linked into the binary, or `None` if nothing should be linked into the binary. """, "supports_objc_interop": """ `Boolean`. Indicates whether or not the toolchain supports Objective-C interop. diff --git a/swift/internal/swift_binary_test.bzl b/swift/internal/swift_binary_test.bzl index 2d5561caf..532d4d1c6 100644 --- a/swift/internal/swift_binary_test.bzl +++ b/swift/internal/swift_binary_test.bzl @@ -25,33 +25,55 @@ load(":non_swift_target_aspect.bzl", "non_swift_target_aspect") load(":providers.bzl", "SwiftToolchainInfo") load(":utils.bzl", "expand_locations") -# Attributes common to both `swift_binary` and `swift_test`. -_BINARY_RULE_ATTRS = dicts.add( - swift_common.compilation_attrs(additional_deps_aspects = [non_swift_target_aspect]), - { - "linkopts": attr.string_list( - doc = """ +def _binary_rule_attrs(stamp_default): + """Returns the dictionary of attributes common to both `swift_binary` and `swift_test`. + + Args: + stamp_default: The default value of the `stamp` attribute. + + Returns: + A `dict` of attributes for a binary or test rule. + """ + return dicts.add( + swift_common.compilation_attrs(additional_deps_aspects = [non_swift_target_aspect]), + { + "linkopts": attr.string_list( + doc = """ Additional linker options that should be passed to `clang`. These strings are subject to `$(location ...)` expansion. """, - mandatory = False, - ), - "malloc": attr.label( - default = Label("@bazel_tools//tools/cpp:malloc"), - doc = """ + mandatory = False, + ), + "malloc": attr.label( + default = Label("@bazel_tools//tools/cpp:malloc"), + doc = """ Override the default dependency on `malloc`. By default, Swift binaries are linked against `@bazel_tools//tools/cpp:malloc"`, which is an empty library and the resulting binary will use libc's `malloc`. This label must refer to a `cc_library` rule. """, - mandatory = False, - providers = [[CcInfo]], - ), - # Do not add references; temporary attribute for C++ toolchain Skylark migration. - "_cc_toolchain": attr.label(default = Label("@bazel_tools//tools/cpp:current_cc_toolchain")), - }, -) + mandatory = False, + providers = [[CcInfo]], + ), + "stamp": attr.bool( + default = stamp_default, + doc = """ +Enable or disable link stamping. + +If this value is true (and if the toolchain supports link stamping), then the toolchain's stamping +logic will be invoked to link additional identifying information into the binary. This information +typically comes from the stable and volatile build information written by Bazel in the output +directory, but could be anything that the toolchain wishes to link into binaries. + +If false, no stamp information will be linked into the binary, which improves build caching. +""", + mandatory = False, + ), + # Do not add references; temporary attribute for C++ toolchain Skylark migration. + "_cc_toolchain": attr.label(default = Label("@bazel_tools//tools/cpp:current_cc_toolchain")), + }, + ) def _configure_features_for_binary(ctx, requested_features = [], unsupported_features = []): """Creates and returns the feature configuration for binary linking. @@ -184,9 +206,22 @@ def _swift_linking_rule_impl( if ctx.attr.malloc: deps_to_link.append(ctx.attr.malloc) + additional_linking_contexts = [] + if swift_toolchain.stamp_producer: + stamp_context = partial.call( + swift_toolchain.stamp_producer, + ctx, + cc_feature_configuration, + swift_toolchain.cc_toolchain_info, + out_bin, + ) + if stamp_context: + additional_linking_contexts.append(stamp_context) + register_link_executable_action( actions = ctx.actions, action_environment = swift_toolchain.action_environment, + additional_linking_contexts = additional_linking_contexts, cc_feature_configuration = cc_feature_configuration, clang_executable = swift_toolchain.clang_executable, deps = deps_to_link, @@ -329,7 +364,7 @@ def _swift_test_impl(ctx): ] swift_binary = rule( - attrs = _BINARY_RULE_ATTRS, + attrs = _binary_rule_attrs(stamp_default = True), doc = """ Compiles and links Swift code into an executable binary. @@ -357,7 +392,7 @@ instead of `swift_binary`. swift_test = rule( attrs = dicts.add( - _BINARY_RULE_ATTRS, + _binary_rule_attrs(stamp_default = False), { "_apple_coverage_support": attr.label( cfg = "host", diff --git a/swift/internal/swift_toolchain.bzl b/swift/internal/swift_toolchain.bzl index 574ba64ae..9ab4a829d 100644 --- a/swift/internal/swift_toolchain.bzl +++ b/swift/internal/swift_toolchain.bzl @@ -122,7 +122,7 @@ def _swift_toolchain_impl(ctx): object_format = "elf", requested_features = requested_features, root_dir = toolchain_root, - stamp = ctx.attr.stamp, + stamp_producer = None, supports_objc_interop = False, swiftc_copts = [], swift_worker = ctx.executable._worker, @@ -162,13 +162,6 @@ content, such as "linux" in "lib/swift/linux". "root": attr.string( mandatory = True, ), - "stamp": attr.label( - doc = """ -A `CcInfo`-providing target that should be linked into any binaries that are built with stamping -enabled. -""", - providers = [[CcInfo]], - ), "_cc_toolchain": attr.label( default = Label("@bazel_tools//tools/cpp:current_cc_toolchain"), doc = """ diff --git a/swift/internal/xcode_swift_toolchain.bzl b/swift/internal/xcode_swift_toolchain.bzl index 4e6c49048..ab10aca06 100644 --- a/swift/internal/xcode_swift_toolchain.bzl +++ b/swift/internal/xcode_swift_toolchain.bzl @@ -328,7 +328,7 @@ def _xcode_swift_toolchain_impl(ctx): object_format = "macho", requested_features = requested_features, root_dir = None, - stamp = ctx.attr.stamp if _is_macos(platform) else None, + stamp_producer = None, supports_objc_interop = True, swiftc_copts = swiftc_copts, swift_worker = ctx.executable._worker, @@ -342,13 +342,6 @@ def _xcode_swift_toolchain_impl(ctx): xcode_swift_toolchain = rule( attrs = dicts.add({ - "stamp": attr.label( - doc = """ -A `CcInfo`-providing target that should be linked into any binaries that are built with stamping -enabled. -""", - providers = [[CcInfo]], - ), "_cc_toolchain": attr.label( default = Label("@bazel_tools//tools/cpp:current_cc_toolchain"), doc = """