Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC: Add a new crate-type, rdylib #1510

Merged
merged 4 commits into from
Apr 21, 2016
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 101 additions & 0 deletions text/0000-rdylib.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
- Feature Name: N/A
- Start Date: 2016-02-23
- RFC PR: (leave this empty)
- Rust Issue: (leave this empty)

# Summary
[summary]: #summary

Add a new crate type accepted by the compiler, called `cdylib`, which
corresponds to exporting a C interface from a Rust dynamic library.

# Motivation
[motivation]: #motivation

Currently the compiler supports two modes of generating dynamic libraries:

1. One form of dynamic library is intended for reuse with further compilations.
This kind of library exposes all Rust symbols, links to the standard library
dynamically, etc. I'll refer to this mode as **rdylib** as it's a Rust
dynamic library talking to Rust.
2. Another form of dynamic library is intended for embedding a Rust application
into another. Currently the only difference from the previous kind of dynamic
library is that it favors linking statically to other Rust libraries
(bundling them inside). I'll refer to this as a **cdylib** as it's a Rust
dynamic library exporting a C API.

Each of these flavors of dynamic libraries has a distinct use case. For examples
rdylibs are used by the compiler itself to implement plugins, and cdylibs are
used whenever Rust needs to be dynamically loaded from another language or
application.

Unfortunately the balance of features is tilted a little bit too much towards
the smallest use case, rdylibs. In practice because Rust is statically linked by
default and has an unstable ABI, rdylibs are used quite rarely. There are a
number of requirements they impose, however, which aren't necessary for
cdylibs:

* Metadata is included in all dynamic libraries. If you're just loading Rust
into somewhere else, however, you have no need for the metadata!
* *Reachable* symbols are exposed from dynamic libraries, but if you're loading
Rust into somewhere else then, like executables, only *public* non-Rust-ABI
functions need to be exported. This can lead to unnecessarily large Rust
dynamic libraries in terms of object size as well as missed optimization
opportunities from knowing that a function is otherwise private.
* We can't run LTO for dylibs because those are intended for end products, not
intermediate ones like (1) is.

The purpose of this RFC is to solve these drawbacks with a new crate-type to
represent the more rarely used form of dynamic library (rdylibs).

# Detailed design
[design]: #detailed-design

A new crate type will be accepted by the compiler, `cdylib`, which can be passed
as either `--crate-type cdylib` on the command line or via `#![crate_type =
"cdylib"]` in crate attributes. This crate type will conceptually correspond to
the cdylib use case described above, and today's `dylib` crate-type will
continue to correspond to the rdylib use case above. Note that the literal
output artifacts of these two crate types (files, file names, etc) will be the
same.

The two formats will differ in the parts listed in the motivation above,
specifically:

* **Metadata** - rdylibs will have a section of the library with metadata,
whereas cdylibs will not.
* **Symbol visibility** - rdylibs will expose all symbols as rlibs do, cdylibs
will expose symbols as executables do. This means that `pub fn foo() {}` will
not be an exported symbol, but `#[no_mangle] pub extern fn foo() {}` will be
an exported symbol. Note that the compiler will also be at liberty to pass
extra flags to the linker to actively hide exported Rust symbols from linked
libraries.
* **LTO** - this will disallowed for rdylibs, but enabled for cdylibs.
* **Linkage** - rdylibs will link dynamically to one another by default, for
example the standard library will be linked dynamically by default. On the
other hand, cdylibs will link all Rust dependencies statically by default.

# Drawbacks
[drawbacks]: #drawbacks

Rust's ephemeral and ill-defined "linkage model" is... well... ill defined and
ephemeral. This RFC is an extension of this model, but it's difficult to reason
about extending that which is not well defined. As a result there could be
unforseen interactions between this output format and where it's used.

# Alternatives
[alternatives]: #alternatives

* Originally this RFC proposed adding a new crate type, `rdylib`, instead of
adding a new crate type, `cdylib`. The existing `dylib` output type would be
reinterpreted as a cdylib use-case. This is unfortunately, however, a breaking
change and requires a somewhat complicated transition plan in Cargo for
plugins. In the end it didn't seem worth it for the benefit of "cdylib is
probably what you want".

# Unresolved questions
[unresolved]: #unresolved-questions

* Should the existing `dylib` format be considered unstable? (should it require
a nightly compiler?). The use case for a Rust dynamic library is so limited,
and so volatile, we may want to just gate access to it by default.