Rustc equivalent of clang's "-undefined dynamic_lookup"?

I have two Hello World programs, one in C and one in Rust.

They both define an extern function called foo, which I want to leave undefined and have dynamically linked into the final executable binary. The C file looks like this:

#include <stdio.h>

extern int foo(int arg1);

int main() {
   printf("Hello World! %d\n", foo(1));
   return 0;
}

The Rust version looks like this:

#[link(name = "foo", kind = "dylib")]
extern "C" {
    fn foo(x: i64) -> i64;
}

fn main() {
    println!("Hello World! {}", unsafe { foo(1) });
}

I can compile the C version successfully to a binary executable that dynamically links foo:

$ clang c_hello.c -undefined dynamic_lookup -o c_hello

When I run the binary, it crashes at runtime - which is exactly what I'm looking for here!

dyld: lazy symbol binding failed: Symbol not found: _foo

However, when I run rustc on the Rust version, it doesn't successfully produce a binary:

$ rustc rs_hello.rs
error: linking with `cc` failed: exit code: 1
  |
  = note: "cc" "-m64" "-arch" "x86_64" "-L" [ ... lots of arguments omitted ... ]
  = note: ld: library not found for -lfoo
          clang: error: linker command failed with exit code 1 (use -v to see invocation)

I thought that maybe this would fix it:

$ rustc -C link-args="-undefined dynamic_lookup" rs_hello.rs

...but it didn't. All it did was add those arguments to the end of the linker invocation:

… "-lSystem" "-lresolv" "-lc" "-lm" "-liconv" "-undefined" "dynamic_lookup"

...but linking still failed with the exact same ld: library not found for -lfoo error.

I also tried link-arg="-undefined dynamic_lookup" instead of -link-args="-undefined dynamic_lookup" (link-arg instead of link-args) which did the same as link-args except then the end of the invocation looked like this:

… "-lSystem" "-lresolv" "-lc" "-lm" "-liconv" "-undefined dynamic_lookup"

...and there was a different error message:

  = note: ld: invalid option to -undefined [ warning | error | suppress | dynamic_lookup ]
          clang: error: linker command failed with exit code 1 (use -v to see invocation)

Is there some way to do this dynamic linking with rustc or cargo?

I believe the flags you are looking for are -C link-arg=-undefined -C link-arg=dynamic_lookup.

We needed that when writing Python bindings for a project on MacOS and I ended up pulling the extra rustc flags into our config.toml for convenience.

2 Likes

Interesting! I tried this:

rustc -C link-arg=-undefined -C link-arg=dynamic_lookup rs_hello.rs

...and it had the same output as what I'd tried previously:

rustc -C link-args="-undefined dynamic_lookup" rs_hello.rs

...which is to say, it still gave a linker error of ld: library not found for -lfoo

Considering this worked for you, I wonder what the difference might be for this small example. :thinking:

You will need to tell the linker where to find foo. rustc -Lnative=dir/containing/foo or rustc -l path/to/libfoo.dylib I think.

1 Like

Try omitting the #[link] attribute if that still doesn't work

1 Like

Omitting the #[link] attribute worked!

I still needed to do rustc -C link-args="-undefined dynamic_lookup" rs_hello.rs but removing #[link(name = "foo", kind = "dylib")] made that succeed where before it was failing.

Thanks so much! :smiley:

1 Like