From 5fa09f4603b4fda9a783f28a25e65fb88b659589 Mon Sep 17 00:00:00 2001 From: Peter Atashian Date: Tue, 22 Jan 2019 13:55:10 -0500 Subject: [PATCH 01/14] dll kind RFC --- text/0000-dll-kind.md | 81 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 text/0000-dll-kind.md diff --git a/text/0000-dll-kind.md b/text/0000-dll-kind.md new file mode 100644 index 00000000000..c330e2760db --- /dev/null +++ b/text/0000-dll-kind.md @@ -0,0 +1,81 @@ +- Feature Name: dll_kind +- Start Date: 2018-06-27 +- RFC PR: (leave this empty) +- Rust Issue: (leave this empty) + +# Summary +[summary]: #summary + +Extend the `#[link]` attribute by adding a new kind `kind="dll"` for use on Windows which emits idata sections for the items in the attached `extern` block, so they may be linked against without linking against an import library. Also add a `#[ordinal]` attribute for specifying symbols that are actually ordinals. + +# Motivation +[motivation]: #motivation + +Traditionally in order to link against a dll the program must actually link against an import library. For example to depend on some symbols from kernel32.dll the program links to kernel32.lib. However this requires that the correct import libraries be available to link against, and for third party libraries that are only distributed as a dll creating an import library can be quite difficult, especially given lib.exe is incapable of creating an import library that links to stdcall symbols. + +A real advantage of this feature, however, is the fact that symbols will be *guaranteed* to come from the specified dll. Currently linking is a very finnicky process where if multiple libraries provide the same symbol the linker will choose one of them to provide the symbol and the user has very little control over it. With `kind="dll"` the user is ensured that the symbol will come from the specified dll. + +Sometimes a crate may know exactly which dll it wants to link against, but which import library it ends up linking against is unknown. In particular the d3dcompiler.lib provided by the Windows SDK can link to several different versions of the d3dcompiler dll depending on which version of the Windows SDK the user has installed. `kind="dll"` would allow `winapi` to link to a specific version of that dll and ensure the symbols are correct for that version. + +# Guide-level explanation +[guide-level-explanation]: #guide-level-explanation + +When trying to link to a Windows dll, the `dylib` kind may sometimes be unsuitable, and `kind="dll"` can be used instead: + +```rust +#[cfg(windows)] +#[link(name = "kernel32.dll", kind = "dll")] +#[allow(non_snake_case)] +extern "system" { + fn GetStdHandle(nStdHandle: u32) -> *mut u8; +} +``` + +Some symbols are only exported by ordinal from the dll in which case `#[ordinal]` may be used: + +```rust +#[cfg(windows)] +#[link(name = "ws2_32.dll", kind = "dll")] +#[allow(non_snake_case)] +extern "system" { + #[ordinal(116)] + fn WSACleanup() -> i32; +} +``` + +# Reference-level explanation +[reference-level-explanation]: #reference-level-explanation + +Add a new value `dll` to the `kind` property of the `link` attribute. When this kind is specified, Rust will *keep* the symbol mangled, instead of having an unmangled symbol. Rust will emit an idata section that maps from the *mangled* symbol to the unmangled symbol in the specified dll. The unmangled symbol will *not* have calling convention decorations. The `name` specified in the `#[link]` attribute when `kind = "dll"` is used *must* include the extension. + +`#[ordinal]` is an attribute taking a single numerical value, such as `#[ordinal(116)]`. It can only be specified on symbols in an extern block using `kind = "dll"`. When specified, the idata section will map from the mangled symbol to the ordinal in the specified dll. + +The attribute `#[link_name]` may be used on symbols in extern blocks using `kind="dll"`. When specified, the idata section will map from the mangled symbol to the symbol name specified in `#[link_name]` in the specified dll, without any calling convention decorations added. If calling convention decorations are desired they must be specified explicitly in the `#[link_name]` attribute. + +# Drawbacks +[drawbacks]: #drawbacks + +Additional complexity in the language through a new `kind` and a new attribute for specifying ordinals. + +# Rationale and alternatives +[alternatives]: #alternatives + +The RFC as proposed would allow for full control over linking to symbols from dlls with syntax as close as possible to existing extern blocks. + +No alternatives are currently known other than the status quo. + +# Prior art +[prior-art]: #prior-art + +No native languages are known of that allow link time linking to symbols from dlls withot import libraries. Please note that this is distinct from runtime loading of dlls. + +# Unresolved questions +[unresolved]: #unresolved-questions + +* Bikeshedding on attribute names. +* Should this feature be extended to other platforms? + +# Future possibilities +[future-possibilities]: #future-possibilities + +With the features described in this RFC, we would be one step closer towards a fully standalone pure Rust target for Windows that does not rely on any external libraries (aside from the obvious and unavoidable runtime dependence on system libraries), allowing for easy installation and incredibly easy cross compilation. From f631ed40da22d7553d0202c57aadf833869e83a4 Mon Sep 17 00:00:00 2001 From: Peter Atashian Date: Tue, 22 Jan 2019 15:42:42 -0500 Subject: [PATCH 02/14] Revision --- text/0000-dll-kind.md | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/text/0000-dll-kind.md b/text/0000-dll-kind.md index c330e2760db..f59ca1b8d6a 100644 --- a/text/0000-dll-kind.md +++ b/text/0000-dll-kind.md @@ -6,7 +6,7 @@ # Summary [summary]: #summary -Extend the `#[link]` attribute by adding a new kind `kind="dll"` for use on Windows which emits idata sections for the items in the attached `extern` block, so they may be linked against without linking against an import library. Also add a `#[ordinal]` attribute for specifying symbols that are actually ordinals. +Extend the `#[link]` attribute by adding a new kind `kind="dll"` for use on Windows which emits idata sections for the items in the attached `extern` block, so they may be linked against without linking against an import library. Also add a `#[link_ordinal]` attribute for specifying symbols that are actually ordinals. # Motivation [motivation]: #motivation @@ -31,14 +31,14 @@ extern "system" { } ``` -Some symbols are only exported by ordinal from the dll in which case `#[ordinal]` may be used: +Some symbols are only exported by ordinal from the dll in which case `#[link_ordinal]` may be used: ```rust #[cfg(windows)] #[link(name = "ws2_32.dll", kind = "dll")] #[allow(non_snake_case)] extern "system" { - #[ordinal(116)] + #[link_ordinal(116)] fn WSACleanup() -> i32; } ``` @@ -46,11 +46,16 @@ extern "system" { # Reference-level explanation [reference-level-explanation]: #reference-level-explanation -Add a new value `dll` to the `kind` property of the `link` attribute. When this kind is specified, Rust will *keep* the symbol mangled, instead of having an unmangled symbol. Rust will emit an idata section that maps from the *mangled* symbol to the unmangled symbol in the specified dll. The unmangled symbol will *not* have calling convention decorations. The `name` specified in the `#[link]` attribute when `kind = "dll"` is used *must* include the extension. +Add a new attribute `#[link_ordinal]` taking a single numerical value, such as `#[link_ordinal(116)]`. It can only be specified on symbols in an extern block using `kind="dll"`. -`#[ordinal]` is an attribute taking a single numerical value, such as `#[ordinal(116)]`. It can only be specified on symbols in an extern block using `kind = "dll"`. When specified, the idata section will map from the mangled symbol to the ordinal in the specified dll. +Add a new value `dll` to the `kind` property of the `link` attribute. When this kind is specified, the `name` must explicitly include the extension. In addition, for all items in the associated extern block Rust will *keep* the symbol mangled, instead of having an unmangled symbol. Rust will emit an idata section that maps from the *mangled* symbol to a symbol in the specified dll. The symbol in the dll that the idata section maps to depends on which attributes are specified on the item in question: -The attribute `#[link_name]` may be used on symbols in extern blocks using `kind="dll"`. When specified, the idata section will map from the mangled symbol to the symbol name specified in `#[link_name]` in the specified dll, without any calling convention decorations added. If calling convention decorations are desired they must be specified explicitly in the `#[link_name]` attribute. +* If `#[link_ordinal]` is specified the idata section will map from the mangled symbol to the ordinal specified in the dll. +* If `#[link_name] is specified the idata section will map from the mangled symbol to the name specified in the dll, without any calling convention decorations added. If calling convention decorations are desired they must be specified explicitly in the value of the `#[link_name]` attribute. +* If both `#[link_ordinal]` and `#[link_name]` are specified, an error will be emitted. +* If neither `#[link_ordinal]` nor `#[link_name]` are specified, the idata section will map from the mangled symbol to its unmangled equivalent in the dll. The unmangled symbol will *not* have calling convention decorations. + +The idata section that is produced is equivalent to the idata sections found in import libraries, and should result in identical code generation by the linker. # Drawbacks [drawbacks]: #drawbacks From 91a1a38763dd8dbebb6aa9c9e7fdb9d143a35087 Mon Sep 17 00:00:00 2001 From: Peter Atashian Date: Tue, 22 Jan 2019 15:45:05 -0500 Subject: [PATCH 03/14] whoops --- text/0000-dll-kind.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0000-dll-kind.md b/text/0000-dll-kind.md index f59ca1b8d6a..1daa6fa2310 100644 --- a/text/0000-dll-kind.md +++ b/text/0000-dll-kind.md @@ -51,7 +51,7 @@ Add a new attribute `#[link_ordinal]` taking a single numerical value, such as ` Add a new value `dll` to the `kind` property of the `link` attribute. When this kind is specified, the `name` must explicitly include the extension. In addition, for all items in the associated extern block Rust will *keep* the symbol mangled, instead of having an unmangled symbol. Rust will emit an idata section that maps from the *mangled* symbol to a symbol in the specified dll. The symbol in the dll that the idata section maps to depends on which attributes are specified on the item in question: * If `#[link_ordinal]` is specified the idata section will map from the mangled symbol to the ordinal specified in the dll. -* If `#[link_name] is specified the idata section will map from the mangled symbol to the name specified in the dll, without any calling convention decorations added. If calling convention decorations are desired they must be specified explicitly in the value of the `#[link_name]` attribute. +* If `#[link_name]` is specified the idata section will map from the mangled symbol to the name specified in the dll, without any calling convention decorations added. If calling convention decorations are desired they must be specified explicitly in the value of the `#[link_name]` attribute. * If both `#[link_ordinal]` and `#[link_name]` are specified, an error will be emitted. * If neither `#[link_ordinal]` nor `#[link_name]` are specified, the idata section will map from the mangled symbol to its unmangled equivalent in the dll. The unmangled symbol will *not* have calling convention decorations. From aa58318612e399002e4fd20eafd93d207b9cf0c0 Mon Sep 17 00:00:00 2001 From: Peter Atashian Date: Tue, 22 Jan 2019 15:53:01 -0500 Subject: [PATCH 04/14] Add some more benefits. --- text/0000-dll-kind.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/text/0000-dll-kind.md b/text/0000-dll-kind.md index 1daa6fa2310..1720d05cb41 100644 --- a/text/0000-dll-kind.md +++ b/text/0000-dll-kind.md @@ -17,6 +17,8 @@ A real advantage of this feature, however, is the fact that symbols will be *gua Sometimes a crate may know exactly which dll it wants to link against, but which import library it ends up linking against is unknown. In particular the d3dcompiler.lib provided by the Windows SDK can link to several different versions of the d3dcompiler dll depending on which version of the Windows SDK the user has installed. `kind="dll"` would allow `winapi` to link to a specific version of that dll and ensure the symbols are correct for that version. +This would also allow `winapi` to not have to bundle import libraries for the `pc-windows-gnu` targets, saving on bandwidth and disk space for users. + # Guide-level explanation [guide-level-explanation]: #guide-level-explanation @@ -84,3 +86,7 @@ No native languages are known of that allow link time linking to symbols from dl [future-possibilities]: #future-possibilities With the features described in this RFC, we would be one step closer towards a fully standalone pure Rust target for Windows that does not rely on any external libraries (aside from the obvious and unavoidable runtime dependence on system libraries), allowing for easy installation and incredibly easy cross compilation. + +If that were to happen, we'd no longer need to pretend the pc-windows-gnu toolchain is standalone, and we'd be able to stop bundling MinGW bits entirely in favor of the user's own MinGW installation, thereby resolving a bunch of issues. + +Also users would stop complaining about having to install several gigabytes of VC++ just to link their Rust binaries. From 6c38aecd60b4e598347d2a91c1f5e6113a417b51 Mon Sep 17 00:00:00 2001 From: Peter Atashian Date: Tue, 22 Jan 2019 16:04:28 -0500 Subject: [PATCH 05/14] Provide reasons for when you should use kind="dll" --- text/0000-dll-kind.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/text/0000-dll-kind.md b/text/0000-dll-kind.md index 1720d05cb41..dbdbefbdfec 100644 --- a/text/0000-dll-kind.md +++ b/text/0000-dll-kind.md @@ -22,7 +22,14 @@ This would also allow `winapi` to not have to bundle import libraries for the `p # Guide-level explanation [guide-level-explanation]: #guide-level-explanation -When trying to link to a Windows dll, the `dylib` kind may sometimes be unsuitable, and `kind="dll"` can be used instead: +When trying to link to a Windows dll, the `dylib` kind may sometimes be unsuitable, and `kind="dll"` can be used instead. A central requirement of `kind="dll"` is that the dll has a stable ABI. Here are some examples of valid reasons to use `kind="dll"`: + +* You've had it up to here with trying to create an import library for a dll that has stdcall functions. +* You're in linking hell with multiple import libraries providing the same symbol but from different dlls. +* You know exactly which dll you need a symbol from, but you don't know which version of the dll the import library is going to give you. +* You maintain `winapi`. + +Here is an example of usage: ```rust #[cfg(windows)] From 8005182e4f0f20f483f3dcc940b620fdbd945d7e Mon Sep 17 00:00:00 2001 From: Peter Atashian Date: Wed, 23 Jan 2019 03:19:16 -0500 Subject: [PATCH 06/14] Provide example of issue. --- text/0000-dll-kind.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0000-dll-kind.md b/text/0000-dll-kind.md index dbdbefbdfec..810ddfe7fa1 100644 --- a/text/0000-dll-kind.md +++ b/text/0000-dll-kind.md @@ -94,6 +94,6 @@ No native languages are known of that allow link time linking to symbols from dl With the features described in this RFC, we would be one step closer towards a fully standalone pure Rust target for Windows that does not rely on any external libraries (aside from the obvious and unavoidable runtime dependence on system libraries), allowing for easy installation and incredibly easy cross compilation. -If that were to happen, we'd no longer need to pretend the pc-windows-gnu toolchain is standalone, and we'd be able to stop bundling MinGW bits entirely in favor of the user's own MinGW installation, thereby resolving a bunch of issues. +If that were to happen, we'd no longer need to pretend the pc-windows-gnu toolchain is standalone, and we'd be able to stop bundling MinGW bits entirely in favor of the user's own MinGW installation, thereby resolving a bunch of issues such as [rust-lang/rust#53454](https://github.com/rust-lang/rust/issues/53454). Also users would stop complaining about having to install several gigabytes of VC++ just to link their Rust binaries. From 385a210367272f03ff05f4026eaae1b1e3da54ff Mon Sep 17 00:00:00 2001 From: Peter Atashian Date: Fri, 25 Jan 2019 00:35:01 -0500 Subject: [PATCH 07/14] Delphi is an example of prior art. --- text/0000-dll-kind.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/text/0000-dll-kind.md b/text/0000-dll-kind.md index 810ddfe7fa1..5ffd9e73e33 100644 --- a/text/0000-dll-kind.md +++ b/text/0000-dll-kind.md @@ -81,7 +81,9 @@ No alternatives are currently known other than the status quo. # Prior art [prior-art]: #prior-art -No native languages are known of that allow link time linking to symbols from dlls withot import libraries. Please note that this is distinct from runtime loading of dlls. +Many non-native languages have the ability to import symbols from dlls, but this uses runtime loading by the language runtime and is not the same as what is being proposed here. + +Delphi is a native language that has the ability to import symbols from dlls without import libraries. # Unresolved questions [unresolved]: #unresolved-questions @@ -96,4 +98,6 @@ With the features described in this RFC, we would be one step closer towards a f If that were to happen, we'd no longer need to pretend the pc-windows-gnu toolchain is standalone, and we'd be able to stop bundling MinGW bits entirely in favor of the user's own MinGW installation, thereby resolving a bunch of issues such as [rust-lang/rust#53454](https://github.com/rust-lang/rust/issues/53454). +A future extension of this feature would be the ability to optionally lazily load such external functions, since Rust would naturally have all the information required to do so. + Also users would stop complaining about having to install several gigabytes of VC++ just to link their Rust binaries. From b962c7b2555947022c16261a38b16bf61ec506a2 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Thu, 31 Jan 2019 20:15:22 -0500 Subject: [PATCH 08/14] Apply suggestions from code review Co-Authored-By: retep998 --- text/0000-dll-kind.md | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/text/0000-dll-kind.md b/text/0000-dll-kind.md index 5ffd9e73e33..c6c7ab396d2 100644 --- a/text/0000-dll-kind.md +++ b/text/0000-dll-kind.md @@ -1,5 +1,5 @@ - Feature Name: dll_kind -- Start Date: 2018-06-27 +- Start Date: 2019-01-22 - RFC PR: (leave this empty) - Rust Issue: (leave this empty) @@ -11,11 +11,13 @@ Extend the `#[link]` attribute by adding a new kind `kind="dll"` for use on Wind # Motivation [motivation]: #motivation -Traditionally in order to link against a dll the program must actually link against an import library. For example to depend on some symbols from kernel32.dll the program links to kernel32.lib. However this requires that the correct import libraries be available to link against, and for third party libraries that are only distributed as a dll creating an import library can be quite difficult, especially given lib.exe is incapable of creating an import library that links to stdcall symbols. +[dll]: https://en.wikipedia.org/wiki/Dynamic-link_library -A real advantage of this feature, however, is the fact that symbols will be *guaranteed* to come from the specified dll. Currently linking is a very finnicky process where if multiple libraries provide the same symbol the linker will choose one of them to provide the symbol and the user has very little control over it. With `kind="dll"` the user is ensured that the symbol will come from the specified dll. +Traditionally, to link against a [dll], the program must actually link against an import library. For example to depend on some symbols from `kernel32.dll` the program links to `kernel32.lib`. However, this requires that the correct import libraries be available to link against, and for third party libraries that are only distributed as a dll creating an import library can be quite difficult, especially given that `lib.exe` is incapable of creating an import library that links to `stdcall` symbols. -Sometimes a crate may know exactly which dll it wants to link against, but which import library it ends up linking against is unknown. In particular the d3dcompiler.lib provided by the Windows SDK can link to several different versions of the d3dcompiler dll depending on which version of the Windows SDK the user has installed. `kind="dll"` would allow `winapi` to link to a specific version of that dll and ensure the symbols are correct for that version. +A real advantage of this feature, however, is the fact that symbols will be *guaranteed* to come from the specified dll. Currently, linking is a very finnicky process where if multiple libraries provide the same symbol the linker will choose one of them to provide the symbol and the user has little control over it. With `kind="dll"` the user is ensured that the symbol will come from the specified dll. + +Sometimes, a crate may know exactly which dll it wants to link against, but which import library it ends up linking against is unknown. In particular the `d3dcompiler.lib` provided by the Windows SDK can link to several different versions of the d3dcompiler dll depending on which version of the Windows SDK the user has installed. `kind="dll"` would allow `winapi` to link to a specific version of that dll and ensure the symbols are correct for that version. This would also allow `winapi` to not have to bundle import libraries for the `pc-windows-gnu` targets, saving on bandwidth and disk space for users. @@ -24,7 +26,7 @@ This would also allow `winapi` to not have to bundle import libraries for the `p When trying to link to a Windows dll, the `dylib` kind may sometimes be unsuitable, and `kind="dll"` can be used instead. A central requirement of `kind="dll"` is that the dll has a stable ABI. Here are some examples of valid reasons to use `kind="dll"`: -* You've had it up to here with trying to create an import library for a dll that has stdcall functions. +* You've had it up to here with trying to create an import library for a dll that has `stdcall` functions. * You're in linking hell with multiple import libraries providing the same symbol but from different dlls. * You know exactly which dll you need a symbol from, but you don't know which version of the dll the import library is going to give you. * You maintain `winapi`. @@ -40,7 +42,7 @@ extern "system" { } ``` -Some symbols are only exported by ordinal from the dll in which case `#[link_ordinal]` may be used: +Some symbols are only exported by ordinal from the dll in which case `#[link_ordinal(..)]` may be used: ```rust #[cfg(windows)] @@ -55,9 +57,9 @@ extern "system" { # Reference-level explanation [reference-level-explanation]: #reference-level-explanation -Add a new attribute `#[link_ordinal]` taking a single numerical value, such as `#[link_ordinal(116)]`. It can only be specified on symbols in an extern block using `kind="dll"`. +Add a new attribute `#[link_ordinal]` taking a single unsuffixed integer value, such as `#[link_ordinal(116)]`. It can only be specified on symbols in an extern block using `kind="dll"`. -Add a new value `dll` to the `kind` property of the `link` attribute. When this kind is specified, the `name` must explicitly include the extension. In addition, for all items in the associated extern block Rust will *keep* the symbol mangled, instead of having an unmangled symbol. Rust will emit an idata section that maps from the *mangled* symbol to a symbol in the specified dll. The symbol in the dll that the idata section maps to depends on which attributes are specified on the item in question: +Add a new value `dll` to the `kind` property of the `link` attribute. When this kind is specified, the `name` must explicitly include the extension. In addition, for all items in the associated extern block, Rust will *keep* the symbol mangled, instead of having an unmangled symbol. Rust will emit an idata section that maps from the *mangled* symbol to a symbol in the specified dll. The symbol in the dll that the idata section maps to depends on which attributes are specified on the item in question: * If `#[link_ordinal]` is specified the idata section will map from the mangled symbol to the ordinal specified in the dll. * If `#[link_name]` is specified the idata section will map from the mangled symbol to the name specified in the dll, without any calling convention decorations added. If calling convention decorations are desired they must be specified explicitly in the value of the `#[link_name]` attribute. @@ -94,7 +96,7 @@ Delphi is a native language that has the ability to import symbols from dlls wit # Future possibilities [future-possibilities]: #future-possibilities -With the features described in this RFC, we would be one step closer towards a fully standalone pure Rust target for Windows that does not rely on any external libraries (aside from the obvious and unavoidable runtime dependence on system libraries), allowing for easy installation and incredibly easy cross compilation. +With the features described in this RFC, we would be one step closer towards a fully standalone pure Rust target for Windows that does not rely on any external libraries (aside from the obvious and unavoidable runtime dependence on system libraries), allowing for easy installation and easy cross compilation. If that were to happen, we'd no longer need to pretend the pc-windows-gnu toolchain is standalone, and we'd be able to stop bundling MinGW bits entirely in favor of the user's own MinGW installation, thereby resolving a bunch of issues such as [rust-lang/rust#53454](https://github.com/rust-lang/rust/issues/53454). From 68f74a46175180879e9cff501347d1e61787fe91 Mon Sep 17 00:00:00 2001 From: Peter Atashian Date: Thu, 31 Jan 2019 21:13:59 -0500 Subject: [PATCH 09/14] no_mangle --- text/0000-dll-kind.md | 1 + 1 file changed, 1 insertion(+) diff --git a/text/0000-dll-kind.md b/text/0000-dll-kind.md index c6c7ab396d2..a6c9a48fa68 100644 --- a/text/0000-dll-kind.md +++ b/text/0000-dll-kind.md @@ -65,6 +65,7 @@ Add a new value `dll` to the `kind` property of the `link` attribute. When this * If `#[link_name]` is specified the idata section will map from the mangled symbol to the name specified in the dll, without any calling convention decorations added. If calling convention decorations are desired they must be specified explicitly in the value of the `#[link_name]` attribute. * If both `#[link_ordinal]` and `#[link_name]` are specified, an error will be emitted. * If neither `#[link_ordinal]` nor `#[link_name]` are specified, the idata section will map from the mangled symbol to its unmangled equivalent in the dll. The unmangled symbol will *not* have calling convention decorations. +* If `#[no_mangle]` is specified an error will be emitted. The idata section that is produced is equivalent to the idata sections found in import libraries, and should result in identical code generation by the linker. From 21dbfbaaa53b157f80ea8acdefb20bdf9cdbdef5 Mon Sep 17 00:00:00 2001 From: Peter Atashian Date: Fri, 1 Feb 2019 01:24:31 -0500 Subject: [PATCH 10/14] Expand on future possibilities a bit more --- text/0000-dll-kind.md | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/text/0000-dll-kind.md b/text/0000-dll-kind.md index a6c9a48fa68..f0b5280c871 100644 --- a/text/0000-dll-kind.md +++ b/text/0000-dll-kind.md @@ -91,16 +91,14 @@ Delphi is a native language that has the ability to import symbols from dlls wit # Unresolved questions [unresolved]: #unresolved-questions -* Bikeshedding on attribute names. -* Should this feature be extended to other platforms? +Whether there are any unresolved questions is an unresolved question. # Future possibilities [future-possibilities]: #future-possibilities -With the features described in this RFC, we would be one step closer towards a fully standalone pure Rust target for Windows that does not rely on any external libraries (aside from the obvious and unavoidable runtime dependence on system libraries), allowing for easy installation and easy cross compilation. - -If that were to happen, we'd no longer need to pretend the pc-windows-gnu toolchain is standalone, and we'd be able to stop bundling MinGW bits entirely in favor of the user's own MinGW installation, thereby resolving a bunch of issues such as [rust-lang/rust#53454](https://github.com/rust-lang/rust/issues/53454). - -A future extension of this feature would be the ability to optionally lazily load such external functions, since Rust would naturally have all the information required to do so. - -Also users would stop complaining about having to install several gigabytes of VC++ just to link their Rust binaries. +* With the features described in this RFC, we would be one step closer towards a fully standalone pure Rust target for Windows that does not rely on any external libraries (aside from the obvious and unavoidable runtime dependence on system libraries), allowing for easy installation and easy cross compilation. +** If that were to happen, we'd no longer need to pretend the pc-windows-gnu toolchain is standalone, and we'd be able to stop bundling MinGW bits entirely in favor of the user's own MinGW installation, thereby resolving a bunch of issues such as [rust-lang/rust#53454](https://github.com/rust-lang/rust/issues/53454). +** Also with that pure Rust target users would stop complaining about having to install several gigabytes of VC++ just to link their Rust binaries. +* A future extension of this feature would be the ability to optionally lazily load such external functions, since Rust would naturally have all the information required to do so. This would allow users to use functions that may not exist, and be able to write fallback code for older versions. +* Another future extension would be to extend this feature to support shared libraries on other platform, as they could also benefit from the ability to be more precise about linking. For example, on Linux and other platforms using ELF shared libraries, the compiler would emit an ELF `NEEDED` entry for the specified shared library name, and an undefined symbol for each function declared. (On ELF platforms, using the `link_ordinal` attribute would produce an error.) On such platforms, the `link_name` attribute may also specify a symbol name that includes a symbol version, including the `@@`. +** Windows, however, should be the priority and figuring out details of support for other platforms should **not** block implementation and stabilization of this feature on Windows. From 20d63b0ce2958143c8aff61220af022fba382be1 Mon Sep 17 00:00:00 2001 From: Peter Atashian Date: Fri, 1 Feb 2019 01:48:12 -0500 Subject: [PATCH 11/14] Information on idata sections and import libraries. --- text/0000-dll-kind.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/text/0000-dll-kind.md b/text/0000-dll-kind.md index f0b5280c871..c5407368b63 100644 --- a/text/0000-dll-kind.md +++ b/text/0000-dll-kind.md @@ -67,7 +67,10 @@ Add a new value `dll` to the `kind` property of the `link` attribute. When this * If neither `#[link_ordinal]` nor `#[link_name]` are specified, the idata section will map from the mangled symbol to its unmangled equivalent in the dll. The unmangled symbol will *not* have calling convention decorations. * If `#[no_mangle]` is specified an error will be emitted. -The idata section that is produced is equivalent to the idata sections found in import libraries, and should result in identical code generation by the linker. +[idata section]: https://docs.microsoft.com/en-us/windows/desktop/debug/pe-format#the-idata-section +[import libraries]: https://docs.microsoft.com/en-us/windows/desktop/debug/pe-format#import-library-format + +The [idata section] that is produced is equivalent to the idata sections found in [import libraries], and should result in identical code generation by the linker. # Drawbacks [drawbacks]: #drawbacks From bcc70fac6f222aa1a6903fb19d5d86de1b759609 Mon Sep 17 00:00:00 2001 From: Peter Atashian Date: Fri, 1 Feb 2019 01:56:58 -0500 Subject: [PATCH 12/14] raw-dylib or something. I dunno. --- text/0000-dll-kind.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/text/0000-dll-kind.md b/text/0000-dll-kind.md index c5407368b63..ff156c9542e 100644 --- a/text/0000-dll-kind.md +++ b/text/0000-dll-kind.md @@ -6,7 +6,7 @@ # Summary [summary]: #summary -Extend the `#[link]` attribute by adding a new kind `kind="dll"` for use on Windows which emits idata sections for the items in the attached `extern` block, so they may be linked against without linking against an import library. Also add a `#[link_ordinal]` attribute for specifying symbols that are actually ordinals. +Extend the `#[link]` attribute by adding a new kind `kind="raw-dylib"` for use on Windows which emits idata sections for the items in the attached `extern` block, so they may be linked against without linking against an import library. Also add a `#[link_ordinal]` attribute for specifying symbols that are actually ordinals. # Motivation [motivation]: #motivation @@ -15,16 +15,16 @@ Extend the `#[link]` attribute by adding a new kind `kind="dll"` for use on Wind Traditionally, to link against a [dll], the program must actually link against an import library. For example to depend on some symbols from `kernel32.dll` the program links to `kernel32.lib`. However, this requires that the correct import libraries be available to link against, and for third party libraries that are only distributed as a dll creating an import library can be quite difficult, especially given that `lib.exe` is incapable of creating an import library that links to `stdcall` symbols. -A real advantage of this feature, however, is the fact that symbols will be *guaranteed* to come from the specified dll. Currently, linking is a very finnicky process where if multiple libraries provide the same symbol the linker will choose one of them to provide the symbol and the user has little control over it. With `kind="dll"` the user is ensured that the symbol will come from the specified dll. +A real advantage of this feature, however, is the fact that symbols will be *guaranteed* to come from the specified dll. Currently, linking is a very finnicky process where if multiple libraries provide the same symbol the linker will choose one of them to provide the symbol and the user has little control over it. With `kind="raw-dylib"` the user is ensured that the symbol will come from the specified dll. -Sometimes, a crate may know exactly which dll it wants to link against, but which import library it ends up linking against is unknown. In particular the `d3dcompiler.lib` provided by the Windows SDK can link to several different versions of the d3dcompiler dll depending on which version of the Windows SDK the user has installed. `kind="dll"` would allow `winapi` to link to a specific version of that dll and ensure the symbols are correct for that version. +Sometimes, a crate may know exactly which dll it wants to link against, but which import library it ends up linking against is unknown. In particular the `d3dcompiler.lib` provided by the Windows SDK can link to several different versions of the d3dcompiler dll depending on which version of the Windows SDK the user has installed. `kind="raw-dylib"` would allow `winapi` to link to a specific version of that dll and ensure the symbols are correct for that version. This would also allow `winapi` to not have to bundle import libraries for the `pc-windows-gnu` targets, saving on bandwidth and disk space for users. # Guide-level explanation [guide-level-explanation]: #guide-level-explanation -When trying to link to a Windows dll, the `dylib` kind may sometimes be unsuitable, and `kind="dll"` can be used instead. A central requirement of `kind="dll"` is that the dll has a stable ABI. Here are some examples of valid reasons to use `kind="dll"`: +When trying to link to a Windows dll, the `dylib` kind may sometimes be unsuitable, and `kind="raw-dylib"` can be used instead. A central requirement of `kind="raw-dylib"` is that the dll has a stable ABI. Here are some examples of valid reasons to use `kind="raw-dylib"`: * You've had it up to here with trying to create an import library for a dll that has `stdcall` functions. * You're in linking hell with multiple import libraries providing the same symbol but from different dlls. @@ -35,7 +35,7 @@ Here is an example of usage: ```rust #[cfg(windows)] -#[link(name = "kernel32.dll", kind = "dll")] +#[link(name = "kernel32.dll", kind = "raw-dylib")] #[allow(non_snake_case)] extern "system" { fn GetStdHandle(nStdHandle: u32) -> *mut u8; @@ -46,7 +46,7 @@ Some symbols are only exported by ordinal from the dll in which case `#[link_ord ```rust #[cfg(windows)] -#[link(name = "ws2_32.dll", kind = "dll")] +#[link(name = "ws2_32.dll", kind = "raw-dylib")] #[allow(non_snake_case)] extern "system" { #[link_ordinal(116)] @@ -57,9 +57,9 @@ extern "system" { # Reference-level explanation [reference-level-explanation]: #reference-level-explanation -Add a new attribute `#[link_ordinal]` taking a single unsuffixed integer value, such as `#[link_ordinal(116)]`. It can only be specified on symbols in an extern block using `kind="dll"`. +Add a new attribute `#[link_ordinal]` taking a single unsuffixed integer value, such as `#[link_ordinal(116)]`. It can only be specified on symbols in an extern block using `kind="raw-dylib"`. -Add a new value `dll` to the `kind` property of the `link` attribute. When this kind is specified, the `name` must explicitly include the extension. In addition, for all items in the associated extern block, Rust will *keep* the symbol mangled, instead of having an unmangled symbol. Rust will emit an idata section that maps from the *mangled* symbol to a symbol in the specified dll. The symbol in the dll that the idata section maps to depends on which attributes are specified on the item in question: +Add a new possible value `raw-dylib` to the `kind` property of the `link` attribute. When this kind is specified, the `name` must explicitly include the extension. In addition, for all items in the associated extern block, Rust will *keep* the symbol mangled, instead of having an unmangled symbol. Rust will emit an idata section that maps from the *mangled* symbol to a symbol in the specified dll. The symbol in the dll that the idata section maps to depends on which attributes are specified on the item in question: * If `#[link_ordinal]` is specified the idata section will map from the mangled symbol to the ordinal specified in the dll. * If `#[link_name]` is specified the idata section will map from the mangled symbol to the name specified in the dll, without any calling convention decorations added. If calling convention decorations are desired they must be specified explicitly in the value of the `#[link_name]` attribute. From 3b456f638037d94e428229bd1954782dd943de5f Mon Sep 17 00:00:00 2001 From: Peter Atashian Date: Fri, 1 Feb 2019 04:14:54 -0500 Subject: [PATCH 13/14] I hate markdown --- text/0000-dll-kind.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/text/0000-dll-kind.md b/text/0000-dll-kind.md index ff156c9542e..b7e20978702 100644 --- a/text/0000-dll-kind.md +++ b/text/0000-dll-kind.md @@ -100,8 +100,8 @@ Whether there are any unresolved questions is an unresolved question. [future-possibilities]: #future-possibilities * With the features described in this RFC, we would be one step closer towards a fully standalone pure Rust target for Windows that does not rely on any external libraries (aside from the obvious and unavoidable runtime dependence on system libraries), allowing for easy installation and easy cross compilation. -** If that were to happen, we'd no longer need to pretend the pc-windows-gnu toolchain is standalone, and we'd be able to stop bundling MinGW bits entirely in favor of the user's own MinGW installation, thereby resolving a bunch of issues such as [rust-lang/rust#53454](https://github.com/rust-lang/rust/issues/53454). -** Also with that pure Rust target users would stop complaining about having to install several gigabytes of VC++ just to link their Rust binaries. + * If that were to happen, we'd no longer need to pretend the pc-windows-gnu toolchain is standalone, and we'd be able to stop bundling MinGW bits entirely in favor of the user's own MinGW installation, thereby resolving a bunch of issues such as [rust-lang/rust#53454](https://github.com/rust-lang/rust/issues/53454). + * Also with that pure Rust target users would stop complaining about having to install several gigabytes of VC++ just to link their Rust binaries. * A future extension of this feature would be the ability to optionally lazily load such external functions, since Rust would naturally have all the information required to do so. This would allow users to use functions that may not exist, and be able to write fallback code for older versions. * Another future extension would be to extend this feature to support shared libraries on other platform, as they could also benefit from the ability to be more precise about linking. For example, on Linux and other platforms using ELF shared libraries, the compiler would emit an ELF `NEEDED` entry for the specified shared library name, and an undefined symbol for each function declared. (On ELF platforms, using the `link_ordinal` attribute would produce an error.) On such platforms, the `link_name` attribute may also specify a symbol name that includes a symbol version, including the `@@`. -** Windows, however, should be the priority and figuring out details of support for other platforms should **not** block implementation and stabilization of this feature on Windows. + * Windows, however, should be the priority and figuring out details of support for other platforms should **not** block implementation and stabilization of this feature on Windows. From b0ca3b850f78b5234d04ae1e3506faf335311475 Mon Sep 17 00:00:00 2001 From: Peter Atashian Date: Thu, 7 Feb 2019 15:56:26 -0500 Subject: [PATCH 14/14] The sacrifices I have to make in the name of cross platform... --- text/{0000-dll-kind.md => 0000-raw-dylib-kind.md} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename text/{0000-dll-kind.md => 0000-raw-dylib-kind.md} (99%) diff --git a/text/0000-dll-kind.md b/text/0000-raw-dylib-kind.md similarity index 99% rename from text/0000-dll-kind.md rename to text/0000-raw-dylib-kind.md index b7e20978702..4f00f3d0600 100644 --- a/text/0000-dll-kind.md +++ b/text/0000-raw-dylib-kind.md @@ -1,4 +1,4 @@ -- Feature Name: dll_kind +- Feature Name: raw_dylib_kind - Start Date: 2019-01-22 - RFC PR: (leave this empty) - Rust Issue: (leave this empty)