[WIP] Support building against c libraries with libc or newlib / nosys
Nobody has claimed this yet.
Assessment
- Difficulty
- 5/5
- Estimated time
- Over a week
- Newbie friendliness
- 25/100
- Issue type
- Documentation
- Clarity
- Needs clarification
- Activity status
- Stale
- Domain
- documentation, embedded-iot
Research direction
Review the rust-and-c section, the Nomicon placement question, and the linked compiler-builtins and sodiumoxide issues before deciding where this guidance belongs. Validate the compiler-builtins, libc, libnosys, linker, ABI, and stub examples on the stated ARM target. Done means a focused, reproducible explanation with unresolved TODOs removed.
Written by the indexing model from the issue text.
Description
Not sure if this is a candidate for the rust-and-c section or if it's too cursed and should go in the `nomicon. Fair warning this is also a bit ranty and all over the show (sorry), and I haven't succeeded at this yet so, any guidance / advice / improvement is greatly appreciated, just want it posted somewhere on the internet so noone else has to got at it alone.
When linking against existing c libraries you may need symbols from 'libc' and/or libnosys. Unfortunately for us, rust's libc elects not to provide any bindings for non-standard targets. cty can be used in place of libc for primitive type definitions, but if you need the classic posix libc functions you're right outa luck.
You'll know if this is required because linking will fail with a bunch of undefined symbols for libc components like:
... sysrandom/randombytes_sysrandom.c:135: undefined reference to `read'
... undefined reference to `__errno'
or for newlib components like:
/usr/lib/gcc/arm-none-eabi/7.3.1/../../../arm-none-eabi/bin/ld: /usr/lib/arm-none-eabi/lib/thumb/v7e-m/fpv4-sp/hard//libc_nano.a(lib_a-signalr.o): in function `_getpid_r':
/tmp/building/package/build_nano/arm-none-eabi/thumb/v7e-m/fpv4-sp/hard/newlib/libc/reent/../../../../../../../../../newlib/libc/reent/signalr.c:83: undefined reference to `_getpid'
/usr/lib/gcc/arm-none-eabi/7.3.1/../../../arm-none-eabi/bin/ld: /usr/lib/arm-none-eabi/lib/thumb/v7e-m/fpv4-sp/hard//libc_nano.a(lib_a-writer.o): in function `_write_r':
/tmp/building/package/build_nano/arm-none-eabi/thumb/v7e-m/fpv4-sp/hard/newlib/libc/reent/../../../../../../../../../newlib/libc/reent/writer.c:49: undefined reference to `_write'
The compiler builtins way
Using Rust-lang/compiler-builtins, which should work for most cases, unless the library you're building requires --specs=nosys.spec, in which case it might not or I might be missing something.
First add the dependency:
[dependencies.compiler_builtins]
git = "https://github.com/rust-lang/compiler-builtins"
features = ["c"]
Make sure it's used:
extern crate compiler_builtins;
Get yourself a copy of compiler-rt:
TODO: work out how to do this?? (see: https://github.com/rust-lang/compiler-builtins/issues/363)
Profit?
The libc way
To deal with this this the libc way, you need to add libc via either:
Adding a link attribute to your main.rs for libc and (optionally) `libnosys:
#[link(name = "c", kind = "static")]
extern {}
Or, adding a linker argument to your .cargo/config for the required target.
"-C", "linker=arm-none-eabi-gcc",
...
"-C", "link-arg=-lc
Unfortunately cargo does not seem to pass enough information for the linker to determine which ABI you are using and provide the correct library path, which results in a lot of linker errors along the lines of Failed to merge target specific data of file X, error: X uses VFP register arguments but Y does not, unsure if this is an oversight or intended, but it results in:
/usr/lib/gcc/arm-none-eabi/7.3.1/../../../arm-none-eabi/bin/ld: failed to merge target specific data of file /usr/lib/gcc/arm-none-eabi/7.3.1/../../../arm-none-eabi/lib/libnosys.a(wait.o)
/usr/lib/gcc/arm-none-eabi/7.3.1/../../../arm-none-eabi/bin/ld: error: /home/ryan/projects/dsf-stm-sensor/target/thumbv7em-none-eabihf/debug/deps/stm32_experiment-8893eaa8a12d65c8 uses VFP register arguments, /usr/lib/gcc/arm-none-eabi/7.3.1/../../../arm-none-eabi/lib/libnosys.a(write.o) does not
/usr/lib/gcc/arm-none-eabi/7.3.1/../../../arm-none-eabi/bin/ld: failed to merge target specific data of file /usr/lib/gcc/arm-none-eabi/7.3.1/../../../arm-none-eabi/lib/libnosys.a(write.o)
/usr/lib/gcc/arm-none-eabi/7.3.1/../../../arm-none-eabi/bin/ld: error: /home/ryan/projects/dsf-stm-sensor/target/thumbv7em-none-eabihf/debug/deps/stm32_experiment-8893eaa8a12d65c8 uses VFP register arguments, /usr/lib/gcc/arm-none-eabi/7.3.1/../../../arm-none-eabi/lib/libnosys.a(_exit.o) does not
To mitigate this, add yet another linker argument (with the correct architecture and floating point kind) so the linker can find the correct library version...
"-C", "link-arg=-L/usr/lib/arm-none-eabi/lib/thumb/v7e-m/fpv4-sp/hard/",
Once you've got libc linking you have a couple of options for resolving the required stubs.
Defining the stubs in rust
If you don't care about the libc calls, or are willing to implement the libc stubs as required, you can define these in your rust app.
#[no_mangle]
pub extern "C" fn _sbrk() {}
#[no_mangle]
pub extern "C" fn _write() {}
#[no_mangle]
pub extern "C" fn _close() {}
#[no_mangle]
pub extern "C" fn _lseek() {}
#[no_mangle]
pub extern "C" fn _read() {}
#[no_mangle]
pub extern "C" fn _fstat() {}
#[no_mangle]
pub extern "C" fn _isatty() {}
#[no_mangle]
pub extern "C" fn _exit() {}
#[no_mangle]
pub extern "C" fn _open() {}
#[no_mangle]
pub extern "C" fn _kill() {}
#[no_mangle]
pub extern "C" fn _getpid() {}
TODO: wouldn't it be great if we had a libnosys package that defined these in a rust-compatible manner?
Using libnosys
If you don't want to implement the stubs yourself, you can link libnosys using either of the earlier methods. Note that this will result in two parallel methods for doing things like, allocation, and you'll need to work out how to setup an end symbol to help with memory allocation/deallocation to resolve the following:
/usr/lib/gcc/arm-none-eabi/7.3.1/../../../arm-none-eabi/bin/ld: /usr/lib/arm-none-eabi/lib/thumb/v7e-m/fpv4-sp/hard//libnosys.a(sbrk.o): in function `_sbrk':
/tmp/building/package/build/arm-none-eabi/thumb/v7e-m/fpv4-sp/hard/libgloss/libnosys/../../../../../../../../libgloss/libnosys/sbrk.c:21: undefined reference to `end'
TODO: work out how to add this without it being, terrible. May be able to use daniel5151/libc_alloc on the rust side to avoid terrible conflicting allocator situations? idk.
Related issues / posts / eulogies:
- Building sodiumoxide on
no_stdwhich was the cause of this (mis)adventure sodiumoxide#363 - https://stackoverflow.com/questions/31494087/linking-rust-with-c-undefined-reference-to-aeabi-functions
- monotron-app which implements newlib stubs here
- Dominant language
- No language data
- Stars
- 1.3k
- Forks
- 223
- PR merge metrics
- No merged PRs in 30d
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from rust-embedded/book
-
Difficulty 1/5 Under an hour Newbie friendliness 75/100
rust-embedded/book#414 ·
-
Difficulty 1/5 Under an hour Newbie friendliness 62/100
rust-embedded/book#370 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
rust-embedded/book#345 · 2 reactions ·
-
Difficulty 1/5 Under an hour Newbie friendliness 68/100
rust-embedded/book#208 ·
-
Difficulty 1/5 1-3 hours Newbie friendliness 65/100
rust-embedded/book#147 ·
All issues in rust-embedded/book
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
bancolombia/sentinel#22 ·
-
test md OpenCI
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
-
optimization optimization:agents-md-curator
Difficulty 2/5 1-3 hours Newbie friendliness 86/100
githubnext/gh-aw-cao#13143 ·
-
Difficulty 1/5 Under an hour Newbie friendliness 94/100
objectionary/hone-maven-plugin#1061 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 85/100
redhat-developer/rhdh-plugins#4887 · 2 comments ·