Skip to content

Commit

Permalink
Configure LLVM cc_toolchain included with Swift releases
Browse files Browse the repository at this point in the history
  • Loading branch information
gferon committed Feb 13, 2024
1 parent df21d3f commit 0618c50
Show file tree
Hide file tree
Showing 8 changed files with 91 additions and 23 deletions.
1 change: 1 addition & 0 deletions MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ non_module_deps = use_extension("//swift:extensions.bzl", "non_module_deps")
use_repo(
non_module_deps,
"build_bazel_rules_swift_index_import",
"build_bazel_rules_swift_local_cc_config",
"build_bazel_rules_swift_local_config",
"com_github_apple_swift_log",
"com_github_apple_swift_nio",
Expand Down
11 changes: 0 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,17 +65,6 @@ also ensure that the Swift compiler is available on your system path.
Copy the `WORKSPACE` snippet from [the releases
page](https://github.com/bazelbuild/rules_swift/releases).

### 3. Additional configuration (Linux only)

The `swift_binary` and `swift_test` rules expect to use `clang` as the driver
for linking, and they query the Bazel C++ API and CROSSTOOL to determine which
arguments should be passed to the linker. By default, the C++ toolchain used by
Bazel is `gcc`, so Swift users on Linux need to override this by setting the
environment variable `CC=clang` when invoking Bazel.

This step is not necessary for macOS users because the Xcode toolchain always
uses `clang`.

## Building with Custom Toolchains

**macOS hosts:** You can build with a custom Swift toolchain (downloaded
Expand Down
2 changes: 1 addition & 1 deletion swift/internal/linking.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ into the binary. Possible values are:
# Do not add references; temporary attribute for C++ toolchain
# Starlark migration.
"_cc_toolchain": attr.label(
default = Label("@bazel_tools//tools/cpp:current_cc_toolchain"),
default = Label("@build_bazel_rules_swift_local_cc_config//:toolchain"),
),
# A late-bound attribute denoting the value of the `--custom_malloc`
# command line flag (or None if the flag is not provided).
Expand Down
83 changes: 80 additions & 3 deletions swift/internal/swift_autoconfiguration.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ should be loaded here. Do not load anything else, even common libraries like
Skylib.
"""

load("@bazel_tools//tools/cpp:unix_cc_configure.bzl", "configure_unix_toolchain")
load("@bazel_tools//tools/cpp:windows_cc_configure.bzl", "configure_windows_toolchain")
load(
"@bazel_tools//tools/cpp:lib_cc_configure.bzl",
"get_cpu_value",
)
load(
"@build_bazel_rules_swift//swift/internal:feature_names.bzl",
"SWIFT_FEATURE_CODEVIEW_DEBUG_INFO",
Expand Down Expand Up @@ -256,6 +262,63 @@ def _normalized_linux_cpu(cpu):
return "x86_64"
return cpu

def _toolchain_root(repository_ctx):
path_to_swiftc = repository_ctx.which("swiftc")
if not path_to_swiftc:
fail("No 'swiftc' executable found in $PATH")
return path_to_swiftc.dirname

def _create_xcode_cc_toolchain(repository_ctx):
"""Creates BUILD alias for the C++ toolchain provided by apple_support
Args:
repository_ctx: The repository rule context.
"""

repository_ctx.file("BUILD", """
alias(
name = "toolchain",
actual = "@local_config_apple_cc//:toolchain",
visibility = ["//visibility:public"]
)
""")

def _toolchain_overriden_tools(toolchain_root, extension = ""):
tools = {
"ld": toolchain_root.get_child("lld" + extension),
"llvm-cov": toolchain_root.get_child("llvm-cov" + extension),
"llvm-profdata": toolchain_root.get_child("llvm-profdata" + extension),
"cpp": toolchain_root.get_child("clang-cpp" + extension),
"gcc": toolchain_root.get_child("clang" + extension),
}

# llvm-ar is not shipped before Swift 5.8
ar = toolchain_root.get_child("llvm-ar" + extension)
if ar.exists:
tools["ar"] = ar
return tools

def _create_linux_cc_toolchain(repository_ctx):
"""Creates BUILD targets for the Swift-provided C++ toolchain on Linux.
Args:
repository_ctx: The repository rule context.
"""

toolchain_root = _toolchain_root(repository_ctx)
cpu = get_cpu_value(repository_ctx)
configure_unix_toolchain(repository_ctx, cpu, overriden_tools = _toolchain_overriden_tools(toolchain_root))

def _create_windows_cc_toolchain(repository_ctx):
"""Creates BUILD targets for the Swift-provided C++ toolchain on Windows.
Args:
repository_ctx: The repository rule context.
"""

toolchain_root = _toolchain_root(repository_ctx)
configure_windows_toolchain(repository_ctx, overriden_tools = _toolchain_overriden_tools(toolchain_root, ".exe"))

def _create_linux_toolchain(repository_ctx):
"""Creates BUILD targets for the Swift toolchain on Linux.
Expand All @@ -266,6 +329,7 @@ def _create_linux_toolchain(repository_ctx):
if not path_to_swiftc:
fail("No 'swiftc' executable found in $PATH")

toolchain_root = _toolchain_root(repository_ctx)
root = path_to_swiftc.dirname.dirname
feature_values = _compute_feature_values(repository_ctx, path_to_swiftc)
version_file = _write_swift_version(repository_ctx, path_to_swiftc)
Expand Down Expand Up @@ -306,6 +370,7 @@ swift_toolchain(
for feature in feature_values
]),
root = root,
toolchain_root = toolchain_root,
version_file = version_file,
),
)
Expand Down Expand Up @@ -421,10 +486,16 @@ swift_toolchain(
),
)

def _swift_cc_autoconfiguration_impl(repository_ctx):
os_name = repository_ctx.os.name.lower()
if os_name.startswith("mac os"):
_create_xcode_cc_toolchain(repository_ctx)
elif os_name.startswith("windows"):
_create_windows_cc_toolchain(repository_ctx)
else:
_create_linux_cc_toolchain(repository_ctx)

def _swift_autoconfiguration_impl(repository_ctx):
# TODO(allevato): This is expedient and fragile. Use the
# platforms/toolchains APIs instead to define proper toolchains, and make it
# possible to support non-Xcode toolchains on macOS as well.
os_name = repository_ctx.os.name.lower()
if os_name.startswith("mac os"):
_create_xcode_toolchain(repository_ctx)
Expand All @@ -433,6 +504,12 @@ def _swift_autoconfiguration_impl(repository_ctx):
else:
_create_linux_toolchain(repository_ctx)

swift_cc_autoconfiguration = repository_rule(
environ = ["PATH"],
implementation = _swift_cc_autoconfiguration_impl,
local = True,
)

swift_autoconfiguration = repository_rule(
environ = ["CC", "PATH", "ProgramData", "Path"],
implementation = _swift_autoconfiguration_impl,
Expand Down
2 changes: 1 addition & 1 deletion swift/internal/swift_import.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ The `.swiftmodule` file provided to Swift targets that depend on this target.
mandatory = False,
),
"_cc_toolchain": attr.label(
default = Label("@bazel_tools//tools/cpp:current_cc_toolchain"),
default = Label("@build_bazel_rules_swift_local_cc_config//:toolchain"),
doc = """\
The C++ toolchain from which linking flags and other tools needed by the Swift
toolchain (such as `clang`) will be retrieved.
Expand Down
7 changes: 1 addition & 6 deletions swift/internal/swift_toolchain.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -274,11 +274,6 @@ def _swift_toolchain_impl(ctx):
toolchain_root = ctx.attr.root
cc_toolchain = find_cpp_toolchain(ctx)

if "clang" not in cc_toolchain.compiler:
fail("Swift requires the configured CC toolchain to be LLVM (clang). " +
"Either use the locally installed LLVM by setting `CC=clang` in your environment " +
"before invoking Bazel, or configure a Bazel LLVM CC toolchain.")

if ctx.attr.os == "windows":
swift_linkopts_cc_info = _swift_windows_linkopts_cc_info(
ctx.attr.arch,
Expand Down Expand Up @@ -450,7 +445,7 @@ configuration options that are applied to targets on a per-package basis.
allow_single_file = True,
),
"_cc_toolchain": attr.label(
default = Label("@bazel_tools//tools/cpp:current_cc_toolchain"),
default = Label("@build_bazel_rules_swift_local_cc_config//:toolchain"),
doc = """\
The C++ toolchain from which other tools needed by the Swift toolchain (such as
`clang` and `ar`) will be retrieved.
Expand Down
2 changes: 1 addition & 1 deletion swift/internal/xcode_swift_toolchain.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -800,7 +800,7 @@ configuration options that are applied to targets on a per-package basis.
providers = [[SwiftPackageConfigurationInfo]],
),
"_cc_toolchain": attr.label(
default = Label("@bazel_tools//tools/cpp:current_cc_toolchain"),
default = Label("@build_bazel_rules_swift_local_cc_config//:toolchain"),
doc = """\
The C++ toolchain from which linking flags and other tools needed by the Swift
toolchain (such as `clang`) will be retrieved.
Expand Down
6 changes: 6 additions & 0 deletions swift/repositories.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
load(
"@build_bazel_rules_swift//swift/internal:swift_autoconfiguration.bzl",
"swift_autoconfiguration",
"swift_cc_autoconfiguration",
)

def _maybe(repo_rule, name, **kwargs):
Expand Down Expand Up @@ -191,6 +192,11 @@ def swift_rules_dependencies(include_bzlmod_ready_dependencies = True):
sha256 = "28c1ffa39d99e74ed70623899b207b41f79214c498c603915aef55972a851a15",
)

_maybe(
swift_cc_autoconfiguration,
name = "build_bazel_rules_swift_local_cc_config",
)

_maybe(
swift_autoconfiguration,
name = "build_bazel_rules_swift_local_config",
Expand Down

0 comments on commit 0618c50

Please sign in to comment.