Bindgen can't find included file

How does bindgen resolve includes?
I'm using cargo-vcpkg which automatically prints cargo:include=... statements in build.rs, does it read those? If not, do I have to provide include path to it somehow?

It seems that bindgen can't find the file I'm including:

Caused by:
  process didn't exit successfully: `C:\Users\j\Source\presentdata-sys\target\debug\build\presentmon-sys-0e1df1374bc0d0ac\build-script-build` (exit code: 101)
  --- stdout
  cargo:include=C:\Users\j\Source\presentdata-sys\target\vcpkg\installed\x64-windows-static-md\include
  cargo:rustc-link-search=native=C:\Users\j\Source\presentdata-sys\target\vcpkg\installed\x64-windows-static-md\lib
  cargo:rustc-link-lib=PresentData
  cargo:rerun-if-changed=wrapper.hpp

  --- stderr
  wrapper.hpp:2:10: fatal error: 'version.h' file not found
  wrapper.hpp:2:10: fatal error: 'version.h' file not found, err: true
  thread 'main' panicked at 'Unable to generate bindings: ()', build.rs:32:10
  note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

wrapper.hpp is just this for now:

#include "version.h"
// #include "PresentMonTraceConsumer.hpp"

the version.h is at C:\Users\j\Source\presentdata-sys\target\vcpkg\installed\x64-windows-static-md\include\version.h, but I don't want to hardcode the path (as far as I understand I shouldn't have to).

build.rs if needed
use std::env;
use std::path::PathBuf;

fn main() {
    let lib = vcpkg::Config::new()
        .emit_includes(true)
        .find_package("presentmon")
        .expect("vcpkg failed");
    // dbg!(&lib);

    println!("cargo:rerun-if-changed=wrapper.hpp");

    let bindings = bindgen::builder()
        .header("wrapper.hpp")
        .parse_callbacks(Box::new(bindgen::CargoCallbacks))
        .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!");
}

I don't think there's any way for bindgen to read the cargo:include lines printed by vcpkg, though it would be great if that were possible.

The only way I can see to provide include paths to bindgen is with the clang_arg/clang_args methods. In order to integrate this with vcpkg, the vcpkg crate might need to add another way to retrieve the list of include paths. (Or it could even add an optional dependency on bindgen and a method that passes extra arguments directly to a bindgen::Builder.)

1 Like

I see, I didn't realize I had to provide the include path to clang, since when I tried it it didn't work.
vcpkg provides Library.include_paths : Vec<PathBuf>, but each contains directories which contain the actual files to include. Clang doesn't recursively include subdirectories automatically, and forcing it with appending /** doesn't seem to work, so I just use WalkDir to get all the subdirectories and include them, and then it works.

working build.rs
use std::env;
use std::path::PathBuf;
use walkdir::WalkDir;

fn main() {
    let lib = vcpkg::Config::new()
        .emit_includes(true)
        .find_package("presentmon")
        .expect("vcpkg failed");
    // dbg!(&lib);

    let mut include_dirs: Vec<String> = Vec::new();
    for path in lib.include_paths {
        for subdir in WalkDir::new(path)
            .into_iter()
            .filter_entry(|e| e.file_type().is_dir())
        {
            let dir = subdir.unwrap().path().to_string_lossy().to_string();
            include_dirs.push(format!("--include-directory={}", dir));
        }
    }

    println!("cargo:rerun-if-changed=wrapper.hpp");

    let bindings = bindgen::builder()
        .header("wrapper.hpp")
        .parse_callbacks(Box::new(bindgen::CargoCallbacks))
        .clang_arg("-v")
        .clang_args(include_dirs)
        .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!");
}

When compiling C code, normally you provides (a list of) directories to the compiler and the compiler finds header files with matching names from them. Common format is -I/path/to/include/dir, like this.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.