Skip to content

linking problem on extern "C" fn called via trait method (on type parameter) in other crate #10543

Closed
@pnkfelix

Description

@pnkfelix

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

No one assigned

    Labels

    A-linkageArea: linking into static, shared libraries and binaries

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions