Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
pnkfelix opened this issue Nov 18, 2013 · 4 comments
Labels
A-linkage Area: linking into static, shared libraries and binaries

Comments

@pnkfelix
Copy link
Member

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
@alexcrichton
Copy link
Member

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
Copy link
Member Author

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).

@ghost ghost assigned pnkfelix Nov 18, 2013
@alexcrichton
Copy link
Member

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
Copy link
Member

Closing as a dupe of #10743

@pnkfelix pnkfelix removed their assignment Jun 16, 2014
flip1995 pushed a commit to flip1995/rust that referenced this issue Apr 6, 2023
…flip1995

Add `tests_outside_test_module` lint

Adds `tests_outside_test_module` from rust-lang#10506. This PR **doesn't** close the issue, just resolves task 1.

changelog: [`tests_outside_test_module`]: The lint has been added
flip1995 pushed a commit to flip1995/rust that referenced this issue Apr 23, 2023
Add `items_after_test_module` lint

Resolves task *3* of rust-lang#10506, alongside *1* resolved at rust-lang#10543 in an effort to help standarize a little bit more testing modules.

---

changelog:[`items_after_test_module`]: Added the lint.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-linkage Area: linking into static, shared libraries and binaries
Projects
None yet
Development

No branches or pull requests

2 participants