Closed
Description
While spending some time playing with a ncurses wrapper library (one of many), I encountered the following odd linking problem. I have one crate which attempts to link to the system ncurses library via #[link_args="-lncurses"]
, and then a main program that pulls in the first crate.
However, the crate that links to the system ncurses library is also exposing functionality via type-parametric methods, and something seems to go wrong with the linkage due to this, AFAICT.
Here is the example:
main crate (call it ncurses.rs
):
#[link(name="ncurses",vers="5.7")];
use std::libc::c_int;
use ncurses_core::{A_NORMAL, A_STANDOUT, attrset};
mod ncurses_core {
use std::libc::c_int;
#[link_args = "-lncurses"]
extern { pub fn attrset (_:c_int) -> c_int; }
pub static A_NORMAL: c_int = 0;
pub static A_STANDOUT: c_int = (1u << 16) as c_int;
}
pub struct Context;
pub enum attr { normal = A_NORMAL, standout = A_STANDOUT }
#[cfg(not(show_bug))]
impl Context {
pub fn attrset2(&mut self, attrs: attrv) {
let i = attrs.encode_direct();
unsafe { attrset(i); }
}
}
#[cfg(show_bug)]
impl Context {
pub fn attrset2<A:EncodesAttrs>(&mut self, attrs: A) {
let i = attrs.encode_via_trait();
unsafe { attrset(i); }
}
}
pub trait EncodesAttrs { fn encode_via_trait(&self) -> c_int; }
impl<'a> EncodesAttrs for attrv<'a> {
fn encode_via_trait(&self) -> c_int { encode_attrs(self.contents) }
}
pub struct attrv<'a> { contents: &'a [attr] }
pub fn attrv<'a>(av: &'a [attr]) -> attrv<'a> { attrv{ contents: av } }
impl<'a> attrv<'a> {
pub fn encode_direct(&self) -> c_int { encode_attrs(self.contents) }
}
fn encode_attrs(_attrs: &[attr]) -> c_int { 0 }
main program (ncurses-intro.rs
):
extern mod ncurses;
fn main() {
let mut context = ncurses::Context;
context.attrset2(ncurses::attrv(&[ncurses::standout]));
}
Invocation that works (by sidestepping type-parametricity):
% rustc --lib ncurses.rs && rustc -L. ncurses-intro.rs
warning: missing crate link meta `package_id`, using `ncurses` as default
Invocation that illustrates the bug (by using the desired type parametric form):
% rustc --cfg show_bug --lib ncurses.rs && rustc -L. ncurses-intro.rs
warning: missing crate link meta `package_id`, using `ncurses` as default
error: linking with `cc` failed: exit code: 1
note: cc arguments: -L/Users/fklock/opt/rust-dbg/lib/rustc/x86_64-apple-darwin/lib -m64 -o ncurses-intro ncurses-intro.o -L/Users/fklock/opt/rust-dbg/lib/rustc/x86_64-apple-darwin/lib -lstd-6425b930ca146ae9-0.9-pre -L/Users/fklock/opt/rust-dbg/lib/rustc/x86_64-apple-darwin/lib -lrustuv-a13edc95d75df17-0.9-pre -L. -lncurses-dd4798ddf43ebf9-5.7 -L. -L/Users/fklock/Dev/Rust/rust-curses/.rust -L/Users/fklock/Dev/Rust/rust-curses -lmorestack -lrustrt -Wl,-rpath,@loader_path/../../../opt/rust-dbg/lib/rustc/x86_64-apple-darwin/lib -Wl,-rpath,@loader_path/. -Wl,-rpath,/Users/fklock/opt/rust-dbg/lib/rustc/x86_64-apple-darwin/lib -Wl,-rpath,/Users/fklock/Dev/Rust/rust-curses
note: ld: warning: directory not found for option '-L/Users/fklock/Dev/Rust/rust-curses/.rust'
Undefined symbols for architecture x86_64:
"_attrset", referenced from:
Context::attrset2::h3513932d42d079afxaM::v0.0 in ncurses-intro.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
error: aborting due to previous error
task 'rustc' failed at 'explicit failure', /Users/fklock/Dev/Mozilla/rust.git/src/libsyntax/diagnostic.rs:101
task '<main>' failed at 'explicit failure', /Users/fklock/Dev/Mozilla/rust.git/src/librustc/lib.rs:396
Metadata
Metadata
Assignees
Type
Projects
Milestone
Relationships
Development
No branches or pull requests
Activity
alexcrichton commentedon Nov 18, 2013
The reason that this is happening is that generic code is instantiated in the client crate, and the client crate is not linking to ncurses.
This was an explicit decision as part of 2b9c774 to stop propagating link arguments across crates. The reason for doing so is that if we unconditionally propagate linker arguments there is no way to have a build dependency that is not distributed alongside a rust library.
I believe that this can be revisited after #10528 lands because that already adds back propagation to a certain degree (one which I am much more comfortable with).
pnkfelix commentedon Nov 18, 2013
Okay, I'll assign this to myself as a reminder to double-check on it (and hopefully close it after we've landed #10528, assuming that enables reasonable propagation).
alexcrichton commentedon Nov 18, 2013
The static linking pull request will not close this in its current incarnation. I'd want to talk about this more broadly to make sure that we want to continue to propagate dependencies, but I believe that we'll be much more amenable to it this time around rather than before.
alexcrichton commentedon Dec 1, 2013
Closing as a dupe of #10743
Auto merge of rust-lang#10543 - blyxyas:tests_outside_test_module, r=…
Auto merge of rust-lang#10578 - blyxyas:items_after_test_module, r=dswij