Linking and Extern

What's the difference between

#[link(name = "libcmt")]
extern {
  fn puts(s: *const u8) -> i32;
}

and

#[link(name = "libcmt")]
extern {}

extern {
  fn puts(s: *const u8) -> i32;
}

The first doesn't seem to compile on Windows, but the latter has no issues

That's very interesting, I'd think these would be equivalent.

When linking to symbols from an import library for a dll, dllimport must be specified for statics while for functions it is optional but recommended.
When linking to symbols from a static library, dllimport must not be specified for statics nor functions.

Extern blocks that are attributed with #[link] will have dllimport specified based on the kind.
If the kind is static or static-nobundle, dllimport will not be specified.
If the kind is dylib, dllimport will be specified.
If the kind is not specified for #[link] then it defaults to dylib which specifies dllimport.
Extern blocks without any #[link] will not have dllimport specified.

You might be fooled into thinking static is the right kind to use, but it is in fact very wrong. Unlike dylib and static-nobundle which simply pass along the library name to the linker which is then responsible for locating it using normal linker search paths, static causes rustc to find the library itself and bundle it into the rlib. This fails when its a static library provided by the system rather than a static library built on the spot by the crate, because rustc does not search the same directories as the linker. Also there's bugs with the bundling itself breaking some static libraries.

2 Likes