
Rust once, run everywhere - steveklabnik
http://blog.rust-lang.org/2015/04/24/Rust-Once-Run-Everywhere.html
======
comex
Not sure why this post doesn't mention it, but for nontrivially sized C APIs,
you don't have to convert the function signatures to Rust manually; instead
you can use rust-bindgen:

[https://github.com/crabtw/rust-bindgen](https://github.com/crabtw/rust-
bindgen)

(Caveat: I think it would need to be fixed up to avoid unstable APIs in order
to run on stable releases of Rust, as opposed to nightlies.)

~~~
minthd
Interesting. Can rust-bindgen support object oriented c?

~~~
comex
Not sure what you mean by "object oriented C". It doesn't support C++
presently (something I'd love to see improved); there are some projects that
do Objective-C interop; if you just mean C that uses structs in an OO-like
way, it shouldn't be that different from any other C.

~~~
minthd
Yes, when using structs in an OO like way. Does it generate c-style rust
wrapper ? or can it generate class-based rust wrapper ,perhaps with some
guidance ?

~~~
comex
AFAIK, rust-bindgen doesn't currently have support for translating C functions
and structs into anything other than the same things in Rust. It's somewhat
idiomatic for manually-written bindings, layered on top of the generated ones,
to take care of things like providing a memory-safe interface (which can't
really be done automatically), converting between native Rust types and C
representations if necessary (perhaps including things like Result vs. error
codes or nulls), and adding object orientation. If you want to go full
automatic, though, you can do a lot with Rust macros, so give them a try.

Examples of manual wrappers on top of bindgen - there are many:

[http://erickt.github.io/blog/2014/12/13/rust-and-
mdbm/](http://erickt.github.io/blog/2014/12/13/rust-and-mdbm/)

[https://github.com/kenz-gelsoft/wxRust/blob/rust-
servo/src/b...](https://github.com/kenz-gelsoft/wxRust/blob/rust-
servo/src/base.rs) (I don't like the design of this one, actually)

[https://github.com/rust-
gnome/gtk/blob/master/src/widgets/ac...](https://github.com/rust-
gnome/gtk/blob/master/src/widgets/action_bar.rs) (better)

------
MichaelGG
This ownership stuff is such a blessing and amazing. I'm currently working on
a contract where we're trying to fixup some code that crashes under heavy
load, as well as troubleshoot some perf issues. The root cause is that it's
not clear who actually owns what until when, so in some cases an object is
destructed while there's still some code thinking it can use it. Fun.

For perf, 30% of the CPU is burned in malloc/free, due to them copying strings
around. The system has an arena allocator built in, and many of these strings
might be able to go in there. Except no one is sure exactly how long the
lifetime is on these things. So everyone copies everything just to be sure.
Rust would force addressing this kinda thing up front. (And this project
coulda added an refcounted structure or something, but it's a few hundred kloc
of C and C++ so...)

~~~
CyberDildonics
Uhh... you do realize C++ std::string has small string optimizations right?
That would probably take care of most of the 30%. const string& would probably
take care of the rest. No program should have performance problems due to
strings.

~~~
Rusky
Small string optimization doesn't help _that_ much. Chrome's use of
std::string accounts for almost half of all allocation:
[https://groups.google.com/a/chromium.org/forum/#!msg/chromiu...](https://groups.google.com/a/chromium.org/forum/#!msg/chromium-
dev/EUqoIz2iFU4/kPZ5ZK0K3gEJ)

~~~
shawn-butler
As always it would depend on the context of usage whether the allocations
would be problematic. Use of SGI STL::rope<T, Alloc>[0] has helped me in the
past in a similar scenario. It is part of SGI stl implementation that did not
make it into part of the standard library specification although it should
have, imho.

Essentially ropes are character strings represented as a tree of concatenation
nodes optimized for immuatability. A rope may contain shared subtrees so is
really a directed acyclic graph where the out-edges of each vertex are
ordered. Kind of search trees that are indexed by position.

[0]:
[https://www.sgi.com/tech/stl/Rope.html](https://www.sgi.com/tech/stl/Rope.html)
[1]: [pdf]
[http://www.cs.rit.edu/usr/local/pub/jeh/courses/QUARTERS/FP/...](http://www.cs.rit.edu/usr/local/pub/jeh/courses/QUARTERS/FP/Labs/CedarRope/rope-
paper.pdf)

------
hsivonen
Cases with primitive arguments are easy to understand, but I think it would be
beneficial for the Rust book to have way more detailed info about working with
buffers and heap-allocated structs that the other language holds onto past the
foreign call returning. Looking at examples on github (I don't mean the ones
from this blog post), one can believe the examples work, but it also looks
like there's undocumented knowledge about deep implentation detail involved
when e.g. allocating something in one language and then letting the other
language hold onto it.

~~~
steveklabnik
> it would be beneficial for the Rust book to have way more detailed info

I was just talking with someone on Twitter about this today, actually. I agree
with you 100%, and want to fill that kind of stuff out. You gotta pick
priorities, and since we'll have more new people than experienced people at
first, I've been focusing on the basics. Now that the language isn't changing
all the time, shortly after 1.0, I'll be able to start writing stuff like
this, that covers topics in more depth.

I also think that libraries will pop up to help with this specific kind of
issue, too. We'll see.

~~~
jbooth
While we're making doc requests on this topic, could you address passing
function pointers between C/Rust at some point? Sorry if this is already
obvious to more experienced Rust users.

~~~
steveklabnik
I don't think it's obvious at all, and yeah, absolutely.

------
Animats
I'm looking forward to seeing the major security-critical libraries being
rewritten in Rust, even if they are then often called from C. Especially
OpenSSL/LibreSSL, which is a mess inside, has way too much legacy code, and
too many ways to turn encryption off, log keys, or weaken checks.

~~~
yellowapple
In the case of LibreSSL, it's probably not going to happen very soon; the
OpenBSD devs are very much C programmers (and Ted Unangst already addressed
this in the case of Heartbleed, though his methodology is the subject of some
contention: [http://www.tedunangst.com/flak/post/heartbleed-in-
rust](http://www.tedunangst.com/flak/post/heartbleed-in-rust) ).

While Ted's post has been criticized by a few Rust programmers (see:
[http://tonyarcieri.com/would-rust-have-prevented-
heartbleed-...](http://tonyarcieri.com/would-rust-have-prevented-heartbleed-
another-look) ), it still brings up the argument that one's language choice
isn't a magic bullet. There's an adage (I have no idea who originated it)
that's along the lines of "every 'idiot-proof' system underestimates an
idiot's ability to break things", and that's worth considering here. Rust
prevents a lot of bugs, but it's not a guarantee of security. One needs to
understand the actual problem that needs solved, and this is where the OpenBSD
devs are focusing with LibreSSL (and their various other projects); their
security track record stands as a good testament of that notion of
understanding trumping language choice.

This isn't to say that I disagree with you. Rust is readily poised to replace
C in a lot of contexts (IIRC, one of the obstacles right now is the use of a
different allocator, so trying to use a Rust library from C results in some
performance overhead), and it would be nice to see it used in a lot more
projects. Just bear in mind that moving to Rust isn't the only step that would
be required to fix these sorts of security bugs.

~~~
frabcus
Of course moving to Rust (or Go) won't fix all security bugs.

It will though stop ordinary random code having remote code execution or
spurious data leak bugs.

That is really significant. It needs cheering and encouraging now, and soon it
needs forcing.

~~~
pjmlp
Quite true.

Memory safe languages aren't bug free in terms of security bugs, as there are
also logical errors, as shown by many Java exploits.

However, removing the typical C memory corruption errors out of the picture is
already quite an improvement.

Rust and other system programming languages have more probability to succeed
outside classic UNIX systems though, as UNIX and C go hand-in-hand and I doubt
that will ever change.

The only non-classic UNIX is Mac OS X and it already has its own "Rust".

~~~
yellowapple
Well, the nice thing about Rust is that it's at least theoretically possible
to swap out C with Rust without affecting very many things (at least not
negatively, other than the duplicate allocators IIRC), so a Rusty Unix is at
least plausible.

------
sampo
> _Rust makes it easy to communicate with C APIs without overhead_

Zero overhead vs. the case where you'd also have function call in C.

But in some cases, especially with numerics, if you have a C library that is
designed to be inlined, you get slowdown even calling C from C, if you prevent
inlining.

A random number generator, SIMD-oriented Fast Mersenne Twister [1], was such a
case when I tried. Just calling with `_attribute__ ((noinline))` makes it 2x
slower, even when calling from C.

[1]
[http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/](http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/)

~~~
twoodfin
I don't see any reason (though I'd love to be enlightened) why the Rust
implementation couldn't someday inline C functions. I'd actually be a little
surprised if the underlying LLVM implementation can't use LTO to do it out of
the box.

~~~
kibwen
As mentioned downthread, this is exactly what Servo intends to do to interop
with SpiderMonkey. I'm very excited to see that project proceed.

------
eliteraspberrie
_Bindings can leverage the ownership and borrowing principles in Rust to
codify comments typically found in a C header about how its API should be
used._

Could the Rust compiler make use of design by contract style annotations in
the C header? Maybe it could reason that an unsafe block is in some ways safe.

There is a specification language for C called ACSL (which was designed for
and is mainly used by Frama-C). Annotations look like:

    
    
        /*@
            ensures \result >= 0;
            assigns \nothing;
         */
        int foo(int x)
        {
            if (x < 0)
                return 0;
            return x;
        }
    

I noticed there are annotations for Rust with the LibHoare library
([https://github.com/nrc/libhoare](https://github.com/nrc/libhoare)). The
example above might look like:

    
    
        #[postcond="result >= 0"]
        fn foo(x: int) -> int {
            if x < 0 {
                0
            } else {
                x
            }
        }
    

It would be really cool if ACSL could be translated to LibHoare.

~~~
dbaupp
I don't think it makes sense to build this functionality into the language or
compiler directly, at least not at this time. However, it certainly makes a
_lot_ of sense to have tooling that uses annotations like that to generate
safer Rust bindings than just the raw function declaration.

------
vezzy-fnord
I recall something about Rust's libc crate being glibc-specific. What's the
status on that, and can one build the compiler on Solaris/illumos, NetBSD and
OpenBSD?

~~~
kibwen
Here's an experience report by someone who managed to get Rust running on
musl, for the purpose of creating fully static Rust binaries:
[https://gist.github.com/cl91/bb927df2525738502131#file-
stati...](https://gist.github.com/cl91/bb927df2525738502131#file-static-
linking-against-musl-md) (discussion at
[https://www.reddit.com/r/rust/comments/33boew/weekend_experi...](https://www.reddit.com/r/rust/comments/33boew/weekend_experiment_link_rust_programs_against/)).

~~~
kibwen
UPDATE: Official (though still experimental) support for using musl with Rust
code is landing in the compiler as we speak! [https://github.com/rust-
lang/rust/pull/24777](https://github.com/rust-lang/rust/pull/24777)

------
cpeterso
What happens if the double_input Rust function is declared extern but not
no_mangle? When would you want a mangled extern Rust function?

~~~
alexcrichton
If you omit the `#[no_mangle]` definition then the compiler will end up
emitting a mangled symbol (e.g. one with a long hash at the end that's hard to
guess).

Many C APIs take a callback function pointer, which in rust has the type
`extern fn()`, and this is the primary use case for an `extern` function
defined in Rust which doesn't have `#[no_mangle]` on it.

~~~
lclarkmichalek
Here's an example of that in a lib I've been working on:
[https://github.com/bluepeppers/libnetfilter_queue/blob/maste...](https://github.com/bluepeppers/libnetfilter_queue/blob/master/src/queue.rs#L47-L102)

~~~
cpeterso
Thanks for the example. What is the advantage of using an unmangled extern fn
as a C callback? That the user-friendlier unmangled function name will appear
in stack traces or can more safely be called from other Rust code?

~~~
lclarkmichalek
True, though it wouldn't be hard to write a GDB extension to unmangle the
names (I know D had this from quite early in it's lifetime). In general, I
leave unmangled names to things that are part of the external interface: when
unmangling the name, I'm explicitly saying "this symbol's name is part of the
contract I have with user of this library".

~~~
steveklabnik
There's already something that ships with Rust that unmangles some stuff:
[http://michaelwoerister.github.io/2015/03/27/rust-
xxdb.html](http://michaelwoerister.github.io/2015/03/27/rust-xxdb.html)

------
tarblog
Does using an FFI call eliminate the possibility of the compiler inlining the
call?

~~~
pcwalton
In most cases, yes. However, with some work we should be able to allow
inlining across language boundaries as long as you're using clang to compile
the C and C++. This is because rustc uses the same backend as clang (LLVM).

~~~
kibwen
Though it may seem like this would be brittle, it's worth mentioning that this
is how Servo eventually intends to interoperate with SpiderMonkey, so it will
be a strategy that is well-researched and officially supported.

~~~
cpeterso
SpiderMonkey has an embedding API. Is the overheard between Servo (or Gecko)
and SpiderMonkey so great that cross-language inlining is important?

~~~
bzbarsky
> SpiderMonkey has an embedding API.

Yes, but it's a C++ API and includes a bunch of inline bits in the form of
RAII classes and so forth.

Making those non-inline would be a noticeable performance hit.

Similarly, using the non-inline jsapi.h versions of the various inline stuff
in jsfriendapi.h would be a noticeable performance hit: those were added for
Gecko to use based on performance measurement and profiling.

The main place where this inlining is needed is in the DOM bindings, where
pretty much anything you're doing is overhead on the path from JS to the
actual implementation. This is especially noticeable when the actual
implementation is fast (e.g. many getters in the DOM). In modern browsers the
binding overhead is on the order of 2 dozen instructions or so. A non-inline
function call takes... well, it depends on the ABI. On x86, with cdecl, you
only have 3 caller-save registers but have to push all the args on the stack.
On x86-64, with the AMD64 ABI (so everything except Windows), there's a ton of
caller-save registers that might need to get pushed/popped around the call.
Either way, the chance that you add noticeable overhead to an operation that's
already <30 instructions is high. And that's if you only have to make one
call. If you have to make _several_ such calls as part of the binding code,
you're just screwed. And then you start adding APIs that compute and return
all sorts of stuff in as single call (see the SpiderMonkey typed array APIs)
and other such ugliness.

------
unfamiliar
So it is simple to interface with C, presumably because the C ABI is well
established. But it is not a type safe interface, so you have to give it the
function signature.

It is not so easy to interface with the other languages, you have to do it
through the C ABI.

Doesn't that suggest a good opportunity for all these actively developed
languages (Python, Ruby, Julia, Rust, Go, plus the output of GCC and LLVM) to
get together and agree on some kind of type safe ABI for calling functions in
a generic way? Even if it is just in the form of some metadata annotation of
function signatures to go along with the C ABI?

------
Ygg2
That said, I think Rust probably will need to improve on two fronts:

1) Better binding to C++ API

2) Compiling via MSVC on Windows. Windows is a bit of a red headed step child
for lots of projects and Rust won't have that luxury

~~~
kibwen
Improving our Windows story will be an enormous priority post-1.0, as
mentioned here: [http://internals.rust-lang.org/t/priorities-
after-1-0/1901](http://internals.rust-lang.org/t/priorities-after-1-0/1901)

It's especially important as Mozilla intends to start shipping minor pieces of
Rust code in Firefox this year, but Rust-based components will be relegated to
nightly Firefox until Windows support improves.

Here's a patch-in-progress for the first Rust code to be integrated into
Firefox (Servo's URL parser):
[https://bugzilla.mozilla.org/show_bug.cgi?id=1151899](https://bugzilla.mozilla.org/show_bug.cgi?id=1151899)

~~~
ufo
I remember hearing somewhere that servo is focusing first on things that are
nicer to do in Rust than in C++. Do you know if there is something that makes
Rust more suitable for URL parsing than C++?

~~~
jruderman
Servo is trying to answer ambitious questions like "can layout be done as a
sequence of top-down and bottom-up parallel tree traversals", "can we GC Rust
DOM objects safely", and "how much of a browser engine has to be infected with
support for non-UTF-8 strings".

Gecko, on the other hand, will gain Rust in modules that can be changed
without replacing the entire browser. I'm happy that one of the first will be
the code that supports the URLUtils DOM API. When the C++ code was changed
from being just "URL parsing" to supporting segment changes, it came to have
way more than its fair share of memory safety bugs. It needs a rewrite and it
might as well be in Rust.

------
madez
Has the call from C to Rust also zero overhead?

~~~
alexcrichton
It does indeed! Due to Rust's lack of a garbage collector or runtime
altogether, when C calls into Rust there is no overhead. In the example in the
blog post [1] you can see that the Rust function has no extra syntactic
burden, and the compiler also will not add any form of conversion one way or
another. The C code then just emits a direct call to the symbol, so everything
is totally free!

[1]: [http://blog.rust-lang.org/2015/04/24/Rust-Once-Run-
Everywher...](http://blog.rust-lang.org/2015/04/24/Rust-Once-Run-
Everywhere.html#c-talking-to-rust)

------
tree_of_item
I was hoping this was an announcement of Emscripten support for Rust :(

~~~
haberman
Likewise I keep hoping someone will make a compile-Rust-to-portable-C story
realistic also! The LLVM C backend has been revived!

[https://github.com/draperlaboratory/llvm-
cbe](https://github.com/draperlaboratory/llvm-cbe)

[http://lists.cs.uiuc.edu/pipermail/llvmdev/2014-August/07593...](http://lists.cs.uiuc.edu/pipermail/llvmdev/2014-August/075934.html)

~~~
comex
Last October I tried using that repo to compile Rust to C and it proved to be
totally broken (i.e. not Rust's fault). There have been a bunch of commits
since then, so maybe it works these days... shouldn't be hard to test.

However, don't expect it to generate code that's portable between
architectures with different pointer widths.

~~~
haberman
> However, don't expect it to generate code that's portable between
> architectures with different pointer widths.

That's a limitation I can live with. If my only concession is that I have to
have two builds (32/64), and everything else is portable, I'll be a very happy
camper.

------
zerocored
Please become a popular language once 1.0 comes out. Please.

------
shmerl
C bindings are more straightforward. What about C++ however?

~~~
kibwen
See elsewhere in this thread for discussion on that.

------
andyl
Can anyone post a link to a RubyGem written with a Rust extension??

~~~
carllerche
Here is how we bind the Skylight gem to the Rust bit:
[https://github.com/skylightio/skylight-
ruby/blob/master/ext/...](https://github.com/skylightio/skylight-
ruby/blob/master/ext/skylight_native.c)

