RIOT-OS / RIOT

RIOT - The friendly OS for IoT
https://riot-os.org
GNU Lesser General Public License v2.1
4.94k stars 1.99k forks source link

C2Rust failes on native on Arch #20451

Open chrysn opened 8 months ago

chrysn commented 8 months ago

(Issue moved over from forum, see https://forum.riot-os.org/t/compiling-rust-example-programs-for-native-rust2c-error/4127 for original entry by @SzymonKubica)

Description

Hello,

I’m working on a project which ports over a rust-based eBPF VM to run on RIOT. So far I’ve been testing it out on the nucleo-f439zi stm32 board and everything was working fine. I have installed c2rust as suggested from the github repo (not directly from cargo).

The problem is that when I try to compile my project for native, c2rust fails with the following error:

Running C2Rust on /home/szymon/Projects/ebpf-on-microcontrollers/mibpf/RIOT/examples/rust-hello-world/bin/native/target/i686-unknown-linux-gnu/release/build/riot-sys-2c2c5674e877dcb9/out/compile_commands.json
  Transpiling riot-c2rust.h
  cargo:warning=C2Rust failed with error code exit status: 101, exiting

  --- stderr
  In file included from riot-c2rust.h:79:
  In file included from /home/szymon/Projects/ebpf-on-microcontrollers/mibpf/RIOT/core/lib/include/rmutex.h:28:
  /home/szymon/Projects/ebpf-on-microcontrollers/mibpf/RIOT/core/include/mutex.h:130:10: fatal error: 'stddef.h' file not found
  #include <stddef.h>
           ^~~~~~~~~~
  1 error generated.
  Error while processing /home/szymon/Projects/ebpf-on-microcontrollers/mibpf/RIOT/examples/rust-hello-world/bin/native/target/i686-unknown-linux-gnu/release/build/riot-sys-2c2c5674e877dcb9/out/riot-c2rust.h.
  warning: Missing child 108724094825960 of node AstNode { tag: TagCallExpr, children: [Some(108724094825960)], loc: SrcSpan { fileid: 110, begin_line: 384, begin_column: 11, end_line: 384, end_column: 33 }, type_id: Some(108724091303168), rvalue: RValue, macro_expansions: [], macro_expansion_text: None, extras: [] }
  Exported Clang AST was invalid. Check warnings above for unimplemented features.
  --> /home/szymon/Projects/ebpf-on-microcontrollers/mibpf/RIOT/sys/include/net/gnrc/netif/internal.h:384:11
   [-Wclang-ast]
  warning: Missing child 108724094826208 of node AstNode { tag: TagCallExpr, children: [Some(108724094826208), Some(108724094826240)], loc: SrcSpan { fileid: 110, begin_line: 387, begin_column: 16, end_line: 387, end_column: 43 }, type_id: Some(108724091303168), rvalue: RValue, macro_expansions: [], macro_expansion_text: None, extras: [] }
  Exported Clang AST was invalid. Check warnings above for unimplemented features.

The same issue is present when I try to compile any of the rust example programs. I suspect it has something to do with my OS as I’m using arch linux and when installing c2rust I needed to explicitly specify the llvm installation dir.

Has anyone seen a similar issue before? Thank you

chrysn commented 8 months ago

Haven't seen this yet; AFAIK @maribu is the RIOT developer who has the most experience with distros that use musl libc.

It may also be that this is an issue with the include paths and how they are adjusted between GCC and LLVM.

Please try both these:

SzymonKubica commented 8 months ago

I have already tried setting TOOLCHAIN=llvm, however this hasn't changed anything. To give you some additional context, in order to get c2rust to even compile during installing, I had to explicitly set

LLVM_TOOLCHAIN_DIR=/usr/lib

And then compile c2rust using the version from the git repo. It seems like the multilib setup on arch isn't ideal, or there is some problem with my configuration. I don't have access to my main machine right now, once I have it, I will test the build in docker option

As for my setup, I'm pretty sure I have all versions of clang and llvm from 14 to 17 installed. Not sure why the compilation process isn't able to find any of them.

maribu commented 8 months ago

AFAIK @maribu is the RIOT developer who has the most experience with distros that use musl libc.

Likely true, but Arch is using glibc.

Sounds more like the bug you fixed some time ago with the order of items in compile_commands.json being assumed to be in a particular order.

SzymonKubica commented 8 months ago

Speaking of compile_commands.json, it could have something to do with this. I had some issues with riot-wrappers and riot-sys after syncing to the latest version of RIOT master. It kept complaining that I need to set RIOT_USEMODULE, even though the build.rs of the latest riot sys should not fail at that point. In order to fix that issue, I had to add the RIOT_USEMODULE line back to this file: https://github.com/RIOT-OS/RIOT/commit/9a59d59bd26b0376aa69a1a0c2dc2760aaa460e4

SzymonKubica commented 8 months ago

I will look into the above once I'm back and figure out if it is causing the issue. Although I did clone a fresh RIOT repo as well and just compiled the rust-hello-word example there and it failed with the same exception.

SzymonKubica commented 8 months ago

Ok so I have tried running with BUILD_IN_DOCKER=1 however there seems to be an issue with the latest version of riot-wrappers requiring a newer version of rustc (1.75) than the one present in the docker image. Do you know how to deal with this issue?

chrysn commented 8 months ago

docker pull riotdocker

should fix that detail easily.

SzymonKubica commented 8 months ago

Thank you for suggesting this, I did that, however it didn't seem to affect the actual image used for docker build:

Launching build container using image "docker.io/riot/riotbuild:latest".

I have pulled this image as 'riotdocker' wasn't found: docker pull kaspar030/riotdocker. Is this the right one? I assume I would have to override it in the config somewhere. I looked through the RIOT build in docker docs, however there doesn't seem to be an easy way to change the image.

I will also try this one docker pull riot/riotdocker-base Or I think this is the one that's executing the build: docker pull riot/riotbuild

SzymonKubica commented 8 months ago

Ok, pulling the last image did the trick. Now I was able to compile the rust-hello-word example and it did execute correctly. Thanks a lot for your help.

I tried using the same setup for my main project, but got the issue where the rust doesn't have the proper toolchain installed:

 i686-unknown-linux-gnu

It is interesting that this one is targeted as I have that one installed locally. I assume it isn't present in docker. I will investigate that.

Edit: Ok so it turns out that I had a toolchain override present in the directory which was messing things up. Now it seems like the toolchain is set up correctly. The problem I'm having now is that one of the packages that my project depends on lives outside of the RIOT tree and the build in docker has some trouble copying it over:

make[1]: Nothing to be done for 'prepare'.
rm -Rf /data/riotbuild/riotbase/build/pkg/femto-container
mkdir -p $(dirname /data/riotbuild/riotbase/build/pkg/femto-container)
cp -a /data/riotbuild/riotbase/../femto-containers /data/riotbuild/riotbase/build/pkg/femto-container
cp: cannot stat '/data/riotbuild/riotbase/../femto-containers': No such file or directory

Does build in docker support out-of-tree packages?

maribu commented 8 months ago

BUILD_IN_DOCKER=1 uses docker.io/riot/riotbuild to build. So you should go for

docker pull docker.io/riot/riotbuild

to update.

You can use a different container via DOCKER_IMAGE=<img_name> (if I recall the name correctly), but I think @chrysn was not suggesting to do that but just recalled the docker image name incorrectly.

chrysn commented 8 months ago

Sorry, still didn't have time to look into this in full, just dumping anything I have on short notes:

think chrysn was not suggesting to do that but just recalled the docker image name incorrectly.

Indeed; I just sent the remark from mobile without looking up the details.

It kept complaining that I need to set RIOT_USEMODULE, even though the build.rs of the latest riot sys should not fail at that point.

That should be fixed already because the latest riot-sys has been uploaded to crates.io. RIOT uses riot-sys/-wrappers with a patch.crates-io to go directly to git. Tracked in https://github.com/RIOT-OS/RIOT/issues/20452 for not letting this happen again.

SzymonKubica commented 8 months ago

Thank you @chrysn for opening the other issue, I will look into this and provide additional context where applicable. As for the current state of my build-in-docker. I did manage to pull the correct image and get the rust-hello-world and rust-gcoap examples to compile. Thanks a lot for helping me fix this issue. My project still doesn't work, but I think the issue lies somewhere deeper (either in the rust toolchain for i686 or c2rust) you can see the issue below but it's probably unrelated to the original problem:

/usr/bin/ld: /data/riotbuild/riotproject/mibpf-server/bin/native/mibpf_server/mibpf_server-fcf3a3ec338093ea.mibpf_server.9ede0b52c9482aa-cgu.0.rcgu.o:(.data.DW.ref.rust_eh_personality[DW.ref.rust_eh_personality]+0x0): undefined reference to `rust_eh_personality'
collect2: error: ld returned 1 exit status

I just attached it here in case you have seen it before. Does this look familiar?

I did some digging and found that this missing eh_personality problem shouldn't be there if Cargo.toml specifies in profile.release panic="abort"

A possible workaround that I found online was to define this function manually like so:

    #[lang = "eh_personality"]
    extern "C" fn eh_personality() {}

The problem is that it requires nightly rust to allow for using language features. Do you know how I can override the toolchain used by the build-in-docker process? I tried using a custom toolchain.toml file, however it then complains that it doesn't have the target installed:

rustup target add i686-unknown-linux-gnu

Is there a way of adding new targets to the rust toolchain that is present in the docker image?

Edit: In case anyone encounters a similar error, I have followed this issue thread: https://github.com/rust-lang/rust/issues/106864 and managed to fix my problem by adding a dummy implementation of the missing function:

#[no_mangle]
extern "C" fn rust_eh_personality() {}

The thing is that I'm not sure why this errors as after some reading I found that if you use panic="abort" then the rust_eh_personality should never be called.

SzymonKubica commented 8 months ago

From the RIOT side, my setup works now. Thank you @chrysn and @maribu for helping me out. Excellent support right here, thank you for all of your contributions to RIOT.

For anyone reading this issue in the future:

Problem

RIOT examples of rust programs (rust-hello-world, rust-gcoap) fail to build because of link-time error in c2rust on Arch Linux.

Solution

Use the BUILD_IN_DOCKER=1 TOOLCHAIN=llvm environment variables when compiling the program If compilation fails because of an incompatible version of rustc, pull the latest docker image required for the build process: docker pull riot/riotbuild. If after that you get some weird issues with eh_personality, read this issue https://github.com/rust-lang/rust/issues/106864 and try solutions suggested there. The thing that worked for me was adding a dummy implementation of that missing function to my main lib.rs file:

#[no_mangle]
extern "C" fn rust_eh_personality() {}
WataNekko commented 6 months ago

Hello, I would also like to report that I'm having the same problem with C2Rust failing when trying to build the rust examples on my Arch Linux (just that I don't use LLVM like OP). Worked around with BUILD_IN_DOCKER=1 but the underlying issue on Arch still remains. :pray:

mcr commented 3 months ago

The underlying problem is that the LLVM needs some gcc headers. GCC knows to look in the compiler-specific directories, but LLVM does not. https://github.com/rust-lang/rust-bindgen/issues/2612 is another example of this problem. https://clangd.llvm.org/guides/system-headers talks more about this, but despite the test at the end working, my bindgen run does not work yet.

mcr commented 3 months ago

make BOARD=native64 all seems to work better, but fails at

/bin/ld: /corp/projects/pandora/riotos/RIOT/examples/rust-gcoap/bin/native64/periph/timer.o: in function `timer_start':
/corp/projects/pandora/riotos/RIOT/cpu/native/periph/timer.c:205: undefined reference to `timer_settime'
/bin/ld: /corp/projects/pandora/riotos/RIOT/examples/rust-gcoap/bin/native64/periph/timer.o: in function `timer_init':
/corp/projects/pandora/riotos/RIOT/cpu/native/periph/timer.c:117: undefined reference to `timer_create'
/bin/ld: /corp/projects/pandora/riotos/RIOT/cpu/native/periph/timer.c:124: undefined reference to `timer_delete'
collect2: error: ld returned 1 exit status

I am on an Ubuntu 20.04 LTS platform. (wont move to 22 due to gnome3 garbage)

mcr commented 3 months ago
sudo apt install gcc-multilib

got me to the same place as native64 did (ztimer errors) things for me on Ubuntu20, once I realized that I was building in 32-bit mode.

maribu commented 3 months ago

make BOARD=native64 all seems to work better, but fails at

/bin/ld: /corp/projects/pandora/riotos/RIOT/examples/rust-gcoap/bin/native64/periph/timer.o: in function `timer_start':
/corp/projects/pandora/riotos/RIOT/cpu/native/periph/timer.c:205: undefined reference to `timer_settime'
/bin/ld: /corp/projects/pandora/riotos/RIOT/examples/rust-gcoap/bin/native64/periph/timer.o: in function `timer_init':
/corp/projects/pandora/riotos/RIOT/cpu/native/periph/timer.c:117: undefined reference to `timer_create'
/bin/ld: /corp/projects/pandora/riotos/RIOT/cpu/native/periph/timer.c:124: undefined reference to `timer_delete'
collect2: error: ld returned 1 exit status

I am on an Ubuntu 20.04 LTS platform. (wont move to 22 due to gnome3 garbage)

That looks like an FEATURES_REQUIRES += periph_timer is missing in the Makefile.

Maybe we should consider a maintainable option to better error messages on modules/features not selected but used.