Skip to content

Commit d08e636

Browse files
committed
draft 1
1 parent 017d661 commit d08e636

File tree

1 file changed

+152
-0
lines changed

1 file changed

+152
-0
lines changed

text/0000-dllimport.md

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
- Feature Name: dllimport
2+
- Start Date: 2016-08-13
3+
- RFC PR: (leave this empty)
4+
- Rust Issue: (leave this empty)
5+
6+
# Summary
7+
[summary]: #summary
8+
9+
Make compiler aware of the association between library names adorning `extern` blocks
10+
and symbols defined within the block. Add attributes and command line switches that leverage
11+
this association.
12+
13+
# Motivation
14+
[motivation]: #motivation
15+
16+
Most of the time a linkage directive is only needed to inform the linker about
17+
what native libraries need to be linked into a program. On some platforms,
18+
however, the compiler needs more detailed knowledge about what's being linked
19+
from where in order to ensure that symbols are wired up correctly.
20+
21+
On Windows, when a symbol is imported from a dynamic library, the code that accesses
22+
this symbol must be generated differently than for symbols imported from a static library.
23+
24+
Currently the compiler is not aware of associations between the libraries and symbols
25+
imported from them, so it cannot alter code generation based on library kind.
26+
27+
# Detailed design
28+
[design]: #detailed-design
29+
30+
### Library <-> symbol association
31+
32+
The compiler shall assume that symbols defined within extern block
33+
are imported from the library mentioned in the `#[link]` attribute adorning the block.
34+
35+
### Changes to code generation
36+
37+
On platforms other than Windows the above association will have no effect.
38+
On Windows, however, `#[link(..., kind="dylib")` shall be presumed to mean linking to a dll,
39+
whereas `#[link(..., kind="static")` shall mean static linking. In the former case, all symbols
40+
associated with that library will be marked with LLVM [dllimport][1] storage class.
41+
42+
[1]: http://llvm.org/docs/LangRef.html#dll-storage-classes
43+
44+
### Library name and kind variance
45+
46+
Many native libraries are linked via the command line via `-l` which is passed
47+
in through Cargo build scripts instead of being written in the source code
48+
itself. As a recap, a native library may change names across platforms or
49+
distributions or it may be linked dynamically in some situations and
50+
statically in others which is why build scripts are leveraged to make these
51+
dynamic decisions. In order to support this kind of dynamism, the following
52+
modifications are proposed:
53+
54+
- A new library kind, "abstract". An "abstract" library by itself does not
55+
cause any libraries to be linked. Its purpose is to establish an identifier,
56+
that may be later referred to from the command line flags.
57+
- Extend syntax of the `-l` flag to `-l [KIND=]lib[:NEWNAME]`. The `NEWNAME`
58+
part may be used to override name of a library specified in the source.
59+
- Add new meaning to the `KIND` part: if "lib" is already specified in the source,
60+
this will override its kind with KIND. Note that this override is possible only
61+
for libraries defined in the current crate.
62+
63+
Example:
64+
65+
```rust
66+
// mylib.rs
67+
#[link(name = "foo", kind="dylib")]
68+
extern {
69+
// dllimport applied
70+
}
71+
72+
#[link(name = "bar", kind="static")]
73+
extern {
74+
// dllimport not applied
75+
}
76+
77+
#[link(name = "baz", kind="abstract")]
78+
extern {
79+
// dllimport not applied, "baz" not linked
80+
}
81+
```
82+
83+
```
84+
rustc mylib.rs -l static=foo # change foo's kind to "static", dllimport will not be applied
85+
rustc mylib.rs -l foo:newfoo # link newfoo instead of foo
86+
rustc mylib.rs -l dylib=baz:quoox # specify baz's kind as "dylib", change link name to quoox.
87+
```
88+
89+
### Unbundled static libs (optional)
90+
91+
It had been pointed out that sometimes one may wish to link to a static system library
92+
(i.e. one that is always available to the linker) without bundling it into .lib's and .rlib's.
93+
For this use case we'll introduce another library "kind", "static-nobundle".
94+
Such libraries would be treated in the same way as "static", minus the bundling.
95+
96+
# Drawbacks
97+
[drawbacks]: #drawbacks
98+
99+
For libraries to work robustly on MSVC, the correct `#[link]` annotation will
100+
be required. Most cases will "just work" on MSVC due to the compiler strongly
101+
favoring static linkage, but any symbols imported from a dynamic library or
102+
exported as a Rust dynamic library will need to be tagged appropriately to
103+
ensure that they work in all situations. Worse still, the `#[link]` annotations
104+
on an `extern` block are not required on any other platform to work correctly,
105+
meaning that it will be common that these attributes are left off by accident.
106+
107+
108+
# Alternatives
109+
[alternatives]: #alternatives
110+
111+
- Instead of enhancing `#[link]`, a `#[linked_from = "foo"]` annotation could be added.
112+
This has the drawback of not being able to handle native libraries whose
113+
name is unpredictable across platforms in an easy fashion, however.
114+
Additionally, it adds an extra attribute to the comipler that wasn't known
115+
previously.
116+
117+
- Support a `#[dllimport]` on extern blocks (or individual symbols, or both).
118+
This has the following drawbacks, however:
119+
- This attribute would duplicate the information already provided by
120+
`#[link(kind="...")]`.
121+
- It is not always known whether `#[dllimport]` is needed. Native
122+
libraires are not always known whether they're linked dynamically or
123+
statically (e.g. that's what a build script decides), so `dllimport`
124+
will need to be guarded by `cfg_attr`.
125+
126+
- When linking native libraries, the compiler could attempt to locate each
127+
library on the filesystem and probe the contents for what symbol names are
128+
exported from the native library. This list could then be cross-referenced
129+
with all symbols declared in the program locally to understand which symbols
130+
are coming from a dylib and which are being linked statically. Some downsides
131+
of this approach may include:
132+
133+
- It's unclear whether this will be a performant operation and not cause
134+
undue runtime overhead during compiles.
135+
136+
- On Windows linking to a DLL involves linking to its "import library", so
137+
it may be difficult to know whether a symbol truly comes from a DLL or
138+
not.
139+
140+
- Locating libraries on the system may be difficult as the system linker
141+
often has search paths baked in that the compiler does not know about.
142+
143+
- As was already mentioned, "kind" override can affect codegen of the current crate only.
144+
This overloading the `-l` flag for this purpose may be confusinfg to developers.
145+
A new codegen flag might be a better fit for this, for example `-C libkind=KIND=LIB`.
146+
147+
# Unresolved questions
148+
[unresolved]: #unresolved-questions
149+
150+
- Should un-overridden "abstract" kind cause an error, a warning, or be silently ignored?
151+
- Do we even need "abstract"? Since kind can be overridden, there's no harm in providing a default in the source.
152+
- Should we allow dropping a library specified in the source from linking via `-l lib:` (i.e. "rename to empty")?

0 commit comments

Comments
 (0)