diff --git a/doc/rules.md b/doc/rules.md
index 7abeea80d..08dd995f2 100644
--- a/doc/rules.md
+++ b/doc/rules.md
@@ -41,8 +41,8 @@ On this page:
## swift_binary
-swift_binary(name, deps, srcs, data, copts, defines, env, linkopts, malloc, module_name,
- package_name, plugins, stamp, swiftc_inputs)
+swift_binary(name, deps, srcs, data, additional_linker_inputs, copts, defines, env, linkopts,
+ malloc, module_name, package_name, plugins, stamp, swiftc_inputs)
Compiles and links Swift code into an executable binary.
@@ -68,6 +68,7 @@ please use one of the platform-specific application rules in
| deps | A list of targets that are dependencies of the target being built, which will be linked into that target.
If the Swift toolchain supports implementation-only imports (`private_deps` on `swift_library`), then targets in `deps` are treated as regular (non-implementation-only) imports that are propagated both to their direct and indirect (transitive) dependents.
Allowed kinds of dependencies are:
* `swift_library` (or anything propagating `SwiftInfo`)
* `cc_library` and `objc_library` (or anything propagating `CcInfo`) | List of labels | optional | `[]` |
| srcs | A list of `.swift` source files that will be compiled into the library.
Except in very rare circumstances, a Swift source file should only appear in a single `swift_*` target. Adding the same source file to multiple `swift_*` targets can lead to binary bloat and/or symbol collisions. If specific sources need to be shared by multiple targets, consider factoring them out into their own `swift_library` instead. | List of labels | optional | `[]` |
| data | The list of files needed by this target at runtime.
Files and targets named in the `data` attribute will appear in the `*.runfiles` area of this target, if it has one. This may include data files needed by a binary or library, or other programs needed by it. | List of labels | optional | `[]` |
+| additional_linker_inputs | List of additional files needed by the linker.
These files will be passed to the linker when linking the binary target. Typically, these are linker scripts or other files referenced by `linkopts`. | List of labels | optional | `[]` |
| copts | Additional compiler options that should be passed to `swiftc`. These strings are subject to `$(location ...)` and ["Make" variable](https://docs.bazel.build/versions/master/be/make-variables.html) expansion. | List of strings | optional | `[]` |
| defines | A list of defines to add to the compilation command line.
Note that unlike C-family languages, Swift defines do not have values; they are simply identifiers that are either defined or undefined. So strings in this list should be simple identifiers, **not** `name=value` pairs.
Each string is prepended with `-D` and added to the command line. Unlike `copts`, these flags are added for the target and every target that depends on it, so use this attribute with caution. It is preferred that you add defines directly to `copts`, only using this feature in the rare case that a library needs to propagate a symbol up to those that depend on it. | List of strings | optional | `[]` |
| env | Specifies additional environment variables to set when the test is executed by `bazel run` or `bazel test`.
The values of these environment variables are subject to `$(location)` and "Make variable" substitution.
NOTE: The environment variables are not set when you run the target outside of Bazel (for example, by manually executing the binary in `bazel-bin/`). | Dictionary: String -> String | optional | `{}` |
@@ -85,8 +86,8 @@ please use one of the platform-specific application rules in
## swift_compiler_plugin
-swift_compiler_plugin(name, deps, srcs, data, copts, defines, linkopts, malloc, module_name,
- package_name, plugins, stamp, swiftc_inputs)
+swift_compiler_plugin(name, deps, srcs, data, additional_linker_inputs, copts, defines, linkopts,
+ malloc, module_name, package_name, plugins, stamp, swiftc_inputs)
Compiles and links a Swift compiler plugin (for example, a macro).
@@ -157,6 +158,7 @@ swift_library(
| deps | A list of targets that are dependencies of the target being built, which will be linked into that target.
If the Swift toolchain supports implementation-only imports (`private_deps` on `swift_library`), then targets in `deps` are treated as regular (non-implementation-only) imports that are propagated both to their direct and indirect (transitive) dependents.
Allowed kinds of dependencies are:
* `swift_library` (or anything propagating `SwiftInfo`)
* `cc_library` and `objc_library` (or anything propagating `CcInfo`) | List of labels | optional | `[]` |
| srcs | A list of `.swift` source files that will be compiled into the library.
Except in very rare circumstances, a Swift source file should only appear in a single `swift_*` target. Adding the same source file to multiple `swift_*` targets can lead to binary bloat and/or symbol collisions. If specific sources need to be shared by multiple targets, consider factoring them out into their own `swift_library` instead. | List of labels | optional | `[]` |
| data | The list of files needed by this target at runtime.
Files and targets named in the `data` attribute will appear in the `*.runfiles` area of this target, if it has one. This may include data files needed by a binary or library, or other programs needed by it. | List of labels | optional | `[]` |
+| additional_linker_inputs | List of additional files needed by the linker.
These files will be passed to the linker when linking the binary target. Typically, these are linker scripts or other files referenced by `linkopts`. | List of labels | optional | `[]` |
| copts | Additional compiler options that should be passed to `swiftc`. These strings are subject to `$(location ...)` and ["Make" variable](https://docs.bazel.build/versions/master/be/make-variables.html) expansion. | List of strings | optional | `[]` |
| defines | A list of defines to add to the compilation command line.
Note that unlike C-family languages, Swift defines do not have values; they are simply identifiers that are either defined or undefined. So strings in this list should be simple identifiers, **not** `name=value` pairs.
Each string is prepended with `-D` and added to the command line. Unlike `copts`, these flags are added for the target and every target that depends on it, so use this attribute with caution. It is preferred that you add defines directly to `copts`, only using this feature in the rare case that a library needs to propagate a symbol up to those that depend on it. | List of strings | optional | `[]` |
| linkopts | Additional linker options that should be passed to `clang`. These strings are subject to `$(location ...)` expansion. | List of strings | optional | `[]` |
@@ -921,8 +923,8 @@ swift_binary(
## swift_test
-swift_test(name, deps, srcs, data, copts, defines, discover_tests, env, env_inherit, linkopts,
- malloc, module_name, package_name, plugins, stamp, swiftc_inputs)
+swift_test(name, deps, srcs, data, additional_linker_inputs, copts, defines, discover_tests, env,
+ env_inherit, linkopts, malloc, module_name, package_name, plugins, stamp, swiftc_inputs)
Compiles and links Swift code into an executable test target.
@@ -996,6 +998,7 @@ root of your workspace (i.e. `$(SRCROOT)`).
| deps | A list of targets that are dependencies of the target being built, which will be linked into that target.
If the Swift toolchain supports implementation-only imports (`private_deps` on `swift_library`), then targets in `deps` are treated as regular (non-implementation-only) imports that are propagated both to their direct and indirect (transitive) dependents.
Allowed kinds of dependencies are:
* `swift_library` (or anything propagating `SwiftInfo`)
* `cc_library` and `objc_library` (or anything propagating `CcInfo`) | List of labels | optional | `[]` |
| srcs | A list of `.swift` source files that will be compiled into the library.
Except in very rare circumstances, a Swift source file should only appear in a single `swift_*` target. Adding the same source file to multiple `swift_*` targets can lead to binary bloat and/or symbol collisions. If specific sources need to be shared by multiple targets, consider factoring them out into their own `swift_library` instead. | List of labels | optional | `[]` |
| data | The list of files needed by this target at runtime.
Files and targets named in the `data` attribute will appear in the `*.runfiles` area of this target, if it has one. This may include data files needed by a binary or library, or other programs needed by it. | List of labels | optional | `[]` |
+| additional_linker_inputs | List of additional files needed by the linker.
These files will be passed to the linker when linking the binary target. Typically, these are linker scripts or other files referenced by `linkopts`. | List of labels | optional | `[]` |
| copts | Additional compiler options that should be passed to `swiftc`. These strings are subject to `$(location ...)` and ["Make" variable](https://docs.bazel.build/versions/master/be/make-variables.html) expansion. | List of strings | optional | `[]` |
| defines | A list of defines to add to the compilation command line.
Note that unlike C-family languages, Swift defines do not have values; they are simply identifiers that are either defined or undefined. So strings in this list should be simple identifiers, **not** `name=value` pairs.
Each string is prepended with `-D` and added to the command line. Unlike `copts`, these flags are added for the target and every target that depends on it, so use this attribute with caution. It is preferred that you add defines directly to `copts`, only using this feature in the rare case that a library needs to propagate a symbol up to those that depend on it. | List of strings | optional | `[]` |
| discover_tests | Determines whether or not tests are automatically discovered in the binary. The default value is `True`.
Tests are discovered in a platform-specific manner. On Apple platforms, they are found using the XCTest framework's `XCTestSuite.default` accessor, which uses the Objective-C runtime to dynamically discover tests. On non-Apple platforms, discovery uses symbol graphs generated from dependencies to find classes and methods written in XCTest's style.
If tests are discovered, then you should not provide your own `main` entry point in the `swift_test` binary; the test runtime provides the entry point for you. If you set this attribute to `False`, then you are responsible for providing your own `main`. This allows you to write tests that use a framework other than Apple's `XCTest`. The only requirement of such a test is that it terminate with a zero exit code for success or a non-zero exit code for failure. | Boolean | optional | `True` |
diff --git a/swift/internal/binary_attrs.bzl b/swift/internal/binary_attrs.bzl
index c25c4fd85..496362b7f 100644
--- a/swift/internal/binary_attrs.bzl
+++ b/swift/internal/binary_attrs.bzl
@@ -59,6 +59,16 @@ def binary_rule_attrs(
requires_srcs = False,
),
{
+ "additional_linker_inputs": attr.label_list(
+ allow_files = True,
+ doc = """\
+List of additional files needed by the linker.
+
+These files will be passed to the linker when linking the binary target.
+Typically, these are linker scripts or other files referenced by `linkopts`.
+""",
+ mandatory = False,
+ ),
"linkopts": attr.string_list(
doc = """\
Additional linker options that should be passed to `clang`. These strings are
diff --git a/swift/swift_binary.bzl b/swift/swift_binary.bzl
index 0ab84e193..92d0c93e7 100644
--- a/swift/swift_binary.bzl
+++ b/swift/swift_binary.bzl
@@ -157,7 +157,7 @@ def _swift_binary_impl(ctx):
binary_link_flags = expand_locations(
ctx,
ctx.attr.linkopts,
- ctx.attr.swiftc_inputs,
+ ctx.attr.additional_linker_inputs,
) + ctx.fragments.cpp.linkopts
# When linking the binary, make sure we use the correct entry point name.
@@ -178,7 +178,7 @@ def _swift_binary_impl(ctx):
linking_outputs = register_link_binary_action(
actions = ctx.actions,
- additional_inputs = ctx.files.swiftc_inputs,
+ additional_inputs = ctx.files.additional_linker_inputs,
additional_linking_contexts = additional_linking_contexts,
additional_outputs = additional_debug_outputs,
feature_configuration = feature_configuration,
@@ -228,7 +228,7 @@ def _swift_binary_impl(ctx):
environment = expand_locations(
ctx,
ctx.attr.env,
- ctx.attr.swiftc_inputs,
+ ctx.attr.swiftc_inputs + ctx.attr.additional_linker_inputs,
),
),
]
@@ -240,7 +240,7 @@ def _swift_binary_impl(ctx):
linking_context, _ = (
create_linking_context_from_compilation_outputs(
actions = ctx.actions,
- additional_inputs = ctx.files.swiftc_inputs,
+ additional_inputs = ctx.files.additional_linker_inputs,
alwayslink = True,
compilation_outputs = compilation_outputs,
feature_configuration = feature_configuration,
diff --git a/test/BUILD b/test/BUILD
index 35deeeb31..5929d0850 100644
--- a/test/BUILD
+++ b/test/BUILD
@@ -1,4 +1,5 @@
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
+load(":additional_linker_inputs_tests.bzl", "additional_linker_inputs_test_suite")
load(":ast_file_tests.bzl", "ast_file_test_suite")
load(":bzl_test.bzl", "bzl_test")
load(":cc_library_tests.bzl", "cc_library_test_suite")
@@ -30,6 +31,8 @@ load(":xctest_runner_tests.bzl", "xctest_runner_test_suite")
licenses(["notice"])
+additional_linker_inputs_test_suite(name = "additional_linker_inputs")
+
ast_file_test_suite(name = "ast_file")
cc_library_test_suite(name = "cc_library")
diff --git a/test/additional_linker_inputs_tests.bzl b/test/additional_linker_inputs_tests.bzl
new file mode 100644
index 000000000..316085132
--- /dev/null
+++ b/test/additional_linker_inputs_tests.bzl
@@ -0,0 +1,102 @@
+"""Tests for swift_binary's additional_linker_inputs attribute."""
+
+load("@bazel_skylib//lib:unittest.bzl", "analysistest", "unittest")
+
+def _swift_binary_additional_linker_inputs_test_impl(ctx):
+ env = analysistest.begin(ctx)
+
+ actions = analysistest.target_actions(env)
+ link_actions = [
+ action
+ for action in actions
+ if action.mnemonic == "CppLink"
+ ]
+
+ if not link_actions:
+ unittest.fail(
+ env,
+ "Expected to find a CppLink action but found none. Available actions: {}".format(
+ [action.mnemonic for action in actions],
+ ),
+ )
+ return analysistest.end(env)
+
+ if len(link_actions) != 1:
+ unittest.fail(
+ env,
+ "Expected exactly one CppLink action, but found {}".format(len(link_actions)),
+ )
+ return analysistest.end(env)
+
+ link_action = link_actions[0]
+
+ expected_inputs = ctx.attr.expected_additional_inputs
+ expected_linkopts = ctx.attr.expected_linkopts
+
+ action_input_paths = [input.short_path for input in link_action.inputs.to_list()]
+
+ if expected_inputs:
+ missing_inputs = [input for input in expected_inputs if input not in action_input_paths]
+ if missing_inputs:
+ unittest.fail(
+ env,
+ "Missing expected additional linker inputs: {}. Available inputs: {}".format(
+ sorted(missing_inputs),
+ sorted(action_input_paths),
+ ),
+ )
+
+ if expected_linkopts:
+ missing_linkopts = []
+ for expected_linkopt in expected_linkopts:
+ # Use substring match since -Wl, options may be grouped with other flags
+ found = False
+ for arg in link_action.argv:
+ if expected_linkopt in arg:
+ found = True
+ break
+ if not found:
+ missing_linkopts.append(expected_linkopt)
+
+ if missing_linkopts:
+ unittest.fail(
+ env,
+ "Missing expected linkopts: {}. Link arguments were: {}".format(
+ missing_linkopts,
+ link_action.argv,
+ ),
+ )
+
+ return analysistest.end(env)
+
+swift_binary_additional_linker_inputs_test = analysistest.make(
+ _swift_binary_additional_linker_inputs_test_impl,
+ attrs = {
+ "expected_additional_inputs": attr.string_list(),
+ "expected_linkopts": attr.string_list(),
+ },
+)
+
+def additional_linker_inputs_test_suite(name, tags = []):
+ all_tags = [name] + tags
+
+ swift_binary_additional_linker_inputs_test(
+ name = "{}_with_additional_inputs".format(name),
+ target_under_test = "//test/fixtures/linking:bin_with_additional_linker_inputs",
+ expected_additional_inputs = ["test/fixtures/linking/test_data.bin"],
+ expected_linkopts = ["-Wl,-sectcreate,__TEXT,__test_section"],
+ tags = all_tags,
+ )
+
+ swift_binary_additional_linker_inputs_test(
+ name = "{}_without_additional_inputs".format(name),
+ target_under_test = "//test/fixtures/linking:bin_without_additional_linker_inputs",
+ expected_additional_inputs = [],
+ expected_linkopts = [],
+ tags = all_tags,
+ )
+
+ native.test_suite(
+ name = name,
+ tags = all_tags,
+ )
diff --git a/test/fixtures/linking/BUILD b/test/fixtures/linking/BUILD
index bcac1f26a..ce641ef16 100644
--- a/test/fixtures/linking/BUILD
+++ b/test/fixtures/linking/BUILD
@@ -34,6 +34,29 @@ cc_binary(
deps = [":lib"],
)
+swift_binary(
+ name = "bin_with_additional_linker_inputs",
+ srcs = ["main.swift"],
+ additional_linker_inputs = ["test_data.bin"],
+ linkopts = [
+ "-Wl,-sectcreate,__TEXT,__test_section,$(execpath test_data.bin)",
+ ],
+ tags = FIXTURE_TAGS,
+)
+
+swift_binary(
+ name = "bin_with_empty_additional_linker_inputs",
+ srcs = ["main.swift"],
+ additional_linker_inputs = [],
+ tags = FIXTURE_TAGS,
+)
+
+swift_binary(
+ name = "bin_without_additional_linker_inputs",
+ srcs = ["main.swift"],
+ tags = FIXTURE_TAGS,
+)
+
bzl_library(
name = "fake_framework",
srcs = ["fake_framework.bzl"],
diff --git a/test/fixtures/linking/test_data.bin b/test/fixtures/linking/test_data.bin
new file mode 100644
index 000000000..21be3ad24
--- /dev/null
+++ b/test/fixtures/linking/test_data.bin
@@ -0,0 +1 @@
+TEST_DATA_FOR_ADDITIONAL_LINKER_INPUTS