Repository navigation
dylib shared libraries will not make public symbols that may be necessary to link inlined code #65610
Description
Activity
- addedA-linkageArea: linking into static, shared libraries and binariesArea: linking into static, shared libraries and binariesT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.Relevant to the compiler team, which will review and decide on the PR/issue.regression-from-stable-to-stablePerformance or correctness regression from one stable version to another.Performance or correctness regression from one stable version to another.
on Oct 19, 2019 Yeah, I can imagine that that doesn't work. Maybe #59752 is related?
cc @Zoxc
You haven't told rustc where that symbol comes from. Try adding
#[link(name = "foo", kind = "static")]on the extern block.Adding the attribute helped, however these symbols are originally linked via command line arguments that
cccrate emits to cargo from the build.rs script. Why the two ways to link in stuff have different behaviour?When you link the library on the command line, rustc doesn't know which symbols are in it, so it won't export any.
Okay, that’s somewhat bad, then, because libraries that rely exclusively on arguments emitted by
ccfor linking purposes are very abound in the ecosystem.We should look at updating the
cc’s documentation to include information about needing the#[link]attribute regardless. cc @alexcrichtonWe could perhaps just consider all reachable extern fns to have static linkage and export them. I'm not sure if there's any problems with that though...
I don't think you need the
kindon the block since the kind is specified on the command line and that overrides what the block says, but yes adding this documentation toccseems fine.- added 2 commits that reference this issue
on Mar 29, 2020 @rustbot modify labels to +I-prioritize
- addedI-prioritizeIssue needs a team member to assess the impact. Will be replaced by P-{low,medium,high,critical}Issue needs a team member to assess the impact. Will be replaced by P-{low,medium,high,critical}
on May 27, 2020 Summary of current situation:
In order for a symbol pulled in from a native library to be exported from a
dylib, Rust has to know that the symbol comes from a static library. This is currently determined by the#[link]attribute attached to the extern block containing those symbols. The kind specified, either via the attribute directly or overridden by a build script later, will determine whether to export the symbol but also has some other effects:kind=dylib. Symbols pulled in will not get exported fromdylibcrates. On Windowsdllimportwill be applied to those symbols.kind=static. Symbols pulled in will get exported fromdylibcrates. On Windowsdllimportwill not be applied to those symbols. Notably, if the native library is linked via a dependency of thedylibcrate and not thedylibdirectly, then it will be unable to link to static libraries provided by the system.kind=static-nobundle. Similar tokind=staticin that symbols will get exported fromdylibcrates anddllimportwill not be applied, but it does always work with static system libraries.- No
kindspecified. A weird case where symbols pulled in will not get exported fromdylibcrates but alsodllimportwill not be applied to those symbols. When trying to link to static system libraries, due tokind=static-nobundlebeing unstable, people will often just not specify thekindso that the library can be found by the linker, anddllimportwill not be applied, however this runs into the problem stated in this issue where the symbol is not exported fromdylibcrates.
Therefore to solve this problem we need to:
- Add documentation stressing the importance of attaching
#[link]attributes to extern blocks and specifying the kind. - Stabilize
kind=static-nobundlein some form.
I’ve seen this mistake one too many times. And it tends to remain that way because just
-lbananaon CLI usually works. A compiler warning would be a great way to do the stressing. For instance:warning: -lbanana was specified on the command line, but no extern block refers to it help: its a problem because…, see [this link] to learn more.possibly could be a clippy lint too.
Note that if symbols are spread across multiple extern blocks, having to annotate each of them with the appropriate
#[link]attribute can cause significant repetition in the linker command line. This is the reason I don't specify#[link]on extern blocks inwinapieven though I should in order to gain the benefits ofdllimport: #38460Also note that on Windows it is possible for a library to have both static and dynamic symbols.
Perhaps it may be worthwhile to allow us to specify whether a symbol comes from a static library or a dynamic library without having to name it. Allowing
#[link(kind="static")]with nonamespecified could be very useful for crate authors to ensure their symbols are exported fromdylibs or have the correctdllimportannotations without running into that linker repetition issue.Reacted by MSxDOS, Jarod and Mic LoAssigning
P-mediumas discussed as part of the Prioritization Working Group process and removingI-prioritize.- addedP-mediumMedium priorityMedium priorityand removedI-prioritizeIssue needs a team member to assess the impact. Will be replaced by P-{low,medium,high,critical}Issue needs a team member to assess the impact. Will be replaced by P-{low,medium,high,critical}
on Jun 3, 2020
When a
dylibcrate has a publicinline(always)functions in it that use, as an implementation, other, private functions, using these public functions from other crates will fail with linkage errors because we fail to "export" the private functions.An example project can be seen here. In this example the
driverdylib crate privatelyexterns a symbol from a static C library and uses it to implement aninline(always)interface/wrapper. Theusercrate then attempts to use theinline(always)wrapper, but linking fails with an error such as this:When inspecting the
libdriver.sowe can see that the extern symbol does indeed exist but is "private":I think we might be un-exporting items too aggressively here. cc @michaelwoerister @oli-obk
Blocks #55617
Regression from 1.36.0 (example builds successfully) to 1.37 (example fails to build).