esp-rs / esp-idf-template

A "Hello, world!" template of a Rust binary crate for the ESP-IDF framework.
373 stars 44 forks source link

Linkage issues when calling C functions in Rust (C/Rust mixed project) #82

Closed Narukara closed 1 year ago

Narukara commented 1 year ago

In a mixed C/Rust project driven by ESP-IDF, calling a C function from Rust produces strange link errors. And the error occurs only when this C function is not called by other C code across files.

Here is a minimal project to reproduce the error. The first commit is the newly generated project, and the second commit contains the necessary changes.

Use idf.py build to build the project, you will get the following error:

in function `rust_main':
rust_temp_mix.ab522936-cgu.0:(.text.rust_main+0x32): undefined reference to `mycomp_test'
collect2: error: ld returned 1 exit status
ninja: build stopped: subcommand failed.
ninja failed with exit code 1

(full version)

I wonder why this happens. Is there something wrong with my CMakeLists.txt?

ivmarkov commented 1 year ago

This indicates that the linking order of mycomp and rust-temp-mix is reversed in that - because rust-temp-mix does depend on mycomp - in linking order the librust-temp-mix.a should come before libmycomp.a or else the linker will not resolve the mycomp_test symbol rust-temp-mix requires with the one provided by mycomp. Now, I'm not an expert in CMake and not sure what affects the linking order, but I suspect that if you put mycomp here the issue might be fixed.

If that indeed fixes it, please report and close this issue.

Narukara commented 1 year ago

It does work. Thank you so much! :+1:

Maldus512 commented 7 months ago

I'm sorry, I'm facing a similar issue and all the links are dead right now. How should one go about to establish a C dependency from Rust code?

ivmarkov commented 7 months ago

But this link is still alive?: https://github.com/esp-rs/esp-idf-template/issues/82#issuecomment-1458745283

What it tells you is that linking order of your libs does matter. Or to oversimlify it, the library that would call function "x" must come before the library which provides that function - in the link order that is passed to the GCC linker. Not sure if this needs any additional paraphrasing. You can also search on stackoverflow. This problem is well known, and has nothing to do with the source language in which the libs are written actually. Oh, and you can control the link order with cmake.

Maldus512 commented 7 months ago

That link (https://github.com/Narukara/temp-mix/blob/main/components/rust-temp-mix/CMakeLists.txt#L3) returns 404 to me, is it a private repository?

I'm aware of how link order matters; I should have lead by saying that I tried to add the component as a dependency with REQUIRES <component> in the idf_component_register command but it didn't work unless the required component was somehow referenced by the main (C) component as well.

I then tried to add the dependency to the add_prebuilt_library command instead and it appears to work.

ivmarkov commented 7 months ago

That link (https://github.com/Narukara/temp-mix/blob/main/components/rust-temp-mix/CMakeLists.txt#L3) returns 404 to me, is it a private repository?

No idea - not my repo.

I'm aware of how link order matters; I should have lead by saying that I tried to add the component as a dependency with REQUIRES <component> in the idf_component_register command but it didn't work unless the required component was somehow referenced by the main (C) component as well.

Here my knowledge falls short, but maybe you know how to do it: can you look at the GCC link line for both cases (REQUIRES vs add_prebuilt_library)? To see whether REQUIRES is listing the C library before the Rust one or not? And then what add_prebuilt_library does on the linker command line.

Narukara commented 7 months ago

That link (https://github.com/Narukara/temp-mix/blob/main/components/rust-temp-mix/CMakeLists.txt#L3) returns 404 to me, is it a private repository?

I'm sorry. I deleted that repo. I've tried my best to restore it. You can check it now.

The solution is actually very simple, as ivmarkov said. Just add dependencies here.