-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Extended linking kinds #1489
Closed
Closed
Extended linking kinds #1489
Changes from 4 commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
91168e0
Some kind of RFC
retep998 3ab01f7
Typo
retep998 c80a9e0
Improvements probably.
retep998 1b5e7e2
Expand on an alternative
retep998 12ba492
Add kind=object
retep998 d6904c8
improve examples
retep998 ad16168
Refocus RFC
retep998 c22a19e
Rerefocus RFC
retep998 c524857
Add more details and questions
retep998 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
- Feature Name: better_static_kind | ||
- Start Date: 2016-02-05 | ||
- RFC PR: (leave this empty) | ||
- Rust Issue: (leave this empty) | ||
|
||
# Summary | ||
[summary]: #summary | ||
|
||
Adds a new `kind=better_static` (name entirely open to bikeshedding) that is used to link static libraries by passing them to the linker, unlike `kind=dynamic` which is intended for dynamic libraries and `kind=static` which has rustc bundle it instead of passing it to the linker. | ||
|
||
# Motivation | ||
[motivation]: #motivation | ||
|
||
Rust currently does not expose the options necessary to have a static library properly linked by the linker. `kind=dynamic` doesn't work because it informs Rust that the library is a dynamic library resulting in issues such as passing the library on to later linker invocations beyond the first immediate linker invocation resulting in symbol duplication, and on Windows it would cause dllimport to be emitted for all the symbols which is incorrect for static libraries. `kind=static` doesn't work because it causes rustc to bundle the library into the `*.rlib` instead of passing it along to the linker, which results in rustc not looking in the standard library paths for the library. | ||
|
||
By adding `kind=better_static` Rust will be able to support passing a static library directly to the linker, thus allowing the library to be found in standard linker search paths, but at the same time still treating it as a static library, thus ensuring `dllimport` and `dllexport` are applied correctly. | ||
|
||
## Related issues and discussions | ||
|
||
* https://github.com/rust-lang/rust/issues/27438 | ||
* https://internals.rust-lang.org/t/meaning-of-link-kinds/2686 | ||
* https://github.com/rust-lang/rfcs/pull/1296 | ||
* https://github.com/rust-lang/rust/issues/31419 | ||
|
||
# Detailed design | ||
[design]: #detailed-design | ||
|
||
`kind=better_static` can be applied the same way as any of the other `kind`s, whether via flags passed to cargo via build scripts or `#[link]` attributes. | ||
|
||
The behavior is that when a library is given such a `kind`, `rustc` will __not__ look for that library itself (unlike `kind=static`). Instead it will trust that it exists and pass it to the first immediate linker invocation (but not to later downstream linker invocations unlike `kind=dynamic`). | ||
|
||
## dllimport and dllexport | ||
|
||
When a native library is linked into a Rust dynamic library via `kind=better_static`, the Rust dynamic library must `dllexport` any symbols from the native library which are reachable (aka any public function as well as anything which can be referenced from a reachable inline/monomorphizable function). | ||
|
||
When referencing the symbols within the same binary, `dllimport` will __not__ be applied to those symbols. Once it goes past a dynamic library boundary then `dllimport` will be applied. | ||
|
||
## Example | ||
|
||
* `a.rlib` is a Rust library that depends on native library `foo.lib`. | ||
* `b.dll` is a dynamic Rust library that depends on `a.rlib`. | ||
* `c.exe` is a Rust executable that depends on `b.dll`. | ||
|
||
* If I specify `kind=static` `foo.lib` is bundled into `a.rlib` by `rustc` and __not__ passed to the linker invocations for `b.dll` and `c.exe`. `a.rlib` and `b.dll` do __not__ use `dllimport` for symbols they reference from `foo.lib`. `b.dll` will `dllexport` any symbols from `foo.lib` that are reachable and `c.exe` will `dllimport` any symbols from `foo.lib` that it uses. | ||
* If I specify `kind=dynamic` `foo.lib` is passed to the linker invocations for `b.dll` and `c.exe`. `a.rlib` `b.dll` and `c.exe` will all use `dllimport` when referencing symbols from `foo.lib` and `b.dll` will __not__ `dllexport` any of the symbols from `foo.lib`. | ||
* If I specify `kind=better_static` `foo.lib` is passed to the linker invocation for `b.dll` but __not__ `c.exe`. `a.rlib` and `b.dll` do __not__ use `dllimport` for symbols they reference from `foo.lib`. `b.dll` will `dllexport` any symbols from `foo.lib` that are reachable and `c.exe` will `dllimport` any symbols from `foo.lib` that it uses. | ||
|
||
## Details of linking on Windows | ||
|
||
On Windows, in the MSVC world, the only kind of library you ever link to is a `foo.lib` library. This may either be a static library or an import library for a DLL (theoretically the library could contain both static symbols and dynamic imports but that is typically rare). MinGW can also sometimes link to a DLL directly. | ||
|
||
When linking to symbols from an import library, `dllimport` needs to be applied to the symbols, otherwise the generated code is less than ideal and it may even fail to link. When linking to symbols from a static library, `dllimport` should not be applied to the symbols, otherwise the generated code is less than ideal and it may even fail to link. Here is a table of various combinations of `dllimport` and their results on linking with MSVC. | ||
|
||
Library type | Static | Function | Result | ||
------------ | ------ | -------- | ------ | ||
Dynamic | No | No | Success | ||
Dynamic | Plain | No | Error | ||
Dynamic | Dllimport | No | Success | ||
Dynamic | No | Plain | Success | ||
Dynamic | Plain | Plain | Error | ||
Dynamic | Dllimport | Plain | Success | ||
Dynamic | No | Dllimport | Success | ||
Dynamic | Plain | Dllimport | Error | ||
Dynamic | Dllimport | Dllimport | Success | ||
Static | No | No | Success | ||
Static | Plain | No | Success | ||
Static | Dllimport | No | Error | ||
Static | No | Plain | Success | ||
Static | Plain | Plain | Success | ||
Static | Dllimport | Plain | Warning | ||
Static | No | Dllimport | Error | ||
Static | Plain | Dllimport | Warning | ||
Static | Dllimport | Dllimport | Error | ||
|
||
# Drawbacks | ||
[drawbacks]: #drawbacks | ||
|
||
* It adds another `kind` that has to be supported and tested. | ||
|
||
# Alternatives | ||
[alternatives]: #alternatives | ||
|
||
* Don't do this and make me very sad. | ||
* Change the behavior of `kind=static`. Remove the bundling aspect and simply make it provide the knowledge to rustc that the symbols are static instead of dynamic. Since Cargo ensures the non-Rust static library will hang around until link time anyway, this would not really break anything for most people. Only a few people would be broken by this and it would be fairly easy to fix. Has the advantage of not adding another `kind`. | ||
|
||
# Unresolved questions | ||
[unresolved]: #unresolved-questions | ||
|
||
* The name of the `kind`. Please bikeshed vigorously. |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I much prefer this alternative. We generally make no guarantees about independent uses of anything other than executables,
cdylib
s andstaticlib
s, the last of which requires the user to make note of the library list Cargo outputs.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am in favor of this alternative as well.