Skip to content

Commit

Permalink
rust: avoid assuming a particular bindgen build
Browse files Browse the repository at this point in the history
`bindgen`'s logic to find `libclang` (via `clang-sys`) may change over
time, and depends on how it was built (e.g. Linux distributions may decide
to build it differently, and we are going to provide documentation on
installing it via distributions later in this series).

Therefore, clarify that `bindgen` may be built in several ways and
simplify the documentation by only mentioning the most prominent
environment variable (`LIBCLANG_PATH`) as an example on how to tweak the
search of the library at runtime (i.e. when `bindgen` is built as our
documentation explains). This also avoids duplicating the documentation,
like `bindgen` itself does (i.e. it refers to `clang-sys`).

Similarly, replace the test we had for this (which used the real program)
with a mocked one, to avoid depending on the particular build as well.

Tested-by: Benno Lossin <benno.lossin@proton.me>
Tested-by: Andreas Hindborg <a.hindborg@samsung.com>
Link: https://lore.kernel.org/r/20240709160615.998336-8-ojeda@kernel.org
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
  • Loading branch information
ojeda authored and herrnst committed Sep 4, 2024
1 parent 5a00789 commit a3af3af
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 24 deletions.
23 changes: 9 additions & 14 deletions Documentation/rust/quick-start.rst
Original file line number Diff line number Diff line change
Expand Up @@ -113,20 +113,15 @@ Install it via (note that this will download and build the tool from source)::

cargo install --locked --version $(scripts/min-tool-version.sh bindgen) bindgen-cli

``bindgen`` needs to find a suitable ``libclang`` in order to work. If it is
not found (or a different ``libclang`` than the one found should be used),
the process can be tweaked using the environment variables understood by
``clang-sys`` (the Rust bindings crate that ``bindgen`` uses to access
``libclang``):

* ``LLVM_CONFIG_PATH`` can be pointed to an ``llvm-config`` executable.

* Or ``LIBCLANG_PATH`` can be pointed to a ``libclang`` shared library
or to the directory containing it.

* Or ``CLANG_PATH`` can be pointed to a ``clang`` executable.

For details, please see ``clang-sys``'s documentation at:
``bindgen`` uses the ``clang-sys`` crate to find a suitable ``libclang`` (which
may be linked statically, dynamically or loaded at runtime). By default, the
``cargo`` command above will produce a ``bindgen`` binary that will load
``libclang`` at runtime. If it is not found (or a different ``libclang`` than
the one found should be used), the process can be tweaked, e.g. by using the
``LIBCLANG_PATH`` environment variable. For details, please see ``clang-sys``'s
documentation at:

https://github.com/KyleMayes/clang-sys#linking

https://github.com/KyleMayes/clang-sys#environment-variables

Expand Down
25 changes: 15 additions & 10 deletions scripts/rust_is_available_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,15 @@ def generate_rustc(cls, stdout):

@classmethod
def generate_bindgen(cls, version_stdout, libclang_stderr):
if libclang_stderr is None:
libclang_case = f"raise SystemExit({cls.bindgen_default_bindgen_libclang_failure_exit_code})"
else:
libclang_case = f"print({repr(libclang_stderr)}, file=sys.stderr)"

return cls.generate_executable(f"""#!/usr/bin/env python3
import sys
if "rust_is_available_bindgen_libclang.h" in " ".join(sys.argv):
print({repr(libclang_stderr)}, file=sys.stderr)
{libclang_case}
else:
print({repr(version_stdout)})
""")
Expand All @@ -67,6 +72,10 @@ def generate_bindgen(cls, version_stdout, libclang_stderr):
def generate_bindgen_version(cls, stdout):
return cls.generate_bindgen(stdout, cls.bindgen_default_bindgen_libclang_stderr)

@classmethod
def generate_bindgen_libclang_failure(cls):
return cls.generate_bindgen(cls.bindgen_default_bindgen_version_stdout, None)

@classmethod
def generate_bindgen_libclang(cls, stderr):
return cls.generate_bindgen(cls.bindgen_default_bindgen_version_stdout, stderr)
Expand All @@ -89,6 +98,7 @@ def setUpClass(cls):
cls.rust_default_sysroot = subprocess.check_output(("rustc", "--print", "sysroot")).decode().strip()

cls.bindgen_default_bindgen_version_stdout = f"bindgen {cls.bindgen_default_version}"
cls.bindgen_default_bindgen_libclang_failure_exit_code = 42
cls.bindgen_default_bindgen_libclang_stderr = f"scripts/rust_is_available_bindgen_libclang.h:2:9: warning: clang version {cls.llvm_default_version} [-W#pragma-messages], err: false"

cls.default_rustc = cls.generate_rustc(f"rustc {cls.rustc_default_version}")
Expand Down Expand Up @@ -227,15 +237,10 @@ def test_bindgen_new_version(self):
self.assertIn(f"Rust bindings generator '{bindgen}' is too new. This may or may not work.", result.stderr)

def test_bindgen_libclang_failure(self):
for env in (
{ "LLVM_CONFIG_PATH": self.missing },
{ "LIBCLANG_PATH": self.missing },
{ "CLANG_PATH": self.missing },
):
with self.subTest(env=env):
result = self.run_script(self.Expected.FAILURE, env | { "PATH": os.environ["PATH"], "BINDGEN": "bindgen" })
self.assertIn("Running 'bindgen' to check the libclang version (used by the Rust", result.stderr)
self.assertIn("bindings generator) failed with code ", result.stderr)
bindgen = self.generate_bindgen_libclang_failure()
result = self.run_script(self.Expected.FAILURE, { "BINDGEN": bindgen })
self.assertIn(f"Running '{bindgen}' to check the libclang version (used by the Rust", result.stderr)
self.assertIn(f"bindings generator) failed with code {self.bindgen_default_bindgen_libclang_failure_exit_code}. This may be caused by", result.stderr)

def test_bindgen_libclang_unexpected_version(self):
bindgen = self.generate_bindgen_libclang("scripts/rust_is_available_bindgen_libclang.h:2:9: warning: clang version unexpected [-W#pragma-messages], err: false")
Expand Down

0 comments on commit a3af3af

Please sign in to comment.