Generating C/C++ bindings in Rust is unfortunately still quite a hassle from my experience: Often C libraries end up with important functions as static inline in header files (these do not get translated automatically by bindgen). If the library uses the macro system to rename functions, these too won't show up as symbols in your library (so you'd have to manually define those names too). Then bindgen often pulls in too many dependencies and I end up manually white/blacklisting what symbols I want/don't want (and track changes through multiple versions). That being said, it's a hard problem and Rust has still one of the better toolings for FFI from what I've seen in other languages.
>This suggests a long-term compromise solution where threads within a process can use hyperthreading to share a core, but threads in different processes can't. Given that hyperthreads share L1 cache, this might also be better for performance.
Intuitively this may sound logical, however in practice it's often not the case. For many workloads putting two threads of the same program on a core ends up being worse than co-locating with threads from different programs. The reason is that two threads of the same program will often end up executing similar instruction streams (a really good example is when both are using vector instructions (these registers are shared between the two hyperthreads)).