rust-lang / rust-bindgen

Automatically generates Rust FFI bindings to C (and some C++) libraries.
https://rust-lang.github.io/rust-bindgen/
BSD 3-Clause "New" or "Revised" License
4.34k stars 687 forks source link

Bindgen passes the rust target to clang. It should pass the host target #1728

Open ceigel opened 4 years ago

ceigel commented 4 years ago

I'm trying to build bindings for minimp3 (https://github.com/lieff/minimp3). I am using these bindings from an embedded project, with target "thumbv7em-none-eabihf". I call bindgen from build.rs, together with the cc invocation to compile the C library. I get a large amount of errors from clang about types being in the wrong architecture (see below). When calling bindgen with the same arguments (taken from .command_line_flags() method) the generation finishes successfully. When I force bindgen to pass the HOST env var to the clang compiler as the --target flag the generation is also successful (see build.rs). I think my solution is a hack and the default behavior of bindgen should be to pass the host target to clang. I believe this issue is similar to issue #1555

Bindgen Invocation

bindgen --output src/bindings.rs bindgen.h --rust-target 1.33 --no-derive-default --ctypes-prefix cty --generate functions,types,vars,methods,constructors,destructors --use-core -- -Iminimp3

Build.rs usage

extern crate bindgen;
extern crate cc;
use std::env;
use std::path::PathBuf;

fn main() {
    println!("cargo:rustc-link-lib=minimp3");
    println!("cargo:rerun-if-changed=minimp3.c");
    println!("cargo:rerun-if-changed=bindgen.h");
    let mut build = cc::Build::new();
    build
        .include("minimp3")
        .define("MINIMP3_IMPLEMENTATION", None)
        .define("MINIMP3_NO_STDIO", None)
        .file("minimp3.c")
        .compile("minimp3");

    let bb = bindgen::builder()
        .header("bindgen.h")
        .ctypes_prefix("cty")
        .generate_comments(true)
        .rustfmt_bindings(true)
        .clang_arg("-Iminimp3")
        // uncomment to make it work .clang_arg(format!("--target={}", env::var("HOST").unwrap()))
        .use_core();
    eprintln!(
        "please run bindgen --output src/bindings.rs {}",
        bb.command_line_flags().join(" ")
    );

    // bindgen --output src/bindings.rs bindgen.h --rust-target 1.33 --no-derive-default --ctypes-prefix cty --generate functions,types,vars,methods,constructors,destructors --use-core -- -Iminimp3
    let bindings = bb.generate().expect("Unable to generate bindings");

    let out_path = PathBuf::from("src");
    bindings
        .write_to_file(out_path.join("bindings.rs"))
        .expect("Couldn't write bindings!");
}

Errors:1) --- stdout cargo:rustc-link-lib=minimp3 cargo:rerun-if-changed=minimp3.c cargo:rerun-if-changed=bindgen.h TARGET = Some("thumbv7em-none-eabihf") OPT_LEVEL = Some("0") HOST = Some("x86_64-apple-darwin") CC_thumbv7em-none-eabihf = None CC_thumbv7em_none_eabihf = None TARGET_CC = None CC = None CROSS_COMPILE = None CFLAGS_thumbv7em-none-eabihf = None CFLAGS_thumbv7em_none_eabihf = None TARGET_CFLAGS = None CFLAGS = None CRATE_CC_NO_DEFAULTS = None DEBUG = Some("true") CARGO_CFG_TARGET_FEATURE = None running: "arm-none-eabi-gcc" "-O0" "-ffunction-sections" "-fdata-sections" "-fPIC" "-g" "-fno-omit-frame-pointer" "-mthumb" "-mfloat-abi=hard" "-march=armv7e-m" "-mfpu=fpv4-sp-d16" "-I" "minimp3" "-Wall" "-Wextra" "-DMINIMP3_IMPLEMENTATION" "-DMINIMP3_NO_STDIO" "-o" "/Users/.../src/stm32f3/example-sound/minimp3-ffi/target/thumbv7em-none-eabihf/debug/build/minimp3-ffi-f769533addf55ac0/out/minimp3.o" "-c" "minimp3.c" exit code: 0 AR_thumbv7em-none-eabihf = None AR_thumbv7em_none_eabihf = None TARGET_AR = None AR = None running: "ar" "crs" "/Users/.../src/stm32f3/example-sound/minimp3-ffi/target/thumbv7em-none-eabihf/debug/build/minimp3-ffi-f769533addf55ac0/out/libminimp3.a" "/Users/.../src/stm32f3/example-sound/minimp3-ffi/target/thumbv7em-none-eabihf/debug/build/minimp3-ffi-f769533addf55ac0/out/minimp3.o" exit code: 0 cargo:rustc-link-lib=static=minimp3 cargo:rustc-link-search=native=/Users/.../src/stm32f3/example-sound/minimp3-ffi/target/thumbv7em-none-eabihf/debug/build/minimp3-ffi-f769533addf55ac0/out

--- stderr please run bindgen --output src/bindings.rs bindgen.h --rust-target 1.40 --no-derive-default --ctypes-prefix cty --generate functions,types,vars,methods,constructors,destructors --use-core -- -Iminimp3 /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/cdefs.h:807:2: error: Unsupported architecture /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/machine/_types.h:34:2: error: architecture not supported /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/_types.h:55:9: error: unknown type name 'int64_t' /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/_types.h:56:9: error: unknown type name 'int32_t' /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/_types.h:57:9: error: unknown type name 'int32_t' /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/_types.h:60:9: error: unknown type name 'uint32_t' /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/_types.h:61:9: error: unknown type name 'uint32_t' /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/_types.h:62:9: error: unknown type name 'uint64_t' /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/_types.h:68:9: error: unknown type name 'darwin_natural_t' /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/_types.h:70:9: error: unknown type name 'uint16_t' /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/_types.h:71:9: error: unknown type name 'int64_t' /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/_types.h:72:9: error: unknown type name 'int32_t' /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/_types.h:73:9: error: unknown type name 'uint32_t' /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/_types.h:74:9: error: unknown type name 'int32_t' /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/_types.h:75:9: error: unknown type name 'uint32_t' /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/_types.h:76:9: error: unknown type name 'uint32_t' /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/machine/types.h:37:2: error: architecture not supported /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/_types/_intptr_t.h:32:9: error: unknown type name 'darwin_intptr_t' /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/cdefs.h:807:2: error: Unsupported architecture, err: true /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/machine/_types.h:34:2: error: architecture not supported, err: true /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/_types.h:55:9: error: unknown type name 'int64_t', err: true /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/_types.h:56:9: error: unknown type name 'int32_t', err: true /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/_types.h:57:9: error: unknown type name 'int32_t', err: true /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/_types.h:60:9: error: unknown type name 'uint32_t', err: true /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/_types.h:61:9: error: unknown type name 'uint32_t', err: true /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/_types.h:62:9: error: unknown type name 'uint64_t', err: true /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/_types.h:68:9: error: unknown type name '__darwin_natural_t', err: true /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/_types.h:70:9: error: unknown type name 'uint16_t', err: true /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/_types.h:71:9: error: unknown type name 'int64_t', err: true /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/_types.h:72:9: error: unknown type name 'int32_t', err: true /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/_types.h:73:9: error: unknown type name 'uint32_t', err: true /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/_types.h:74:9: error: unknown type name 'int32_t', err: true /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/_types.h:75:9: error: unknown type name 'uint32_t', err: true /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/_types.h:76:9: error: unknown type name 'uint32_t', err: true /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/machine/types.h:37:2: error: architecture not supported, err: true /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/_types/_intptr_t.h:32:9: error: unknown type name '__darwin_intptr_t', err: true thread 'main' panicked at 'Unable to generate bindings: ()', src/libcore/result.rs:1165:5 note: run with RUST_BACKTRACE=1 environment variable to display a backtrace.

emilio commented 4 years ago

Hmmm... I'm confused. You generally want to generate the bindings for the target. Otherwise you may get wrong bindings.

It just seems like you're not passing the right include / sysroot flags to correctly find those types, so it's failing with weird errors when including host headers, which seems obviously bad.

ceigel commented 4 years ago

I am confused as well. I'm not an expert of bindgen but I expect running from command-line or calling the library from build.rs to be identical. The default target of my project is "thumbv7em-none-eabihf". Finding documentation about passing the right way to call bindgen when building cross-compiled libraries is not easy.

ceigel commented 4 years ago

I added "-I/usr/local/opt/gcc-arm-none-eabi-74/arm-none-eabi/include/" to the clang_arg and it also worked. Thank you @emilio for the suggestion.

bunnie commented 4 years ago

I also ran into this problem, and opened a pull request #1734 to add to the list of possible problems a host v. target architecture mismatch. Took me a day of head scratching before I came across this thread, so at least a note about the issue might save other embedded developers an afternoon down the road...

fwiw, I am developing for risc-v and I was unable to get it to work by adding the sysroot includes as @ceigel did. It turns out my problem is actually even weirder than his, I am trying to build an FFI binding for a library to format data packets for a network coprocessor that's ARM architecture, from an embedded CPU that's RISC-V, being developed on an x86_64 machine.

So in this case, neither host nor target is the architectural binding I'm looking to generate. That being said, the vendor's C API for their ARM-based coprocessor is "oblivious" to all of this, and people have used it successfully from various ARM and x86 hosts and it's worked, likely because they don't do anything too arcane with respect to packing data into structs, and thus the mismatch of host v. target in the C API hasn't been a problem (afaik).

My final solution to this was to just run bindgen from the command line on the x86_64 host and commit the output as a static artifact. Ugly, but probably OK given that this is essentially what everyone has been doing when they target the C API from C.