rust-embedded/gpio-cdev

Please remove `backtrace` and `libc` dependency

elcritch opened this issue · 5 comments

Great library! It got me up and running on the new chardev gpio devices which was fantastic. I've been experimenting with using Rust on Linux SBCs. However the library isn't suitable for cross compiling currently; would it be possible to remove the extra C library dependencies?

My embedded device build system uses cross compiling for everything and the backtrace dependency (via both the error-chain and clap dependencies) makes cross compiling a pain. To get it to function correctly you have to use an obscure environment variable CARGO_TARGET_$(TRIPLET)_LINKER= to setup the appropriate cross linker.

Effectively the addition of a C library in the Rust toolchain eliminates almost all of the advantages of using Rust. It add unnecessary complications in a cross compiling scenario as now I have 2 more compilers settings to get correct (the Rust one, and the c compiler). Is it possible to remove the backtrace or use a Rust native one?

Based on a look at the inverse dependencies, it looks like the backtrace dependency probably could be removed by replacing error-chain-based logic with a custom error handling (i.e. enum Error + From<> implementations). I'd be open to considering a PR for such a change, curious what @posborne thinks.

➜ cargo tree --invert --no-dev-dependencies --package backtrace
backtrace v0.3.34
└── error-chain v0.12.1
    └── gpio-cdev v0.2.1 (/Users/nick/dev/gpio-cdev)

note that I am omitting dev-dependencies in these graphs because those dependencies are only pulled in for building tests and examples

Removing libc however is basically a non-starter for anything that needs to interact with Linux kernel interfaces. The primary library for raw file I/O and ioctls (a key part of gpio-cdev) is nix, and that will always need to depend on libc.

➜ cargo tree --invert --no-dev-dependencies --package libc     
libc v0.2.62
├── backtrace v0.3.34
│   └── error-chain v0.12.1
│       └── gpio-cdev v0.2.1 (/Users/nick/dev/gpio-cdev)
├── backtrace-sys v0.1.31
│   └── backtrace v0.3.34 (*)
├── gpio-cdev v0.2.1 (/Users/nick/dev/gpio-cdev) (*)
└── nix v0.14.1
    └── gpio-cdev v0.2.1 (/Users/nick/dev/gpio-cdev) (*)

All that said, I think it would be worth addressing the cross-compiling difficulties you're having as well. In order to cross-compile Rust binaries at this point, you are still reliant on an external linker, which for most SBCs is going to be some flavor of GCC. So you're already going to have a C compiler available. Anything that's using the cc crate to manage building C code, which backtrace absolutely does, should pull cross-compiler settings from your environment without issue. So it would be good to look and see if there's something that can be done to ease some of your compiling woes - even if that means maybe exporting a couple environment variables and running cargo from a shell script.

Regarding the error-chain removal, would you be interested in opening a PR to address that?

hey hey, having to have other tools (and libraries) for cross compilation can be a bit of a hassle, but as @nastevens points out, is unfortunately unavoidable.

i've been doing this a bit recently and my current preference is to use a docker image (ryankurte/rust-embedded) with multiarch and the required dependencies for your project (you'll notice libssl-dev:armhf in the package list, another classic c dependency). you might also be interested in cross, but it's rather a lot more complicated imo.

it may depend on your target, but afaik (and ime) you should be able to set linker and other options in .cargo/config rather than using an environmental variable, and once that's set all the cross compilation should work without any manual configuration. as @nastevens said, if you're still finding sharp edges with that set it'd be good to look at what packages and why it's not working ^_^

also heads up that cross builds and cc do not always update. when changing configurations it's good to cargo clean or you can see some strange errors bubble up from the underlying tools, for example when rust is compiling for one target but cmake has cached the configuration for another. this caused me some confusion to start.

and as an aside, from a brief nosy i can't see in linker config in the book (though i thought that's where i originally got it from), so maybe that's an something for us to look at too.

Thanks for the responses! You're right it's not possible to completely remove C dependencies, though minimizing them would (IMHO) be best. Having external build dependencies is fine, but surprising that it's 99% of the way to having a complete self-contained cross build system but fails on a somewhat obscure setting.

I'm using a buildroot derived system and cross compiler build system which works quite well. Most Makefile/CMake/etc C/C++ projects work by using the appropriate environment CC/CXX/LD flags. That makes it easy to pull almost any C/C++ into the system and cross-compile it (in unix/linux at least) with whatever compiler the user wants even for projects completely unaware of cross-compiling.

If Cargo build needs to use an external linker, it would make sense that it'd follow the same standard *Nix environment variables on *Nix platforms or provide it's own. I have the correct LD variable set, so making a Makefile to call cargo with the correct value is trivial, but feels clumsy. Setting a variable in ~/.cargo/config isn't ideal for a generic cross-compiler system which might configure lots of different compilers.

Here's a snippet of the Makefile I used to get the build to finish:

export TRIPLET = $(shell echo $(TARGET_ARCH) | tr a-z A-Z | tr '-' '_')
...
CARGO_TARGET_$(TRIPLET)_LINKER=$(LD) cargo build --target=$(TARGET_ARCH)

I tried running the binary to the device and it just froze, so not sure if it's a missing library, or incorrect library version.

Regarding the error-chain removal, would you be interested in opening a PR to address that?

I'd be up for trying that, but I've got a pretty busy schedule the next few weeks and I'm new to Rust so it'll take me some time. Still it'd be interesting way to learn more error handling basics.

Looking at some other targets, it looks like the backtrace-sys "build-script-build" does look for the CC/CFLAGS but not the LD flag which is why it was compiling for me, but not linking.

Edit: actually I tried just doing a "hello world" without any dependencies. It looks like Cargo is calling "cc", which if replaced with $CC works. It also works if CARGO_TARGET_$(TRIPLET)_LINKER is set as well. Not sure how the cross-compiler is being found but not the linker.

Looks like this is more of an issue with Cargo not detecting the linker automatically. While it'd still be nice to not have C deps it'd be difficult to completely do.

See rust-lang/cargo#4133