diff --git a/MODULE.bazel b/MODULE.bazel index 7353bed50..88328e745 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -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", diff --git a/README.md b/README.md index 85a1062a8..c462c4e89 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/swift/internal/linking.bzl b/swift/internal/linking.bzl index fe1b9ca02..d8460fd92 100644 --- a/swift/internal/linking.bzl +++ b/swift/internal/linking.bzl @@ -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). diff --git a/swift/internal/swift_autoconfiguration.bzl b/swift/internal/swift_autoconfiguration.bzl index 513964337..4d06d090a 100644 --- a/swift/internal/swift_autoconfiguration.bzl +++ b/swift/internal/swift_autoconfiguration.bzl @@ -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", @@ -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. @@ -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) @@ -306,6 +370,7 @@ swift_toolchain( for feature in feature_values ]), root = root, + toolchain_root = toolchain_root, version_file = version_file, ), ) @@ -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) @@ -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, diff --git a/swift/internal/swift_import.bzl b/swift/internal/swift_import.bzl index d51685ef0..2f8aaac03 100644 --- a/swift/internal/swift_import.bzl +++ b/swift/internal/swift_import.bzl @@ -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. diff --git a/swift/internal/swift_toolchain.bzl b/swift/internal/swift_toolchain.bzl index 423a97637..85ce19adf 100644 --- a/swift/internal/swift_toolchain.bzl +++ b/swift/internal/swift_toolchain.bzl @@ -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, @@ -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. diff --git a/swift/internal/xcode_swift_toolchain.bzl b/swift/internal/xcode_swift_toolchain.bzl index b7b2639ea..d0ddd24ad 100644 --- a/swift/internal/xcode_swift_toolchain.bzl +++ b/swift/internal/xcode_swift_toolchain.bzl @@ -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. diff --git a/swift/repositories.bzl b/swift/repositories.bzl index ca39896b2..72bd35522 100644 --- a/swift/repositories.bzl +++ b/swift/repositories.bzl @@ -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): @@ -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",