I have something working in C, and I'm getting an error trying to do the same in Rust. If anyone can help, I'd really appreciate it!
Background
I need to build an executable by linking two .o
files which are built separately on different machines. Here's a minimal example in C:
app.c
char* run() {
return "hello!";
}
host.c
#include <stdio.h>
extern char* run();
int main() {
printf("app says: %s\n", run());
return 0;
}
Here's how I build and run the combined application:
$ clang -c host.c -o host.o
$ clang -c app.c -o app.o
$ ld -lc host.o app.o -o app
$ ./app
app says: hello!
Importantly, I have to build the executable by building host.c
and app.c
separately (because in the actual use case this would happen on separate machines). Once I have host.o
and app.o
, I can link them together with ld
to get the app
executable.
Rust Version
I'm trying to repeat this process with a host.rs
instead of host.c
, leaving everything else the same.
Here's the first host.rs
implementation I tried:
host.rs
use std::ffi::CStr;
use std::os::raw::c_char;
extern "C" {
fn run() -> *const c_char;
}
pub fn main() {
let c_str = unsafe { CStr::from_ptr(run()) };
println!("app says: \"{}\"", c_str.to_str().unwrap());
}
I tried to build this, and got:
$ rustc host.rs -o host.o
error: linking with `cc` failed: exit code: 1
|
= note: "cc" [ …lots of cc args snipped… ]
= note: Undefined symbols for architecture x86_64:
"_run", referenced from:
host::main::h9e67e7b31c940a95 in host.host.7rcbfp3g-cgu.4.rcgu.o
ld: symbol(s) not found for architecture x86_64
Next I tried adding #![crate_type = "staticlib"]
to the top of host.rs
. That successfully generated host.o
, but then the next step in the process failed - the ld
call:
$ ld -lc host.o app.o -o app
Undefined symbols for architecture x86_64:
"_main", referenced from:
implicit entry/start for main executable
ld: symbol(s) not found for architecture x86_64
I tried messing around with a few things, including trying #![crate_type = "lib"]
instead of staticlib
, and also changing the function's name from main
to start
. I even tried this trick to avoid LLVM name mangling:
#[export_name = "\x01start"]
pub extern "C" fn start(_argc: isize, _argv: *const *const u8) -> isize {
However, even after having removed all instances of the string main
from all source files, and recompiling, ld
is still complaining about not finding the symbol _main
. (This is on macOS 10.15.6, if that's relevant.)
I'm not sure what I should be telling rustc
(or maybe I should try getting cargo
involved?) to get it to emit the same .o
file that the C version is doing, but I assume there's some combination of arguments that will do the trick!
Any help would be greatly appreciated.