Search code examples
rustarmcross-compilingalsa

Cross compiling alsa crate for armv7


I'm trying to cross-compile for amrv7-unknown-linux-gnueabihf a rust binary based on the alsa crate.

For the cross-compilation, I'm using Cross with a custom Dockerfile to have the required dependencies:

FROM ghcr.io/cross-rs/armv7-unknown-linux-gnueabihf:0.2.5

RUN dpkg --add-architecture armhf && \
    apt-get update && \
    apt-get install -y --no-install-recommends \
        libasound2-dev:armhf \
        libudev-dev:armhf \
        pkg-config:armhf

RUN apt-get autoremove -y && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*

COPY .cargo/config.toml /root/.cargo/config.toml

I followed the instruction from this post about cross compiling for arm, by adding the following .cargo/config.toml file:

[build]

[target.arm-unknown-linux-gnueabihf.libasound]
linker = "arm-linux-gnueabihf-gcc"
rustc-link-lib = ["libasound"]
rustc-link-search = ["/usr/lib/arm-linux-gnueabihf"]

But this leads to the following error, with pkg-config complaining about not finding the alsa library:

➜  alsa-cross git:(master) ✗ cross build --target armv7-unknown-linux-gnueabihf --features "alsa-backend" -v
+ cargo metadata --format-version 1 --filter-platform armv7-unknown-linux-gnueabihf --features alsa-backend
+ rustc --print sysroot
+ rustup toolchain list
+ rustup target list --toolchain stable-x86_64-unknown-linux-gnu
+ rustup component list --toolchain stable-x86_64-unknown-linux-gnu
+ /usr/bin/docker
+ "/gitrepos/alsa-cross" /usr/bin/docker build --label 'org.cross-rs.for-cross-target=armv7-unknown-linux-gnueabihf' --label 'org.cross-rs.workspace_root=/gitrepos/alsa-cross' --tag cross-custom-alsa-cross:armv7-unknown-linux-gnueabihf-7235a --build-arg 'CROSS_DEB_ARCH=armhf' --build-arg 'CROSS_BASE_IMAGE=ghcr.io/cross-rs/armv7-unknown-linux-gnueabihf:0.2.5' --file ./Dockerfile /gitrepos/alsa-cross
Sending build context to Docker daemon  30.33MB
Step 1/6 : FROM ghcr.io/cross-rs/armv7-unknown-linux-gnueabihf:0.2.5
 ---> 32cf786140f9
Step 2/6 : RUN dpkg --add-architecture armhf &&     apt-get update &&     apt-get install -y --no-install-recommends         libasound2-dev:armhf         libudev-dev:armhf         pkg-config:armhf
 ---> Using cache
 ---> 8288951e6f23
Step 3/6 : RUN apt-get autoremove -y &&     apt-get clean &&     rm -rf /var/lib/apt/lists/*
 ---> Using cache
 ---> e0ba37616482
Step 4/6 : COPY .cargo/config.toml /root/.cargo/config.toml
 ---> Using cache
 ---> 68d32d3aa8f2
Step 5/6 : LABEL org.cross-rs.for-cross-target=armv7-unknown-linux-gnueabihf
 ---> Using cache
 ---> 42924a9ff180
Step 6/6 : LABEL org.cross-rs.workspace_root=/gitrepos/alsa-cross
 ---> Using cache
 ---> 98094b203092
[Warning] One or more build-args [CROSS_DEB_ARCH CROSS_BASE_IMAGE] were not consumed
Successfully built 98094b203092
Successfully tagged cross-custom-alsa-cross:armv7-unknown-linux-gnueabihf-7235a
+ /usr/bin/docker run --userns host -e 'PKG_CONFIG_ALLOW_CROSS=1' -e 'XARGO_HOME=/xargo' -e 'CARGO_HOME=/cargo' -e 'CARGO_TARGET_DIR=/target' -e 'CROSS_RUNNER=' -e TERM -e 'USER=florian' --rm --user 1000:1000 -v /home/florian/.xargo:/xargo:z -v /home/florian/.cargo:/cargo:z -v /cargo/bin -v /gitrepos/alsa-cross:/project:z -v /home/florian/.rustup/toolchains/stable-x86_64-unknown-linux-gnu:/rust:z,ro -v /gitrepos/alsa-cross/target:/target:z -w /project -i -t cross-custom-alsa-cross:armv7-unknown-linux-gnueabihf-7235a sh -c 'PATH=$PATH:/rust/bin cargo build --target armv7-unknown-linux-gnueabihf --features alsa-backend -v'
       Fresh pkg-config v0.3.27
       Fresh libc v0.2.145
       Fresh bitflags v1.3.2
       Fresh cfg-if v1.0.0
   Compiling alsa-sys v0.3.1
       Fresh nix v0.24.3
     Running `/target/debug/build/alsa-sys-5b7e484eb5de5d94/build-script-build`
error: failed to run custom build command for `alsa-sys v0.3.1`

Caused by:
  process didn't exit successfully: `/target/debug/build/alsa-sys-5b7e484eb5de5d94/build-script-build` (exit status: 101)
  --- stdout
  cargo:rerun-if-env-changed=ALSA_NO_PKG_CONFIG
  cargo:rerun-if-env-changed=PKG_CONFIG_ALLOW_CROSS_armv7-unknown-linux-gnueabihf
  cargo:rerun-if-env-changed=PKG_CONFIG_ALLOW_CROSS_armv7_unknown_linux_gnueabihf
  cargo:rerun-if-env-changed=TARGET_PKG_CONFIG_ALLOW_CROSS
  cargo:rerun-if-env-changed=PKG_CONFIG_ALLOW_CROSS
  cargo:rerun-if-env-changed=PKG_CONFIG_armv7-unknown-linux-gnueabihf
  cargo:rerun-if-env-changed=PKG_CONFIG_armv7_unknown_linux_gnueabihf
  cargo:rerun-if-env-changed=TARGET_PKG_CONFIG
  cargo:rerun-if-env-changed=PKG_CONFIG
  cargo:rerun-if-env-changed=ALSA_STATIC
  cargo:rerun-if-env-changed=ALSA_DYNAMIC
  cargo:rerun-if-env-changed=PKG_CONFIG_ALL_STATIC
  cargo:rerun-if-env-changed=PKG_CONFIG_ALL_DYNAMIC
  cargo:rerun-if-env-changed=PKG_CONFIG_PATH_armv7-unknown-linux-gnueabihf
  cargo:rerun-if-env-changed=PKG_CONFIG_PATH_armv7_unknown_linux_gnueabihf
  cargo:rerun-if-env-changed=TARGET_PKG_CONFIG_PATH
  cargo:rerun-if-env-changed=PKG_CONFIG_PATH
  cargo:rerun-if-env-changed=PKG_CONFIG_LIBDIR_armv7-unknown-linux-gnueabihf
  cargo:rerun-if-env-changed=PKG_CONFIG_LIBDIR_armv7_unknown_linux_gnueabihf
  cargo:rerun-if-env-changed=TARGET_PKG_CONFIG_LIBDIR
  cargo:rerun-if-env-changed=PKG_CONFIG_LIBDIR
  cargo:rerun-if-env-changed=PKG_CONFIG_SYSROOT_DIR_armv7-unknown-linux-gnueabihf
  cargo:rerun-if-env-changed=PKG_CONFIG_SYSROOT_DIR_armv7_unknown_linux_gnueabihf
  cargo:rerun-if-env-changed=TARGET_PKG_CONFIG_SYSROOT_DIR
  cargo:rerun-if-env-changed=PKG_CONFIG_SYSROOT_DIR

  --- stderr
  thread 'main' panicked at '`PKG_CONFIG_ALLOW_SYSTEM_CFLAGS="1" PKG_CONFIG_ALLOW_SYSTEM_LIBS="1" PKG_CONFIG_PATH="/usr/lib/arm-linux-gnueabihf/pkgconfig/:" "pkg-config" "--libs" "--cflags" "alsa"` did not exit successfully: exit status: 2
  error: could not find system library 'alsa' required by the 'alsa-sys' crate

  --- stderr
  /usr/bin/pkg-config: 1: /usr/bin/pkg-config: Syntax error: word unexpected (expecting ")")
  ', /cargo/registry/src/index.crates.io-6f17d22bba15001f/alsa-sys-0.3.1/build.rs:13:18
  note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
+ rustup component list --toolchain stable-x86_64-unknown-linux-gnu

Do you have any lead about how to fix this error ?

I have tried the following:

  1. Adding the feature flag "alsa-backend" as described here
  2. Custom .cargo/config.toml as described in the same post
  3. Look at all the stackoverflow posts related to cross compiling alsa to armv7, but I didn't find any useful responses, when the post had responses at all.

Solution

  • I'm sure there is a way with cross, but I personally didn't manage to achieve it.

    I did, however, achieve this by using the cross-building functionality of cargo directly.

    Create the following Dockerfile:

    ARG DEBIAN_VERSION="11.7"
    
    FROM debian:${DEBIAN_VERSION}
    
    # Install target compilation targets
    RUN dpkg --add-architecture armhf
    
    # Add cross compilers and dependencies
    RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install --yes \
        curl git crossbuild-essential-armhf pkg-config \
        libasound2-dev:armhf \
        && apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
    
    # Install Rust system-wide
    ENV RUSTUP_HOME=/opt/rust
    ENV CARGO_HOME=/opt/rust
    ENV CARGO_REGISTRIES_CRATES_IO_PROTOCOL=sparse
    RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --no-modify-path
    ENV PATH="/opt/rust/bin:${PATH}"
    
    # Add cross compilation target and set as default
    RUN rustup target add armv7-unknown-linux-gnueabihf
    ENV CARGO_BUILD_TARGET=armv7-unknown-linux-gnueabihf
    
    # Configure Rust linkers for cross compilation
    ENV CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_LINKER=/usr/bin/arm-linux-gnueabihf-gcc
    
    # Configure pkg-config for cross compilation
    ENV PKG_CONFIG_ALLOW_CROSS=1/
    ENV PKG_CONFIG_PATH_armv7_unknown_linux_gnueabihf=/usr/lib/arm-linux-gnueabihf/pkgconfig/
    
    # Set the working directory to /src, where we will mount our project
    WORKDIR /src
    

    Build the docker container (I named it armv7_cross here):

    docker build -t armv7_cross .
    

    Then, inside of your project directory, you can do:

    docker run -v $PWD:/src --user $(id -u):$(id -g) --rm -ti armv7_cross cargo build
    

    This should build like normally, and you should get our output at target/armv7-unknown-linux-gnueabihf.

    Explanation of the docker run flags:

    • -v $PWD:/src - Mounts the current directory to /src in your docker container

    • --user $(id -u):$(id -g) - Configures user and group id, otherwise all your build outputs would be owned by root

    • --rm - Destroys the docker container again after building

    • -ti - Interactive terminal mode, to get some pretty colors

    • armv7_cross - The name of the docker image

    • cargo build - The command that gets executed inside of the container.

      Note we already set armv7-unknown-linux-gnueabihf as the default target inside our docker container, so we don't need to supply a --target flag.