As I’m sure most people here know, the #[link]
attribute used to link to native libraries for FFI has a kind
option, which can take one of three values:
-
kind = "dylib"
(the default) -
kind = "static
" -
kind = "framework"
(OS X specific)
I’ve been experimenting on Linux, so I’m going to ignore framework for the rest of this post.
The FFI guide describes the meanings of these options, and at least implies that dylibs should be linked against using the “dylib” kind (or more commonly by leaving it out) and static libraries should be linked using the “static” kind, as one would expect from the names. This has been confirmed to me on the pull request that started me looking at this. (After that I experimented with having rustc determine what type of library it was linking and choose the link kind automatically, but it turns out that is a bad idea.)
However, that isn’t actually what the option does internally, nor is it how it is used in practice. At least one test in the rust repository links to static libraries without specifying a kind, and when linking against system libraries one often does not know what form they are going to be provided in on a user’s computer. (This is causing distros trouble with using external LLVM.)
The FFI guide section mentioned above actually does accurately describe what the option does: when compiling an rlib, a “static” library is bundled into the generated file, while a “dylib” library is just recorded as a dependency and not linked until an executable (or dylib) using the rlib is created. This does mean that a “static” library must be an actual static library, because one can’t usefully put a dylib into an archive. The “dylib” kind will, however, work for either a dylib or a static library, and in either case will delay linking it in until creating an executable.
It turns out that this is actually the desired behavior for static libraries much of the time. If the test mentioned above is changed to “correctly” specify that it is linking against a static library, it fails to build with multiply defined symbol errors. In terms of today’s implementation, it seems that the meanings of these options are roughly
-
kind = "static"
== bundled -
kind = "dylib"
== external (available on the system)
and linking against a system library with with the “static” link type will actually break things if it is done in both an executable crate and an rlib crate that it uses.
The current behavior actually seems more useful to me than what appears to have been intended, but it means the names are very confusing.
What I’m wondering is: Does this all seem correct? Do people think the current behavior is a bug? Should the option names or documentation be changed?