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. ![]()