ruabmbua / hidapi-rs

Rust bindings for the hidapi C library
MIT License
172 stars 81 forks source link

Cross compiling #10

Closed Lindenk closed 6 years ago

Lindenk commented 6 years ago

Currently cross-compiling is not a simple or straight-forward. It requires copying several libraries from the target architecture so gcc won't complain. These are the libraries I've needed to copy so far:

libusb.so
libutil.so
libdl.so
librt.so
libpthread.a
libgcc_s.so.1
libc.a

Also, libudev.so.1 seems to be required for libusb.so however it doesn't seem like adding this to ld's search path solves the issue.

I'd propose a small guide be added or linked for cross-compiling, and secondly, if anyone has a working solution to cross-compiling, I would be ecstatic to know how it was accomplished.

ruabmbua commented 6 years ago

What exactly do you want to achieve? Cross compiling from linux x86 to linux arm, or to a different operating system like windows?

Lindenk commented 6 years ago

Linux x86 to Linux Arm specifically in this case. I would expect to need the libraries of the target system regardless though (of course they would be different depending on the OS).

ruabmbua commented 6 years ago

What cross C / C++ compiler toolchain do you use? Did you get some from your system package manager, or did you build it yourself / with the help of some tool like crosstool-ng?

Lindenk commented 6 years ago

I'm using the x-tools-armv7-bin toolchain in the arch linux user repo (arm-unknown-linux-gnueabihf-gcc).

ruabmbua commented 6 years ago

Okay you can run armv7-gcc -print-sysroot (or however it is actually called), which should give you back the directory, where all the libraries and headers of the toolchain are stored. Normally for cross toolchains this includes the most common C and C++ libraries, so you can get up and running without the need to build some extra libraries.

To get new libraries like libusb working, I would just suggest you compile them yourself and install them into your cross compiler sysroot.

To be able to compile the libraries, you have to build them one by one, beginning with the first, which does not have any dependencies on other missing libraries.

Most C / C++ libraries use autotools as their build system, and you can go through this step for step:

1.) Download and extract source code of e.g. libusb

2.) Obtain the target arch of the cross compiler by running armv7-gcc -v. In the output search for the value of Target.

3.) Obtain the cross compiler sysroot by running armv7-gcc -print-sysroot.

4.) In the source dir of the library you run ./configure CC=armv7-gcc --host=TARGET_ARCH --prefix=SYSROOT. This configures your build.

5.) Run make, or make -j8 (Hint: the -j8 will use all your 8 CPU cores, you may have to adjust that part).

6.) Run make install. This will install the library shared objects, resources and headers into your before configured prefix / sysroot. Your cross compile can now find and access these resources.

Lindenk commented 6 years ago

Thanks, with that I've almost gotten it to work. Cross compiling libudev is a pretty long rabbit hole since it's been merged into systemd. I ended up copied the compiled library from the device into the sysroot for the cross-compiler which let me compile and install libusb which let me cross-compile hidapi. Unfortunately it seems to segfault when running the compiled application. I'll post back after I figure out why or if I can cross-compile systemd.

ruabmbua commented 6 years ago

@Lindenk , the cross compiling story of the crate was improved a little in the current master. (more available backends and a fix to the buildscript).

theronic commented 5 years ago

@Lindenk can you show how you tell Cargo where to look for those native libraries? I'm trying to cross-compile for a MIPS (little Endian) architecture on a MT7688 and seeing these errors, which I presume means I need to tell Rust which libraries to use:

  = note: mipsel-openwrt-linux-musl-gcc.bin: warning: environment variable 'STAGING_DIR' not defined
          mipsel-openwrt-linux-musl-gcc.bin: warning: environment variable 'STAGING_DIR' not defined
          /toolchain/bin/../lib/gcc/mipsel-openwrt-linux-musl/5.3.0/../../../../mipsel-openwrt-linux-musl/bin/ld: skipping incompatible /usr/lib/x86_64-linux-gnu/libusb-1.0.so when searching for -lusb-1.0
          /toolchain/bin/../lib/gcc/mipsel-openwrt-linux-musl/5.3.0/../../../../mipsel-openwrt-linux-musl/bin/ld: skipping incompatible /usr/lib/x86_64-linux-gnu/libusb-1.0.a when searching for -lusb-1.0
          /toolchain/bin/../lib/gcc/mipsel-openwrt-linux-musl/5.3.0/../../../../mipsel-openwrt-linux-musl/bin/ld: cannot find -lusb-1.0
          collect2: error: ld returned 1 exit status
ruabmbua commented 5 years ago

@theronic You are getting an error from your cross mipsel-openwrt-linux-musl-gcc.

Normally a cross compiler should not search system directories e.g. /usr/lib/x86_64-linux-gnu/ for static and dynamic libraries. It should search in the cross compiled library path. This is distribution / toolchain specific.

For example I have

/usr/lib/arm-linux-gnueabihf/libusb-1.0.so

My arm-linux-gnueabihf-gcc is searching in the correct directories..

From your output:

mipsel-openwrt-linux-musl-gcc.bin: warning: environment variable 'STAGING_DIR' not defined

My guess is, that your cross compiler wants a STAGING_DIR, where the cross compiler sysroot is located.

export STAGING_DIR="/your/path/to/the/openwrt/staging/dir"
cargo build

This is just a guess.