Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Building sys crates with internal cc builder and bindgen #321

Open
Nyrmburk opened this issue Jul 5, 2024 · 2 comments
Open

Building sys crates with internal cc builder and bindgen #321

Nyrmburk opened this issue Jul 5, 2024 · 2 comments

Comments

@Nyrmburk
Copy link

Nyrmburk commented Jul 5, 2024

  1. Do setup from docs.
  2. Generate esp-idf template.
  3. Compile successfully.
  4. Add a crate with generated Rust bindings for a wrapped C library such as ring or littlefs2.
  5. Observe a build failure (fish and bash have the same result).

Is there a mechanism to forward the environment that is compiling the esp-idf to these other sys dependencies?

Template generate config:

cargo generate esp-rs/esp-idf-template cargo
⚠️   Favorite `esp-rs/esp-idf-template` not found in config, using it as a git repository: https://github.com/esp-rs/esp-idf-template.git
🤷   Project Name: buildnative-espidf
🔧   Destination: /home/nyrmburk/documents/dev/buildnative-espidf ...
🔧   project-name: buildnative-espidf ...
🔧   Generating template ...
✔ 🤷   Which MCU to target? · esp32c3
✔ 🤷   Configure advanced template options? · true
✔ 🤷   Enable STD support? · true
✔ 🤷   ESP-IDF version (master = UNSTABLE) · v5.2
✔ 🤷   Configure project to use Dev Containers (VS Code and GitHub Codespaces)? · false
✔ 🤷   Configure project to support Wokwi simulation with Wokwi VS Code extension? · false
✔ 🤷   Add CI files for GitHub Action? · false
🔧   Moving generated files into: `/home/nyrmburk/documents/dev/buildnative-espidf`...
🔧   Initializing a fresh Git repository
✨   Done! New project created /home/nyrmburk/documents/dev/buildnative-espid

Build failure with littlefs2:
Crate: https://docs.rs/littlefs2/latest/littlefs2/
Repo: https://github.com/trussed-dev/littlefs2

This crate generates bindings and builds the C littlefs library with the littlefs2-sys crate:
Crate: https://docs.rs/littlefs2-sys/latest/littlefs2_sys/
Repo: https://github.com/trussed-dev/littlefs2-sys

The build.rs file is very simple:
https://github.com/trussed-dev/littlefs2-sys/blob/main/build.rs

use std::env;
use std::path::PathBuf;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut builder = cc::Build::new();
    let target = env::var("TARGET")?;
    let builder = builder
        .flag("-std=c11")
        .flag("-DLFS_NO_DEBUG")
        .flag("-DLFS_NO_WARN")
        .flag("-DLFS_NO_ERROR")
        .file("littlefs/lfs.c")
        .file("littlefs/lfs_util.c")
        .file("string.c");

    #[cfg(feature = "software-intrinsics")]
    let builder = builder.flag("-DLFS_NO_INTRINSICS");

    #[cfg(not(feature = "assertions"))]
    let builder = builder.flag("-DLFS_NO_ASSERT");

    #[cfg(feature = "trace")]
    let builder = builder.flag("-DLFS_YES_TRACE");

    #[cfg(not(feature = "malloc"))]
    builder.flag("-DLFS_NO_MALLOC");

    builder.compile("lfs-sys");

    let bindings = bindgen::Builder::default()
        .header("littlefs/lfs.h")
        .clang_arg(format!("--target={}", target))
        .use_core()
        .allowlist_item("lfs_.*")
        .allowlist_item("LFS_.*")
        .generate()
        .expect("Unable to generate bindings");

    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
    bindings
        .write_to_file(out_path.join("bindings.rs"))
        .expect("Couldn't write bindings!");

    Ok(())
}

cargo build results:

$ cargo add littlefs2
...
$ cargo build
...
The following warnings were emitted during compilation:

warning: [email protected]: Compiler family detection failed due to error: ToolNotFound: Failed to find tool. Is `riscv32-esp-elf-gcc` installed?

error: failed to run custom build command for `littlefs2-sys v0.1.7`

Caused by:
 process didn't exit successfully: `/home/nyrmburk/documents/dev/buildnative-espidf/target/debug/build/littlefs2-sys-78b36b8617a86ec1/build-script-build` (exit status: 1)
 --- stdout
 OUT_DIR = Some(/home/nyrmburk/documents/dev/buildnative-espidf/target/riscv32imc-esp-espidf/debug/build/littlefs2-sys-0283119dc2df45e7/out)
 TARGET = Some(riscv32imc-esp-espidf)
 OPT_LEVEL = Some(z)
 HOST = Some(x86_64-unknown-linux-gnu)
 cargo:rerun-if-env-changed=CC_riscv32imc-esp-espidf
 CC_riscv32imc-esp-espidf = None
 cargo:rerun-if-env-changed=CC_riscv32imc_esp_espidf
 CC_riscv32imc_esp_espidf = None
 cargo:rerun-if-env-changed=TARGET_CC
 TARGET_CC = None
 cargo:rerun-if-env-changed=CC
 CC = None
 cargo:rerun-if-env-changed=CROSS_COMPILE
 CROSS_COMPILE = None
 RUSTC_LINKER = Some(ldproxy)
 cargo:rerun-if-env-changed=CC_ENABLE_DEBUG_OUTPUT
 cargo:warning=Compiler family detection failed due to error: ToolNotFound: Failed to find tool. Is `riscv32-esp-elf-gcc` installed?
 RUSTC_WRAPPER = None
 cargo:rerun-if-env-changed=CRATE_CC_NO_DEFAULTS
 CRATE_CC_NO_DEFAULTS = Some(1)
 cargo:rerun-if-env-changed=CFLAGS_riscv32imc-esp-espidf
 CFLAGS_riscv32imc-esp-espidf = None
 cargo:rerun-if-env-changed=CFLAGS_riscv32imc_esp_espidf
 CFLAGS_riscv32imc_esp_espidf = None
 cargo:rerun-if-env-changed=TARGET_CFLAGS
 TARGET_CFLAGS = None
 cargo:rerun-if-env-changed=CFLAGS
 CFLAGS = None

 --- stderr


 error occurred: Failed to find tool. Is `riscv32-esp-elf-gcc` installed?


warning: build failed, waiting for other jobs to finish...

Adding the compiler bins to my path manually (fish shell):

$ export PATH="$(pwd)/.embuild/espressif/tools/riscv32-esp-elf/esp-13.2.0_20230928/riscv32-esp-elf/bin:$PATH"
$ cargo build
...
error: failed to run custom build command for `littlefs2-sys v0.1.7`

Caused by:
 process didn't exit successfully: `/home/nyrmburk/documents/dev/buildnative-espidf/target/debug/build/littlefs2-sys-78b36b8617a86ec1/build-script-build` (exit status: 101)
 --- stdout
 OUT_DIR = Some(/home/nyrmburk/documents/dev/buildnative-espidf/target/riscv32imc-esp-espidf/debug/build/littlefs2-sys-0283119dc2df45e7/out)
 TARGET = Some(riscv32imc-esp-espidf)
 OPT_LEVEL = Some(z)
 HOST = Some(x86_64-unknown-linux-gnu)
 cargo:rerun-if-env-changed=CC_riscv32imc-esp-espidf
 CC_riscv32imc-esp-espidf = None
 cargo:rerun-if-env-changed=CC_riscv32imc_esp_espidf
 CC_riscv32imc_esp_espidf = None
 cargo:rerun-if-env-changed=TARGET_CC
 TARGET_CC = None
 cargo:rerun-if-env-changed=CC
 CC = None
 cargo:rerun-if-env-changed=CROSS_COMPILE
 CROSS_COMPILE = None
 RUSTC_LINKER = Some(ldproxy)
 cargo:rerun-if-env-changed=CC_ENABLE_DEBUG_OUTPUT
 RUSTC_WRAPPER = None
 cargo:rerun-if-env-changed=CRATE_CC_NO_DEFAULTS
 CRATE_CC_NO_DEFAULTS = Some(1)
 cargo:rerun-if-env-changed=CFLAGS_riscv32imc-esp-espidf
 CFLAGS_riscv32imc-esp-espidf = None
 cargo:rerun-if-env-changed=CFLAGS_riscv32imc_esp_espidf
 CFLAGS_riscv32imc_esp_espidf = None
 cargo:rerun-if-env-changed=TARGET_CFLAGS
 TARGET_CFLAGS = None
 cargo:rerun-if-env-changed=CFLAGS
 CFLAGS = None
 cargo:rerun-if-env-changed=AR_riscv32imc-esp-espidf
 AR_riscv32imc-esp-espidf = None
 cargo:rerun-if-env-changed=AR_riscv32imc_esp_espidf
 AR_riscv32imc_esp_espidf = None
 cargo:rerun-if-env-changed=TARGET_AR
 TARGET_AR = None
 cargo:rerun-if-env-changed=AR
 AR = None
 cargo:rerun-if-env-changed=ARFLAGS_riscv32imc-esp-espidf
 ARFLAGS_riscv32imc-esp-espidf = None
 cargo:rerun-if-env-changed=ARFLAGS_riscv32imc_esp_espidf
 ARFLAGS_riscv32imc_esp_espidf = None
 cargo:rerun-if-env-changed=TARGET_ARFLAGS
 TARGET_ARFLAGS = None
 cargo:rerun-if-env-changed=ARFLAGS
 ARFLAGS = None
 cargo:rustc-link-lib=static=lfs-sys
 cargo:rustc-link-search=native=/home/nyrmburk/documents/dev/buildnative-espidf/target/riscv32imc-esp-espidf/debug/build/littlefs2-sys-0283119dc2df45e7/out

 --- stderr
 error: unknown target triple 'riscv32imc-esp-espidf'
 thread 'main' panicked at /home/nyrmburk/.cargo/registry/src/index.crates.io-6f17d22bba15001f/bindgen-0.56.0/src/ir/context.rs:531:15:
 libclang error; possible causes include:
 - Invalid flag syntax
 - Unrecognized flags
 - Invalid flag arguments
 - File I/O errors
 - Host vs. target architecture mismatch
 If you encounter an error missing from this list, please file an issue or a PR!
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
warning: build failed, waiting for other jobs to finish...

From some other bugs I read here, it seems like bindgen might be trying to use some host resources instead of the cross compile ones?

Trying the same for the ring crate is extremely siimilar:
Crate: https://lib.rs/crates/ring
Repo:https://github.com/briansmith/ring

*new terminal with default env variables*
$ cargo remove littlefs2
...
$ cargo add ring
...
$ cargo build
The following warnings were emitted during compilation:

warning: [email protected]: Compiler family detection failed due to error: ToolNotFound: Failed to find tool. Is `riscv32-esp-elf-gcc` installed?
warning: [email protected]: Compiler family detection failed due to error: ToolNotFound: Failed to find tool. Is `riscv32-esp-elf-gcc` installed?

error: failed to run custom build command for `ring v0.17.8`

Caused by:
  process didn't exit successfully: `/home/nyrmburk/documents/dev/buildnative-espidf/target/debug/build/ring-6ae3434f56ff74da/build-script-build` (exit status: 1)
  --- stdout
  cargo:rerun-if-env-changed=RING_PREGENERATE_ASM
  cargo:rustc-env=RING_CORE_PREFIX=ring_core_0_17_8_
  OPT_LEVEL = Some(z)
  TARGET = Some(riscv32imc-esp-espidf)
  OUT_DIR = Some(/home/nyrmburk/documents/dev/buildnative-espidf/target/riscv32imc-esp-espidf/debug/build/ring-513392959b65266a/out)
  HOST = Some(x86_64-unknown-linux-gnu)
  cargo:rerun-if-env-changed=CC_riscv32imc-esp-espidf
  CC_riscv32imc-esp-espidf = None
  cargo:rerun-if-env-changed=CC_riscv32imc_esp_espidf
  CC_riscv32imc_esp_espidf = None
  cargo:rerun-if-env-changed=TARGET_CC
  TARGET_CC = None
  cargo:rerun-if-env-changed=CC
  CC = None
  cargo:rerun-if-env-changed=CROSS_COMPILE
  CROSS_COMPILE = None
  RUSTC_LINKER = Some(ldproxy)
  cargo:rerun-if-env-changed=CC_ENABLE_DEBUG_OUTPUT
  cargo:warning=Compiler family detection failed due to error: ToolNotFound: Failed to find tool. Is `riscv32-esp-elf-gcc` installed?
  RUSTC_WRAPPER = None
  cargo:rerun-if-env-changed=CRATE_CC_NO_DEFAULTS
  CRATE_CC_NO_DEFAULTS = Some(1)
  cargo:rerun-if-env-changed=CFLAGS_riscv32imc-esp-espidf
  CFLAGS_riscv32imc-esp-espidf = None
  cargo:rerun-if-env-changed=CFLAGS_riscv32imc_esp_espidf
  CFLAGS_riscv32imc_esp_espidf = None
  cargo:rerun-if-env-changed=TARGET_CFLAGS
  TARGET_CFLAGS = None
  cargo:rerun-if-env-changed=CFLAGS
  CFLAGS = None
  cargo:warning=Compiler family detection failed due to error: ToolNotFound: Failed to find tool. Is `riscv32-esp-elf-gcc` installed?

  --- stderr


  error occurred: Failed to find tool. Is `riscv32-esp-elf-gcc` installed?


warning: build failed, waiting for other jobs to finish...

Adding the compiler path for ring hit some compilation failures that are outside the scope of this issue. However if it succeeded, I think the following bindgen would fail for the same reason as littlefs2.

@Vollbrecht
Copy link
Collaborator

Vollbrecht commented Jul 8, 2024

In most situation the "simplest" way is let esp-idf-sys handle the bindgen creation for you. In case of your littlefs example, its probably also good to use a forked version that is known to work on esp-idf. It already exist on the esp-idf component registry, so you could add it to the build process described here. That could give you a little-fs sys module inside the esp-idf-sys. You would than go and instead of using the -sys module from littlefs2 rust crate, directly use the generated bindgens from us. In other words the littlefs2 crate would not use its own -sys module but the one you now build.

Other than that we propagate a bunch of information in the build script inside esp-idf-sys that gets produced by the embuild crate for consumption in downstream crates. This can be found here and you see it used in esp-idf-hal/svc buildscript.

Overall the creation of FFI bindings and the building of a C library into a static lib and including it are two separate things.

While not exactly the same but a similar case can be made about the rust bindings for the lvgl crate. I didn't look recently into it but i know that it can work with our system, without even knowing that we exist by essentially doing the heavy lifting by itself. They also generate a static C library and generate bindings off of that.

@AlixANNERAUD
Copy link

The same issue occurs with wamr-rust-sdk.

I'm not sure if this is related, but overriding LIBCLANG_PATH by sourcing export-esp.sh seems to interfere with the compilation of the regular x86_64-unknown-linux-gnu target when bindgen is used by crates:

  thread 'main' panicked at /home/alix_anneraud/.cargo/registry/src/index.crates.io-6f17d22bba15001f/bindgen-0.69.4/lib.rs:899:13:
  assertion `left == right` failed: "x86_64-unknown-linux-gnu" "x86_64-unknown-linux-gnu"
    left: 4
   right: 8

This issue did not occur before I updated to version 1.79.0 of the esp Rust toolchain.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Todo
Development

No branches or pull requests

3 participants