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.29k stars 681 forks source link

can't parse msvc inline __asm #2034

Open Orycterope opened 3 years ago

Orycterope commented 3 years ago

I'm trying to cross-compile from x64 ubuntu to i686-pc-windows-msvc using the include files from msvc-wine and bingen fails to parse the msvc inline asm blocks in winnt.h.

The inline asm blocks in question use the __asm syntax specific to MSVC (official doc), allowed on 32bit only, which should be supported by llvm.

The error I get is very easily reproducible with the following header file:

// input.h
void test() {
    int i = 42;
    __asm    {
        mov     ecx, i
        mov     eax, ecx
    }
}
// build.rs
fn main() {
    bindgen::Builder::default()
        .header("test.h")
        .generate()
        .unwrap();
}

Trying to compile it with cargo build --target i686-pc-windows-msvc shows the following error:

   Compiling asm_bindgen v0.1.0 (/home/orycterope/workspace/asm_bindgen)
error: failed to run custom build command for `asm_bindgen v0.1.0 (/home/orycterope/workspace/asm_bindgen)`

Caused by:
  process didn't exit successfully: `/home/orycterope/workspace/asm_bindgen/target/debug/build/asm_bindgen-7d7435a9639ad2dc/build-script-build` (exit code: 101)
  --- stderr
  test.h:21:5: error: MS-style inline assembly is not available: Unable to find target for this triple (no targets are registered)
  test.h:21:5: error: MS-style inline assembly is not available: Unable to find target for this triple (no targets are registered), err: true
  thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: ()', build.rs:5:10

My knowledge of llvm and clang is very limited, but I found this llvm mailing thread from 2013 when this used to make the lib crash, and added the error that we see. It suggests calling

llvm::InitializeAllTargets();
llvm::InitializeAllTargetMCs();
llvm::InitializeAllAsmPrinters();
llvm::InitializeAllAsmParsers();

to initialize the MS target Assembly Parser so it can recognize __asm blocks, which presumably is always done by clang but not by libclang. It also mentions that this is not needed for gcc style inline asm because they are not handled by a target Assembly Parser.

I don't really know how to go about this issue. Any advice ?

emilio commented 3 years ago

This seems like something that would need to be done in upstream libclang, unless I'm missing something, reading the discussion in https://github.com/Caphyon/clang-power-tools/issues/177 / https://reviews.llvm.org/D17981...