RFC 1717: dllimport

tools (attributes | linkage)

Summary

Make compiler aware of the association between library names adorning extern blocks and symbols defined within the block. Add attributes and command line switches that leverage this association.

Motivation

Most of the time a linkage directive is only needed to inform the linker about what native libraries need to be linked into a program. On some platforms, however, the compiler needs more detailed knowledge about what's being linked from where in order to ensure that symbols are wired up correctly.

On Windows, when a symbol is imported from a dynamic library, the code that accesses this symbol must be generated differently than for symbols imported from a static library.

Currently the compiler is not aware of associations between the libraries and symbols imported from them, so it cannot alter code generation based on library kind.

Detailed design

Library <-> symbol association

The compiler shall assume that symbols defined within extern block are imported from the library mentioned in the #[link] attribute adorning the block.

Changes to code generation

On platforms other than Windows the above association will have no effect. On Windows, however, #[link(..., kind="dylib") shall be presumed to mean linking to a dll, whereas #[link(..., kind="static") shall mean static linking. In the former case, all symbols associated with that library will be marked with LLVM dllimport storage class.

Library name and kind variance

Many native libraries are linked via the command line via -l which is passed in through Cargo build scripts instead of being written in the source code itself. As a recap, a native library may change names across platforms or distributions or it may be linked dynamically in some situations and statically in others which is why build scripts are leveraged to make these dynamic decisions. In order to support this kind of dynamism, the following modifications are proposed:

Example:

// mylib.rs
#[link(name="foo", kind="dylib")]
extern {
    // dllimport applied
}

#[link(name="bar", kind="static")]
extern {
    // dllimport not applied
}

#[link(name="baz")]
extern {
    // kind defaults to "dylib", dllimport applied
}
rustc mylib.rs -l static=foo # change foo's kind to "static", dllimport will not be applied
rustc mylib.rs -l foo:newfoo # link newfoo instead of foo, keeping foo's kind as "dylib"
rustc mylib.rs -l dylib=bar # change bar's kind to "dylib", dllimport will be applied

Unbundled static libs (optional)

It had been pointed out that sometimes one may wish to link to a static system library (i.e. one that is always available to the linker) without bundling it into .lib's and .rlib's. For this use case we'll introduce another library "kind", "static-nobundle". Such libraries would be treated in the same way as "static", except they will not be bundled into the target .lib/.rlib.

Drawbacks

For libraries to work robustly on MSVC, the correct #[link] annotation will be required. Most cases will "just work" on MSVC due to the compiler strongly favoring static linkage, but any symbols imported from a dynamic library or exported as a Rust dynamic library will need to be tagged appropriately to ensure that they work in all situations. Worse still, the #[link] annotations on an extern block are not required on any other platform to work correctly, meaning that it will be common that these attributes are left off by accident.

Alternatives

Unresolved questions