Skip to content

Commit

Permalink
Substitute ${SDKROOT} and ${DEVELOPER_DIR} by their environment v…
Browse files Browse the repository at this point in the history
…ariables on darwin.

This PR attempts to fix an issue with bindgen when used on darwin with clang
compiled from source (i.e. from `@llvm-project`).

When using clang compiled from source on darwin, libclang (used through `clang-sys`) failed
to find system header files (such as `stdarg.h` or `stdbool.h`) because these
files are actually living under the SDK path (under `<SDK_PATH>/System/Library/Frameworks/Kernel.framework/Versions/A/Headers/` and `<SDK_PATH>/usr/include`).

Similar to what Bazel did in their [`xcrunwrapper.sh`](https://github.com/bazelbuild/bazel/blob/d8c27bfcd37a74dfbf1bdb9a1e3df13af8360a01/tools/objc/xcrunwrapper.sh#L17), we must have a way to tell bindgen's libclang
where to find these system headers.

In this commit, I add the following two substitutes variables:
  - `${SDKROOT}`: replaced by `std::env::var("SDKROOT")` if found.
  - `${DEVELOPER_DIR}`: replaced by `std::env::var("DEVELOPER")` if found.

This is similar to what it is currently done for `${pwd}`.

The following rule should now work on darwin:

```c
// mylib.h
#include <stdarg.h>
```

```starlark
# BUILD
cc_library(
    name = "mylib",
    srcs = ["mylib.c"],
    hdrs = ["mylib.h"],
)

rust_bindgen_library(
    name = "mylib_bindgen",
    cc_lib = ":mylib",
    clang_flags = select({
        "@platforms//os:macos": [
            "--sysroot=${SDKROOT}",
            "-isystem${SDKROOT}/usr/include",
            "-isystem${SDKROOT}/System/Library/Frameworks/Kernel.framework/Versions/A/Headers/",
        ],
        "//conditions:default": [],
    }),
    crate_name = "mylib",
    header = "mylib.h",
)
```

It may also fix #1834.
  • Loading branch information
thb-sb committed Apr 18, 2024
1 parent 825aef9 commit 514706c
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 6 deletions.
20 changes: 18 additions & 2 deletions bindgen/private/bindgen.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,22 @@ def _rust_bindgen_impl(ctx):

args = ctx.actions.args()

executable = bindgen_bin

# When running on darwin, we have to forward the SDKROOT environment variable,
# otherwise some system include files may not be found if the clang compiled
# from source is being used.
# Since the sdk directory given by the apple toolchain[1] may be a dummy
# variable, we have to use the process_wrapper.
#
# [1]: https://bazel.build/rules/lib/builtins/apple_toolchain.html#sdk_dir
if apple_common != None:
args.add_all(["--subst", "SDKROOT=${SDKROOT}"])
args.add_all(["--subst", "DEVELOPER_DIR=${DEVELOPER_DIR}"])
args.add_all(["--", bindgen_bin])
tools = depset([bindgen_bin], transitive = [tools])
executable = ctx.executable._process_wrapper

# Configure Bindgen Arguments
args.add_all(ctx.attr.bindgen_flags)
args.add(header)
Expand Down Expand Up @@ -266,7 +282,7 @@ def _rust_bindgen_impl(ctx):
env["DYLD_LIBRARY_PATH"] = env["LD_LIBRARY_PATH"]

ctx.actions.run(
executable = bindgen_bin,
executable = executable,
inputs = depset(
[header],
transitive = [
Expand Down Expand Up @@ -359,7 +375,7 @@ rust_bindgen_toolchain = rule(
doc = """\
The tools required for the `rust_bindgen` rule.
This rule depends on the [`bindgen`](https://crates.io/crates/bindgen) binary crate, and it
This rule depends on the [`bindgen`](https://crates.io/crates/bindgen) binary crate, and it
in turn depends on both a clang binary and the clang library. To obtain these dependencies,
`rust_bindgen_dependencies` imports bindgen and its dependencies.
Expand Down
11 changes: 7 additions & 4 deletions util/process_wrapper/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,11 +138,14 @@ pub(crate) fn options() -> Result<Options, OptionError> {
OptionError::Generic(format!("empty key for substitution '{arg}'"))
})?;
let v = if val == "${pwd}" {
current_dir.as_str()
current_dir.as_str().to_owned()
} else if val == "${SDKROOT}" {
std::env::var("SDKROOT").unwrap_or(val.to_owned())
} else if val == "${DEVELOPER_DIR}" {
std::env::var("DEVELOPER_DIR").unwrap_or(val.to_owned())
} else {
val
}
.to_owned();
val.to_owned()
};
Ok((key.to_owned(), v))
})
.collect::<Result<Vec<(String, String)>, OptionError>>()?;
Expand Down

0 comments on commit 514706c

Please sign in to comment.