commit | 851a6418373bfa10c9a6ce097cac6198cd422822 | [log] [tgz] |
---|---|---|
author | Devin Jeanpierre <jeanpierreda@google.com> | Thu Apr 13 14:38:14 2023 -0700 |
committer | Copybara-Service <copybara-worker@google.com> | Thu Apr 13 14:38:42 2023 -0700 |
tree | 3bc22136d42c3afcc4ed4e91c8f86641355be60a | |
parent | 861697a08418b39904d06a076834496633244a20 [diff] |
Fully implement "soft" bindings generation failures. After this CL, you can disable bindings generation for a target (or even, in theory, an individual item), and it will not break the build if non-disabled items/targets use the disabled item in their public API. Instead: 1. Aliases which alias a disabled type will themselves be disabled, and not receive bindings. 2. Structs which reference a disabled type will replace it with an opaque blob of bytes in their layout. 3. Functions which reference a disabled type will not receive bindings. The implementation shows, a little bit, why it's annoying to do this as a separate function to the side: we need to replicate the logic for generating _bindings_ for aliases inside the logic for testing if aliases are disabled, so as to avoid the cyclic dependency, per previous CL. Ah, well. --- Quick note: one alternative design is to instead do feature checks in C++, and not emit them into the IR at all if they don't pass a feature check. That is simpler, but means writing more C++ code, and means we can't call Rust query functions. For example, if `rs_type_kind` fails for reasons not accounted for in C++, this allows aliases to fail gracefully. If the check were in C++, we'd continue to have a point of no return that leads to crashes. However, more importantly, by doing this in Rust we are deliberately introducing more resiliency into `src_code_gen.rs`, and allowing it to succeed on more inputs without crashing entirely. In particular, doing it this way forced us to handle recoverable failures in TypeAlias. And doing it this way gave us the general mechanism with which to do it. So overall I'm strongly in favor of this approach. We have had a bit of a mixed approach wrt error handling and when toc rash, and I think this CL starts painting a clearer picture by clearly delineating recoverable and non-recoverable errors. ### TODO: Now that this is done, I'm finally unblocked on implementing and testing that template instantiation should be suppressed when the template definition is suppressed. ### Other changes In order to make this work nicely, I ended up fixing a longstanding want-to-fix of showing nested causes in bindings error messages. That's just a matter of using `{:#}` instead of `{}` when formatting the error. So now, recoverable failures show the full cause chain, and in particular, we get nice cause chains like: ``` Failed to format type of parameter 0: Missing required features on //test:dependency: [//third_party/crubit:experimental] ``` Also, this now formats the error reason for `[[no_unique_address]]` fields, which previously were omitted due to slightly different branching code. PiperOrigin-RevId: 524106254
Crubit is an experimental bidirectional bindings generator for C++ and Rust.
Please don‘t use, this is an experiment and we don’t yet know where will it take us. There will be breaking changes without warning. Unfortunately, we can't take contributions at this point.
Crubit allows for C++ code and Rust code to call each other without manually wrapping the APIs in an FFI-friendly interop layer. For example, a C++ function like this:
bool IsAbsPath(std::string_view path);
... becomes callable from Rust as if it were defined as:
pub fn IsAbsPath(path: std::string_view) -> bool {...}
Crubit automatically generates ABI-compatible bindings for structs (which can be passed both by value and by reference), functions, and methods, for a large variety of types. (Trivial types, nontrivial types, templated types, etc.)
$ apt install clang lld bazel $ git clone git@github.com:google/crubit.git $ cd crubit $ bazel build --linkopt=-fuse-ld=/usr/bin/ld.lld //rs_bindings_from_cc:rs_bindings_from_cc_impl
$ git clone https://github.com/llvm/llvm-project $ cd llvm-project $ CC=clang CXX=clang++ cmake -S llvm -B build -DLLVM_ENABLE_PROJECTS='clang' -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=install $ cmake --build build -j $ # wait... $ cmake --install build $ cd ../crubit $ LLVM_INSTALL_PATH=../llvm-project/install bazel build //rs_bindings_from_cc:rs_bindings_from_cc_impl