Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion doc/rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ On this page:

<pre>
swift_binary(<a href="#swift_binary-name">name</a>, <a href="#swift_binary-deps">deps</a>, <a href="#swift_binary-srcs">srcs</a>, <a href="#swift_binary-data">data</a>, <a href="#swift_binary-additional_linker_inputs">additional_linker_inputs</a>, <a href="#swift_binary-copts">copts</a>, <a href="#swift_binary-defines">defines</a>, <a href="#swift_binary-env">env</a>, <a href="#swift_binary-linkopts">linkopts</a>,
<a href="#swift_binary-malloc">malloc</a>, <a href="#swift_binary-module_name">module_name</a>, <a href="#swift_binary-package_name">package_name</a>, <a href="#swift_binary-plugins">plugins</a>, <a href="#swift_binary-stamp">stamp</a>, <a href="#swift_binary-swiftc_inputs">swiftc_inputs</a>)
<a href="#swift_binary-linkshared">linkshared</a>, <a href="#swift_binary-malloc">malloc</a>, <a href="#swift_binary-module_name">module_name</a>, <a href="#swift_binary-package_name">package_name</a>, <a href="#swift_binary-plugins">plugins</a>, <a href="#swift_binary-stamp">stamp</a>, <a href="#swift_binary-swiftc_inputs">swiftc_inputs</a>)
</pre>

Compiles and links Swift code into an executable binary.
Expand All @@ -58,6 +58,9 @@ please use one of the platform-specific application rules in
[rules_apple](https://github.com/bazelbuild/rules_apple) instead of
`swift_binary`.

Setting `linkshared = True` links a shared library instead of an executable;
see the `linkshared` attribute.

**ATTRIBUTES**


Expand All @@ -72,6 +75,7 @@ please use one of the platform-specific application rules in
| <a id="swift_binary-defines"></a>defines | A list of defines to add to the compilation command line.<br><br>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.<br><br>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 | `[]` |
| <a id="swift_binary-env"></a>env | Specifies additional environment variables to set when the test is executed by `bazel run` or `bazel test`.<br><br>The values of these environment variables are subject to `$(location)` and "Make variable" substitution.<br><br>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/`). | <a href="https://bazel.build/rules/lib/dict">Dictionary: String -> String</a> | optional | `{}` |
| <a id="swift_binary-linkopts"></a>linkopts | Additional linker options that should be passed to `clang`. These strings are subject to `$(location ...)` expansion. | List of strings | optional | `[]` |
| <a id="swift_binary-linkshared"></a>linkshared | If `True`, link the target as a shared library / loadable module instead of an executable, similar to `cc_binary`'s `linkshared`. The binary has no `main` entry point and the renamed-entry-point machinery is disabled.<br><br>This produces a dynamic library named `lib<name>.so` (`.dylib` on Apple platforms) suitable for loading with `dlopen` / `System.loadLibrary` (e.g. an Android JNI library; export functions with `@_cdecl`). | Boolean | optional | `False` |
| <a id="swift_binary-malloc"></a>malloc | Override the default dependency on `malloc`.<br><br>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. | <a href="https://bazel.build/concepts/labels">Label</a> | optional | `"@bazel_tools//tools/cpp:malloc"` |
| <a id="swift_binary-module_name"></a>module_name | The name of the Swift module being built.<br><br>If left unspecified, the module name will be computed based on the target's build label, by stripping the leading `//` and replacing `/`, `:`, and other non-identifier characters with underscores. | String | optional | `""` |
| <a id="swift_binary-package_name"></a>package_name | The semantic package of the Swift target being built. Targets with the same package_name can access APIs using the 'package' access control modifier in Swift 5.9+. | String | optional | `""` |
Expand Down
11 changes: 11 additions & 0 deletions examples/xplatform/shared_library/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
load("//swift:swift_binary.bzl", "swift_binary")

licenses(["notice"])

# `linkshared` links a native dynamic library instead of an executable: a
# `.dylib` on Apple platforms or a `.so` on Linux.
swift_binary(
name = "shared_library",
srcs = ["greeting.swift"],
linkshared = True,
)
18 changes: 18 additions & 0 deletions examples/xplatform/shared_library/greeting.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright 2024 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.

@_cdecl("greeting")
public func greeting() -> Int32 {
return 42
}
7 changes: 7 additions & 0 deletions swift/internal/feature_names.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,13 @@ SWIFT_FEATURE_DECLARE_SWIFTSOURCEINFO = "swift.emit_swiftsourceinfo"
# system command line limit.
SWIFT_FEATURE_NO_EMBED_DEBUG_MODULE = "swift.no_embed_debug_module"

# If enabled, the entry point of a `swift_binary` is not renamed to a
# target-specific symbol (which is otherwise aliased back to `main` at link
# time so that the binary's code can also be linked into another binary, such
# as a test executable). Toolchains whose linkers cannot create such aliases
# (e.g. wasm-ld, which has no `--defsym`) should enable this feature.
SWIFT_FEATURE_NO_ENTRY_POINT_RENAME = "swift.no_entry_point_rename"

# If enabled, the toolchain will directly generate from the raw proto files
# and not from the DescriptorSets.
#
Expand Down
84 changes: 68 additions & 16 deletions swift/swift_binary.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

"""Implementation of the `swift_binary` rule."""

load("@bazel_skylib//lib:dicts.bzl", "dicts")
load("@bazel_skylib//lib:paths.bzl", "paths")
load("@rules_cc//cc/common:cc_common.bzl", "cc_common")
load("@rules_cc//cc/common:cc_info.bzl", "CcInfo")
Expand All @@ -22,6 +23,7 @@ load("//swift/internal:compiling.bzl", "compile")
load(
"//swift/internal:feature_names.bzl",
"SWIFT_FEATURE_ADD_TARGET_NAME_TO_OUTPUT",
"SWIFT_FEATURE_NO_ENTRY_POINT_RENAME",
)
load("//swift/internal:features.bzl", "is_feature_enabled")
load(
Expand Down Expand Up @@ -85,6 +87,15 @@ def _swift_binary_impl(ctx):
unsupported_features = ctx.disabled_features,
)

# A binary linked as a shared object (`linkshared`) has no `main`, so the
# entry-point rename (and the matching `--defsym main=...` at link time)
# must be skipped, just as it is when the toolchain requests it via
# `swift.no_entry_point_rename`.
skip_entry_point = ctx.attr.linkshared or is_feature_enabled(
feature_configuration = feature_configuration,
feature_name = SWIFT_FEATURE_NO_ENTRY_POINT_RENAME,
)

srcs = ctx.files.srcs
output_groups = {}
module_contexts = []
Expand All @@ -99,7 +110,21 @@ def _swift_binary_impl(ctx):
ctx.label,
feature_configuration = feature_configuration,
)
entry_point_name = entry_point_function_name(module_name)

if skip_entry_point:
entry_point_name = None
entry_point_copts = []
else:
# Use a custom entry point name so that the binary's code can
# also be linked into another process (like a test executable)
# without having its main function collide.
entry_point_name = entry_point_function_name(module_name)
entry_point_copts = [
"-Xfrontend",
"-entry-point-function-name",
"-Xfrontend",
entry_point_name,
]

include_dev_srch_paths = include_developer_search_paths(ctx.attr)

Expand All @@ -111,15 +136,7 @@ def _swift_binary_impl(ctx):
ctx,
ctx.attr.copts,
ctx.attr.swiftc_inputs,
) + _maybe_parse_as_library_copts(srcs) + [
# Use a custom entry point name so that the binary's code can
# also be linked into another process (like a test executable)
# without having its main function collide.
"-Xfrontend",
"-entry-point-function-name",
"-Xfrontend",
entry_point_name,
],
) + _maybe_parse_as_library_copts(srcs) + entry_point_copts,
defines = ctx.attr.defines,
feature_configuration = feature_configuration,
include_dev_srch_paths = include_dev_srch_paths,
Expand Down Expand Up @@ -178,6 +195,13 @@ def _swift_binary_impl(ctx):
else:
name = ctx.label.name

# `linkshared` produces a real dynamic library (`lib<name>.so` / `.dylib`),
# matching `cc_binary`'s `linkshared`; otherwise an executable.
if ctx.attr.linkshared:
output_type = "dynamic_library"
else:
output_type = "executable"

linking_outputs = register_link_binary_action(
actions = ctx.actions,
additional_inputs = ctx.files.additional_linker_inputs,
Expand All @@ -189,18 +213,27 @@ def _swift_binary_impl(ctx):
label = ctx.label,
module_contexts = module_contexts,
name = name,
output_type = "executable",
output_type = output_type,
stamp = ctx.attr.stamp,
toolchains = toolchains,
user_link_flags = binary_link_flags + entry_point_linkopts,
variables_extension = variables_extension,
)

if output_type == "dynamic_library":
library_to_link = linking_outputs.library_to_link
output_file = (
library_to_link.resolved_symlink_dynamic_library or
library_to_link.dynamic_library
)
else:
output_file = linking_outputs.executable

providers = [
DefaultInfo(
executable = linking_outputs.executable,
executable = output_file,
files = depset(
[linking_outputs.executable] + additional_debug_outputs,
[output_file] + additional_debug_outputs,
),
runfiles = ctx.runfiles(
collect_data = True,
Expand Down Expand Up @@ -278,9 +311,25 @@ def _swift_binary_impl(ctx):
return providers

swift_binary = rule(
attrs = binary_rule_attrs(
additional_deps_providers = [[SwiftCompilerPluginInfo]],
stamp_default = -1,
attrs = dicts.add(
binary_rule_attrs(
additional_deps_providers = [[SwiftCompilerPluginInfo]],
stamp_default = -1,
),
{
"linkshared": attr.bool(
default = False,
doc = """\
If `True`, link the target as a shared library / loadable module instead of an
executable, similar to `cc_binary`'s `linkshared`. The binary has no `main`
entry point and the renamed-entry-point machinery is disabled.

This produces a dynamic library named `lib<name>.so` (`.dylib` on Apple
platforms) suitable for loading with `dlopen` / `System.loadLibrary` (e.g. an
Android JNI library; export functions with `@_cdecl`).
""",
),
},
),
doc = """\
Compiles and links Swift code into an executable binary.
Expand All @@ -296,6 +345,9 @@ If you want to create a multi-architecture binary or a bundled application,
please use one of the platform-specific application rules in
[rules_apple](https://github.com/bazelbuild/rules_apple) instead of
`swift_binary`.

Setting `linkshared = True` links a shared library instead of an executable;
see the `linkshared` attribute.
""",
exec_groups = {
# The `plugins` attribute associates its `exec` transition with this
Expand Down
Loading