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