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

Conversation

alexcrichton
Copy link
Member

@alexcrichton alexcrichton commented Feb 24, 2016

Add a new crate type accepted by the compiler, called rdylib, which
corresponds to the behavior of -C prefer-dynamic plus --crate-type dylib.

Rendered

Add a new crate type accepted by the compiler, called `rdylib`, which
corresponds to the behavior of `-C prefer-dynamic` plus `--crate-type dylib`.
@alexcrichton alexcrichton added T-dev-tools Relevant to the development tools team, which will review and decide on the RFC. T-compiler Relevant to the compiler team, which will review and decide on the RFC. labels Feb 24, 2016
@alexcrichton alexcrichton self-assigned this Feb 24, 2016
@arielb1
Copy link
Contributor

arielb1 commented Feb 24, 2016

Can you have 2 cdylibs, both linked against libstd, in the same process?

@alexcrichton
Copy link
Member Author

@arielb1 I believe so, yes. If we're careful to restrict the exported symbols of a dylib to only the public, no_mangle, and extern ABI functions, the in theory two independent Rust cdylibs would have disjoint sets of symbols, and they wouldn't accidentally use standard library symbols from another. I haven't tested this, however, so there may be cross-platform oddities lurking as well

@arielb1
Copy link
Contributor

arielb1 commented Feb 24, 2016

Won't the 2 separate copies of libstd fight with each other?

@alexcrichton
Copy link
Member Author

Having not tested this, I'm not 100% certain, but I would expect it to work. Each dynamic library would not have any unresolved symbols to copies of libstd as they're all internally resolved. The only dependencies would be on usual system libraries (e.g. libc.so or librt.so). I don't believe that two copies of a library can conflict each other if there's never any unresolved symbol to one another.

Basically what I would expect is:

  1. The set of exported symbols from each dynamic library is completely disjoint (assuming properly namespaced C-like apis)
  2. The set of unresolved symbols is only those to standard system libraries.

With that, I don't believe that they can conflict. But again, untested!

@nikomatsakis
Copy link
Contributor

Seems pretty reasonable to me.

@Kimundi
Copy link
Member

Kimundi commented Mar 2, 2016

If I understood this right, then huge 1+ from me, since I believe something like this is necessary if you want to experiment with runtime loadable crates that share dependencies and have it work right.

@retep998
Copy link
Member

Yes, definitely splitting up the two kinds of dylibs is very much needed and I am in favor of this.

On Windows I know for sure that having two DLLs which have their own statically linked standard libraries should be fine with coexisting. They won't accidentally call each other's symbols. Pretty much the only thing you have to worry about is if two DLLs each keep track of some state and you pass an object specific to the state from one DLL to the other DLL. An example of this is if you have two cdylibs both with jemalloc statically linked in, and you allocate something in one DLL and then try to free it in the other. That will explode and fail horribly. As long as you avoid situations like that then everything is totally fine, on Windows anyway.

Also it might be worth pointing out in the RFC how the output artifacts will be named as well as which allocators will be used by default.

@emoon
Copy link

emoon commented Mar 12, 2016

I really hope this one gets done!

As I wrote here https://users.rust-lang.org/t/dynamic-linking-of-sharedlibs-with-cargo/4756

My use-case is that I will have lots of plugins written in Rust (as I write in the post) and without -C prefer-dynamic I would/will endup with a 'copy' of stdlib in each plugin which is a bit wasteful.

@nikomatsakis
Copy link
Contributor

@alexcrichton think this is ready for FCP? I think so :)

@alexcrichton
Copy link
Member Author

Sounds good to me!

@michaelwoerister
Copy link
Member

This RFC looks good to me. No need to stuff metadata into most dynamic libraries and having LTO available is also pretty good.

@brson
Copy link
Contributor

brson commented Apr 5, 2016

I am very concerned that this is a really big breaking change, and one that is easily avoilable. We could alternately deprecated the dylib type and introduce a cdylib or native-dylib.

@alexcrichton
Copy link
Member Author

🔔 This RFC is now entering its week-long final comment period 🔔

@alexcrichton alexcrichton added final-comment-period Will be merged/postponed/closed in ~10 calendar days unless new substational objections are raised. and removed I-nominated labels Apr 5, 2016
@alexcrichton
Copy link
Member Author

cc https://internals.rust-lang.org/t/do-you-compile-a-dylib/3342, trying to get some broader feedback on how dylibs are used

@jethrogb
Copy link
Contributor

jethrogb commented Apr 6, 2016

Why is LTO disabled for rdylibs? Or perhaps I'm misunderstanding the usecase of rdylibs? But it sounds to me like a rdylib differs from an rlib in that it is linked.

@alexcrichton
Copy link
Member Author

One of the primary purposes of our current implementation of LTO is to internalize all symbols, stripping what's not needed and heavily optimizing based on what's there. This means that the public API of an rdylib, in terms of symbols, isn't actually known by the compiler, so nothing can later link to that rdylib (unless it's through a C API, in which case it's just the same as a cdylib)

@jethrogb
Copy link
Contributor

jethrogb commented Apr 6, 2016

So if I understand correctly you're saying you don't want to do LTO because the linker's reachability analysis doesn't understand the way Rust uses the symbols in the shared library, is that correct? It seems to me like this could be solved by having rustc generate a linker script based on the pub-ness of the functions in the crate, after which the linker is able to perform LTO correctly. I don't think this needs to be done as part of this RFC, but it would be good to mention the reasons when you say "disallowed for rdylibs".

@alexcrichton
Copy link
Member Author

So if I understand correctly you're saying you don't want to do LTO because the linker's reachability analysis doesn't understand the way Rust uses the symbols in the shared library, is that correct?

Not quite I believe. The way LTO works in Rust is:

  1. Find rlibs for all dependencies.
  2. Load LLVM bytecode from the rlib of all dependencies.
  3. Shove all LLVM bytecode from all dependencies and the local crate into one giant LLVM module.
  4. Internalize all non-public symbols in this LLVM module. Public symbols include things like C API entry points, the main function, etc.
  5. Optimize this LLVM module.

As part of steps 4/5, massive swaths of code are removed. We could not internalize symbols, but that defeats one of the main purposes of LTO. LTO is also basically the antithesis of dynamic linking (you have to recompile if any dependencies change) so I'm not really sure why you'd want to do it for an rdylib?

If we change or tweak how we do LTO then it may be appropriate to allow it on rdylibs in the future, but the current implementation would just flat out break rdylibs (which is why it's disabled for rdylibs today anyway).

@jethrogb
Copy link
Contributor

jethrogb commented Apr 6, 2016

Please correct me if I'm wrong, but when compiling an rdylib, that is the "one giant LLVM module" and whatever the resulting code is in the rdylib end product, it will never be touched again in a future link but instead just used as is through dynamic linking. This means you're missing a huge opportunity to optimize away code that is never used, i.e. any functions that are not going to be called from outside the crate. For rdylibs, step 4 in your process would be a little different by specifying far more public symbols than you'd have in a normal binary, but it would still be possible to do LTO this way I think.

@alexcrichton
Copy link
Member Author

Ah yeah so an rdylib (today's dylib crate type) isn't one large LLVM module. It's the same as an rlib, just an object file for the crate being compiled. In that sense, without LTO, we have no ability to optimize away code that isn't used beyond what we can tell the linker (which we indeed try to do).

@alexcrichton
Copy link
Member Author

Tracking issue: rust-lang/rust#33132

@sagebind
Copy link

@DaGenix Not really relevant to the RFC any longer, but did you ever manage to accomplish using rdylibs for use case 2 you mentioned? I'm interested, as I'm looking to do the same thing.

@liigo
Copy link
Contributor

liigo commented May 5, 2016

@alexcrichton Would you like to change the title of this PR to use word 'cdylib' instead of 'rdylib'?
and maybe rename RFC file '1510-rdylib.md ' to '1510-cdylib.md '

eddyb pushed a commit to eddyb/rust that referenced this pull request May 16, 2016
This commit is an implementation of [RFC 1510] which adds a new crate type,
`cdylib`, to the compiler. This new crate type differs from the existing `dylib`
crate type in a few key ways:

* No metadata is present in the final artifact
* Symbol visibility rules are the same as executables, that is only reachable
  `extern` functions are visible symbols
* LTO is allowed
* All libraries are always linked statically

This commit is relatively simple by just plubming the compiler with another
crate type which takes different branches here and there. The only major change
is an implementation of the `Linker::export_symbols` function on Unix which now
actually does something. This helps restrict the public symbols from a cdylib on
Unix.

With this PR a "hello world" `cdylib` is 7.2K while the same `dylib` is 2.4MB,
which is some nice size savings!

[RFC 1510]: rust-lang/rfcs#1510

Closes rust-lang#33132
alexcrichton added a commit to alexcrichton/rust that referenced this pull request May 18, 2016
This commit is an implementation of [RFC 1510] which adds a new crate type,
`cdylib`, to the compiler. This new crate type differs from the existing `dylib`
crate type in a few key ways:

* No metadata is present in the final artifact
* Symbol visibility rules are the same as executables, that is only reachable
  `extern` functions are visible symbols
* LTO is allowed
* All libraries are always linked statically

This commit is relatively simple by just plubming the compiler with another
crate type which takes different branches here and there. The only major change
is an implementation of the `Linker::export_symbols` function on Unix which now
actually does something. This helps restrict the public symbols from a cdylib on
Unix.

With this PR a "hello world" `cdylib` is 7.2K while the same `dylib` is 2.4MB,
which is some nice size savings!

[RFC 1510]: rust-lang/rfcs#1510

Closes rust-lang#33132
bors added a commit to rust-lang/rust that referenced this pull request May 19, 2016
rustc: Add a new crate type, cdylib

This commit is an implementation of [RFC 1510] which adds a new crate type,
`cdylib`, to the compiler. This new crate type differs from the existing `dylib`
crate type in a few key ways:

* No metadata is present in the final artifact
* Symbol visibility rules are the same as executables, that is only reachable
  `extern` functions are visible symbols
* LTO is allowed
* All libraries are always linked statically

This commit is relatively simple by just plubming the compiler with another
crate type which takes different branches here and there. The only major change
is an implementation of the `Linker::export_symbols` function on Unix which now
actually does something. This helps restrict the public symbols from a cdylib on
Unix.

With this PR a "hello world" `cdylib` is 7.2K while the same `dylib` is 2.4MB,
which is some nice size savings!

[RFC 1510]: rust-lang/rfcs#1510

Closes #33132
alexcrichton added a commit to alexcrichton/rust that referenced this pull request May 19, 2016
This commit is an implementation of [RFC 1510] which adds a new crate type,
`cdylib`, to the compiler. This new crate type differs from the existing `dylib`
crate type in a few key ways:

* No metadata is present in the final artifact
* Symbol visibility rules are the same as executables, that is only reachable
  `extern` functions are visible symbols
* LTO is allowed
* All libraries are always linked statically

This commit is relatively simple by just plubming the compiler with another
crate type which takes different branches here and there. The only major change
is an implementation of the `Linker::export_symbols` function on Unix which now
actually does something. This helps restrict the public symbols from a cdylib on
Unix.

With this PR a "hello world" `cdylib` is 7.2K while the same `dylib` is 2.4MB,
which is some nice size savings!

[RFC 1510]: rust-lang/rfcs#1510

Closes rust-lang#33132
bors added a commit to rust-lang/rust that referenced this pull request May 20, 2016
rustc: Add a new crate type, cdylib

This commit is an implementation of [RFC 1510] which adds a new crate type,
`cdylib`, to the compiler. This new crate type differs from the existing `dylib`
crate type in a few key ways:

* No metadata is present in the final artifact
* Symbol visibility rules are the same as executables, that is only reachable
  `extern` functions are visible symbols
* LTO is allowed
* All libraries are always linked statically

This commit is relatively simple by just plubming the compiler with another
crate type which takes different branches here and there. The only major change
is an implementation of the `Linker::export_symbols` function on Unix which now
actually does something. This helps restrict the public symbols from a cdylib on
Unix.

With this PR a "hello world" `cdylib` is 7.2K while the same `dylib` is 2.4MB,
which is some nice size savings!

[RFC 1510]: rust-lang/rfcs#1510

Closes #33132
@golddranks
Copy link

The rendered link is broken. Here's a fresh one: https://github.com/rust-lang/rfcs/blob/master/text/1510-cdylib.md

@Centril Centril added A-linkage Proposals relating to the linking step. A-flags Proposals relating to rustc flags or flags for other tools. A-crate-type Proposals relating to crate types. labels Nov 23, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-crate-type Proposals relating to crate types. A-flags Proposals relating to rustc flags or flags for other tools. A-linkage Proposals relating to the linking step. final-comment-period Will be merged/postponed/closed in ~10 calendar days unless new substational objections are raised. T-compiler Relevant to the compiler team, which will review and decide on the RFC. T-dev-tools Relevant to the development tools team, which will review and decide on the RFC.
Projects
None yet
Development

Successfully merging this pull request may close these issues.