diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock index e0f2c73f90cc..8deec32e3973 100644 --- a/MODULE.bazel.lock +++ b/MODULE.bazel.lock @@ -307,7 +307,7 @@ "moduleExtensions": { "//bazel/cc_toolchains:clang_configuration.bzl%clang_toolchain_extension": { "general": { - "bzlTransitiveDigest": "zlzuUB95ZT/0gx6Xy5Ercb4YiRyDEn9PzsoEcN6q2gk=", + "bzlTransitiveDigest": "DyUCJOgQYb+hGTTTtitbFytne29L1JZ2UsbwLpdkMKM=", "usagesDigest": "lTxkeAFhR0iBEa3dg5hWvtd2HFCr5zCJx/fl27A+IKA=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, diff --git a/bazel/cc_toolchains/carbon_cc_toolchain_config.bzl b/bazel/cc_toolchains/carbon_cc_toolchain_config.bzl index 4061c66c90b5..afb932f75ce6 100644 --- a/bazel/cc_toolchains/carbon_cc_toolchain_config.bzl +++ b/bazel/cc_toolchains/carbon_cc_toolchain_config.bzl @@ -143,10 +143,15 @@ def _carbon_cc_toolchain_config_impl(ctx): # Only use a sysroot if a non-trivial one is set in Carbon's config. builtin_sysroot = None sysroot_include_search = [] + sdk_settings = [] if clang_sysroot != "None" and clang_sysroot != "/": builtin_sysroot = clang_sysroot sysroot_include_search = ["%sysroot%/usr/include"] + # On MacOS, the compiler depends on this file at the root of the SDK, + # and it ends up in the `.d` files. + sdk_settings = ["%sysroot%/SDKSettings.json"] + runtimes_path = None if ctx.attr.runtimes: for f in ctx.files.runtimes: @@ -186,7 +191,7 @@ def _carbon_cc_toolchain_config_impl(ctx): "runtimes/libcxxabi/include", "{}/include".format(clang_resource_dir), "runtimes/clang_resource_dir/include", - ] + _compute_clang_system_include_dirs() + sysroot_include_search, + ] + _compute_clang_system_include_dirs() + sysroot_include_search + sdk_settings, builtin_sysroot = builtin_sysroot, # This configuration only supports local non-cross builds so derive diff --git a/bazel/cc_toolchains/cc_toolchain_cpp_features.bzl b/bazel/cc_toolchains/cc_toolchain_cpp_features.bzl index 44a243f4cb5e..d178d156c544 100644 --- a/bazel/cc_toolchains/cc_toolchain_cpp_features.bzl +++ b/bazel/cc_toolchains/cc_toolchain_cpp_features.bzl @@ -17,10 +17,49 @@ load( "preprocessor_compile_actions", ) +# Sysroots and MacOS are complicated: +# +# On Darwin/MacOS, the `-isysroot` flag is used for includes *and* libraries, +# and if specified it wins over `--sysroot` which would be used for libraries +# on other platforms. +# https://discourse.llvm.org/t/silly-what-is-the-difference-between-sysroot-and-isysroot/55788/2 +# +# Additionally, on a MacOS build of clang, the sysroot defaults to `/`, which +# is incorrect and it needs to be pointed to the SDK root. However, as a +# convenience, homebrew builds of clang automatically add `-isysroot` to the +# command line, so that the user doesn't have to. But the SDK it chooses does +# not always match the one returned from `xcrun --show-sdk-path`, which is the +# SDK that we want to use. So we need to override homebrew's choice and specify +# `-isysroot`. This will also supersede anything given to `--sysroot` (on +# Darwin) so we don't need to specify both. For non-homebrew clang builds on +# MacOS, specifying `-isysroot` will also work to point the compiler to the +# correct SDK instead of `--sysroot`. +_sysroot_flag_sets = [ + flag_set( + actions = ACTION_NAME_GROUPS.all_cc_compile_actions + ACTION_NAME_GROUPS.all_cc_link_actions, + flag_groups = [ + flag_group( + expand_if_available = "sysroot", + flags = ["--sysroot=%{sysroot}"], + ), + ], + with_features = [with_feature_set(not_features = ["macos_target"])], + ), + flag_set( + actions = ACTION_NAME_GROUPS.all_cc_compile_actions + ACTION_NAME_GROUPS.all_cc_link_actions, + flag_groups = [ + flag_group( + flags = ["-isysroot", "%{sysroot}"], + ), + ], + with_features = [with_feature_set(["macos_target"])], + ), +] + clang_feature = feature( name = "clang", enabled = True, - flag_sets = [ + flag_sets = _sysroot_flag_sets + [ flag_set( actions = ACTION_NAME_GROUPS.all_cc_compile_actions + ACTION_NAME_GROUPS.all_cc_link_actions, flag_groups = [ @@ -28,10 +67,6 @@ clang_feature = feature( "-no-canonical-prefixes", "-fcolor-diagnostics", ]), - flag_group( - expand_if_available = "sysroot", - flags = ["--sysroot=%{sysroot}"], - ), ], ), flag_set( diff --git a/bazel/cc_toolchains/clang_cc_toolchain_config.bzl b/bazel/cc_toolchains/clang_cc_toolchain_config.bzl index 913aac9fb05c..a2cbd311385b 100644 --- a/bazel/cc_toolchains/clang_cc_toolchain_config.bzl +++ b/bazel/cc_toolchains/clang_cc_toolchain_config.bzl @@ -28,9 +28,14 @@ load( def _impl(ctx): # Only use a sysroot if one was found when detecting Clang. sysroot = None + sdk_settings = [] if sysroot_dir != "None": sysroot = sysroot_dir + # On MacOS, the compiler depends on this file at the root of the SDK, + # and it ends up in the `.d` files. + sdk_settings = [sysroot_dir + "/SDKSettings.json"] + identifier = "local-{0}-{1}".format(ctx.attr.target_cpu, ctx.attr.target_os) return cc_common.create_cc_toolchain_config_info( ctx = ctx, @@ -41,7 +46,7 @@ def _impl(ctx): extra_cpp_features = [libcxx_feature(llvm_bindir, clang_bindir)], ), action_configs = llvm_action_configs(llvm_bindir, clang_bindir), - cxx_builtin_include_directories = clang_include_dirs + [ + cxx_builtin_include_directories = clang_include_dirs + sdk_settings + [ # Add Clang's resource directory to the end of the builtin include # directories to cover the use of sanitizer resource files by the # driver. diff --git a/bazel/cc_toolchains/clang_configuration.bzl b/bazel/cc_toolchains/clang_configuration.bzl index 958899ddb607..709937c1008e 100644 --- a/bazel/cc_toolchains/clang_configuration.bzl +++ b/bazel/cc_toolchains/clang_configuration.bzl @@ -152,7 +152,7 @@ def _compute_clang_cpp_include_search_paths(repository_ctx, clang, sysroot): if repository_ctx.os.name.lower().startswith("mac os"): if not sysroot: fail("Must provide a sysroot on macOS!") - cmd.append("--sysroot=" + sysroot) + cmd += ["-isysroot", sysroot] # Note that verbose output is on stderr, not stdout! output = _run(repository_ctx, cmd).stderr.splitlines()