Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can libraries be distributed as a binary, so the end user cannot see the source code?

Tags:

rust

Is it possible to compile a Rust library crate so that the user can't see the source code but can still use the library?

If it is, are all the generics provided as "Source code" or some IR, or does Rust implement generics differently from C++ templates?

like image 296
J V Avatar asked Jan 17 '15 12:01

J V


1 Answers

A lot of metadata is included with each library crate, be it statically linked (.rlib) or dynamically linked (.so/.dylib/.dll):

  • module structure
  • exported macro_rules macros
  • type and trait definitions
  • constants with their initializer expressions
  • signatures for all functions
  • the entire body of each function that is marked as #[inline] or is generic (default trait methods are considered generic over Self)

All of this is enough to reproduce some of the original source (how much depends on the usage of generics), albeit with no comments or other whitespace.
The function bodies are serialized in the compiler's internal AST structure - you can see a pretty form of it with rustc -Z ast-json lib.rs.

While the metadata is binary, not JSON, using librustc to extract all exported function definitions from a compiled crate, and pretty-printing the ASTs is fairly easy.

In the future, there might not be any AST past type-checking, so the metadata would encode an IR of sorts – one possibility is CFG, i.e. "control flow graph", which is already used internally in a couple places.

However, that would still expose more information than Java bytecode, it would be an optimization, you could still approximate the original code (and easily get something which compiles).

As such, there are only two options I can recommend:

  1. expose a C API; it has the advantage of being a stable ABI, but it's quite limiting and brittle;
  2. expose a Rust API using only trait objects, instead of generics; this way you get to keep memory safety and all monomorphic functions would still work normally, but trait objects (dynamic dispatch) cannot express all the patterns possible with generics: in particular, generic trait methods are not callable on trait objects (C++ should have a similar restriction for mixing template and virtual, with workarounds potentially available on a case-by-case basis).
like image 135
eddyb Avatar answered Nov 18 '22 04:11

eddyb