[HN Gopher] CXX - Safe interop between Rust and C++
___________________________________________________________________
CXX - Safe interop between Rust and C++
Author : dgellow
Score : 121 points
Date : 2021-03-24 10:27 UTC (1 days ago)
(HTM) web link (github.com)
(TXT) w3m dump (github.com)
| dgellow wrote:
| Steve Klabnik published a blog post about this library (and some
| controversy surrounding it) a few months ago, "The CXX Debate":
| https://steveklabnik.com/writing/the-cxx-debate
| dtolnay wrote:
| This is outdated and does not apply to the library today. The
| resolution is discussed at the bottom of your link.
| steveklabnik wrote:
| I will edit the post to make this more prominent sometime
| soon :)
| abahlo wrote:
| Looks super great! Someone write this for Go please.
| The_rationalist wrote:
| Reminds me of https://github.com/bytedeco/javacpp
|
| _it maps naturally and efficiently many common features afforded
| by the C++ language and often considered problematic, including
| overloaded operators, class and function templates, callbacks
| through function pointers, function objects (aka functors),
| virtual functions and member function pointers, nested struct
| definitions, variable length arguments, nested namespaces, large
| data structures containing arbitrary cycles, virtual and multiple
| inheritance, passing /returning by value/reference/string/vector,
| anonymous unions, bit fields, exceptions, destructors and shared
| or unique pointers (via either try-with-resources or garbage
| collection), and documentation comments_
| IshKebab wrote:
| I use this. It's mostly excellent, though there are some awkward
| bits, e.g. you can't return `std::string` or `std::vector` by
| value from Rust to C++. You'll basically always end up with some
| degree of copying stuff.
|
| The build system is also confusing but I guess that's partly just
| because it's a really complicated thing to do.
|
| Still, beats doing it all by hand!
| dtolnay wrote:
| std::string and std::vector are not things that can exist by
| value in Rust, because it's possible for them to be implemented
| using internal pointers which are incompatible with how Rust
| does move semantics.
|
| Some easy and efficient ways to return a vector (or similarly
| string) from Rust to C++ which do not involve moving it around
| in Rust:
|
| 1. A signature like `fn f() -> UniquePtr<CxxVector<T>>` i.e. a
| return type of std::unique_ptr<std::vector<T>>, which is
| trivially Rust-movable
|
| 2. A signature like `fn f(out: Pin<&mut CxxVector<T>>)` with a
| stack-allocated empty vector constructed by C++ for your Rust
| to write the elements into, which is pinned and never moved by
| Rust
|
| 3. A signature like `fn f() -> Vec<T>` returning a Rust vector
| i.e. rust::Vec<T> on the C++ side; rust::Vec has a fleshed out
| API in C++ allowing it to be used like a C++ collection, with
| iteration and indexing etc
| zozbot234 wrote:
| There is a 'transfer' crate adding support for custom non-
| trivial moves of pinned objects, ala C++ move semantics.
| AIUI, support for "in-place" objects would also be needed,
| which is not yet part of Rust but there are plans to add it
| to the language.
| boris wrote:
| I wouldn't call (1) efficient, especially for std::string
| which itself might omit a dynamic allocation due to small
| string optimization.
| yazaddaruvala wrote:
| It might not be truly zero-cost, but as a safe FFI it is
| efficient. Meanwhile, does it really matter?
|
| For any C++ project to integrate Rust the motivation would
| have to be:
|
| - The Rust code is specifically needed for the long-term.
|
| - The FFI-boundary is temporary (i.e. always moving) as
| more of the C++ is migrated to Rust. Ideally, checkpointing
| the migration at optimal FFI boundaries. As such, any "in-
| efficient" checkpoint should be cleaned up "soon", and dev
| speed is more valuable from an FFI than perfectly zero-
| cost.
|
| - If for any reason a C++ project integrates Rust in a way
| that is permanently through an FFI (I can't understand why
| - maybe there is a really good crate or something), then
| the development costs to use the unsafe non-ergonomic FFI
| are worth the effort for this unique situation.
|
| Very similar logic applies for any Rust project that
| integrates with a C++ library for the long term. If the
| team just needs a C++ library for the short term, the
| efficiency likely also doesn't matter much.
| dtolnay wrote:
| > If for any reason a C++ project integrates Rust in a
| way that is permanently through an FFI, then the
| development costs to use the unsafe non-ergonomic FFI are
| worth the effort for this unique situation.
|
| I don't follow this train of thought; could you
| elaborate? Why would I want _more_ unsafe code in my
| project because it 's going to be there for longer? If
| anything I'd want the opposite -- longevity of the unsafe
| code being a reason _against_ wanting more of it sitting
| around. I am just not sure how "being worth the effort"
| to write more unsafe code factors in.
|
| FWIW the primary use case of CXX in my work codebase is
| in long term hybrid-Rust-C++ projects in which dozens of
| libraries using CXX (in both directions) are going to be
| around for many years.
| htfy96 wrote:
| The motivations in claims unfortunately don't apply to my
| case:
|
| 1. FFI boundary will likely to exist forever in a
| milions-of-line C++ codebase, especially when the
| behavior of this system is not possible to be formally
| specified / tested (e.g., depending on an unknown
| external system, or some behaviors specified in hundreds
| of pages "specs" full of jargons)
|
| 2. In the above case, when C++ code dominates the FFI
| cost would be signified as you need to call C++ routines
| frequently to achieve stuffs. For example, when every
| struct has some methods returning std::string the
| std::string needs to be targeted.
|
| In our case, the primary motivation of Rust isn't its
| safety - we just use it for syntax sugars and ease of
| extensions (with proc macros).
| yazaddaruvala wrote:
| > In our case, the primary motivation of Rust isn't its
| safety - we just use it for syntax sugars and ease of
| extensions (with proc macros).
|
| Fair enough, but then "CXX -- ***safe*** FFI between Rust
| and C++" (emphasis mine) is just not the right library
| for you, and that is totally ok. It has a niche and your
| usecase is different, both the library and your usecase
| are in "the right".
|
| > The motivations in claims unfortunately don't apply to
| my case:
|
| Is this situation different than what I called out
| earlier?
|
| > - If for any reason a C++ project integrates Rust in a
| way that is permanently through an FFI (I can't
| understand why - maybe there is a really good crate or
| something), then the development costs to use the unsafe
| non-ergonomic FFI are worth the effort for this unique
| situation.
| rvz wrote:
| > The build system is also confusing but I guess that's partly
| just because it's a really complicated thing to do.
|
| > Still, beats doing it all by hand!
|
| Still a pain to maintain, tweak and update your Rust project
| and cargo configs with your C++ code alongside a third party
| crate maintained by one person in the project. D lang is
| probably the only language that has this built into into the
| language.
|
| I'd rather go for a first party library with this support or
| C++ interop support built into the language like D.
| mhh__ wrote:
| D can even catch C++ exceptions on Linux (haven't tried it on
| Windows yet)
| lalaithion wrote:
| https://cxx.rs/binding/result.html
|
| You can also catch C++ exceptions (by turning them into the
| idiomatic Result type in Rust) using cxx.
| mhh__ wrote:
| That's cheating!
|
| https://d.godbolt.org/z/Ed65xMdj1
| vardump wrote:
| Might otherwise be a great idea (never tried D), but not very
| useful if you have to integrate Rust with C++.
| CodeMage wrote:
| In your opinion, as someone who has experience using it, can
| CXX make it easier to write Rust code that loads dynamically
| linked plugins (also written in Rust)? Sorry if the question is
| dumb, I started learning Rust only a month ago and one of the
| things I ran into is that Rust doesn't guarantee stable ABI.
| IshKebab wrote:
| Probably not. It's not really designed for that, and
| involving C++ when you don't need to is going to make it
| really complicated!
|
| I think you want something like this instead:
| https://crates.io/crates/abi_stable
| CodeMage wrote:
| Thanks! I didn't know about that one.
| ogoffart wrote:
| Another create which i've been contributing to and maintaining is
| the cpp crate, which can also be useful for interoperability with
| C++, as it allows to embed C++ code snippets directly within rust
| functions:
|
| https://github.com/mystor/rust-cpp
| gregwebs wrote:
| This looks amazing. I wish it existed for C as well: C is
| supported, but non-trivial C interaction is a lot of work with
| Rust. Actually I wish it existed for Rust (for dynamic loading of
| Rust libraries from Rust). Rust does not have a stable ABI and
| the stable_abi crate creates a lot of additional work. I am
| looking at using separate processes and using the shared_memory
| crate.
| afranchuk wrote:
| I agree I wish that would be nicer, but I've found the
| stable_abi crate to be quite convenient/easy for most
| situations. It is extra work, but with derive support it's
| often not too bad :)
| quotemstr wrote:
| One thing I've wanted to do for a while now is teach the Rust
| compiler to interop with C++ by actually invoking the C++
| compiler to specialize templates for Rust types.
| choeger wrote:
| I just glanced over it but if this does what it seems to do it is
| really a great piece of work.
|
| One of the biggest problems with typical FFIs is that they not
| only use the C-ABI but also at some point invoke some C-API so
| that the type safety features that both involved languages have,
| but C does not have, are normally lost at the boundary.
|
| Generating the C bindings from a description of the Rust and C++
| interface is a really neat idea.
|
| Now can this be used inside a standard C++ project? Could we
| write pieces of code in Rust to gradually augment a C++ library?
| nynx wrote:
| Yep! That's the intention I think.
___________________________________________________________________
(page generated 2021-03-25 23:01 UTC)