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.23k stars 679 forks source link

error: linking with `link.exe` failed: exit code: 1120 #2800

Closed Niwo04 closed 3 months ago

Niwo04 commented 3 months ago

I'm trying to generate bindings for the NVENC lib, but some functions cannot be linked for whatever reason.

Excerpt from nvEncodeAPI.h:

NVENCSTATUS NVENCAPI NvEncodeAPICreateInstance(NV_ENCODE_API_FUNCTION_LIST *functionList);

NVENCSTATUS NVENCAPI NvEncInitializeEncoder(void* encoder, NV_ENC_INITIALIZE_PARAMS* createEncodeParams);

build.rs:

use std::{env, path::PathBuf};

fn main() {
    println!("cargo:rustc-link-search=C:\\Users\\janne_lnpq1lo\\Desktop\\test\\lib");
    println!("cargo:rustc-link-lib=nvencodeapi");

    let bindings = bindgen::Builder::default()
        .header("src/wrapper.h")
        .parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
        .allowlist_function("NvEncodeAPICreateInstance")
        .allowlist_function("NvEncInitializeEncoder")
        .generate()
        .expect("Unable to generate bindings");

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

Excerpt from generated bindings:

extern "C" {
    pub fn NvEncInitializeEncoder(
        encoder: *mut ::std::os::raw::c_void,
        createEncodeParams: *mut NV_ENC_INITIALIZE_PARAMS,
    ) -> NVENCSTATUS;
}

extern "C" {
    pub fn NvEncodeAPICreateInstance(functionList: *mut NV_ENCODE_API_FUNCTION_LIST) -> NVENCSTATUS;
}

main.rs:

pub mod nvenc;

use std::ptr;

use nvenc::{NvEncInitializeEncoder, NvEncodeAPICreateInstance};

fn main() {
    unsafe {
        NvEncodeAPICreateInstance(ptr::null_mut());
        NvEncInitializeEncoder(ptr::null_mut(), ptr::null_mut());
    }
}

My problem is that NvEncodeAPICreateInstance works perfectly fine, but when I include code involving NvEncInitializeEncoder I get the link error.

I'm on Windows 10, my build tools are up to date and my rust toolchain is nightly-x86_64-pc-windows-msvc.

emilio commented 3 months ago

This smells like the dll not containing the symbols, or it not being marked as dllexport, or rust not finding it properly somehow... Does it happen without bindgen (just with the plain symbol declaration)? How does the function declarations look like in the header (is there any difference between them, like calling convention or something)?

Niwo04 commented 3 months ago

I used dumpbin to check the lib file and this is the output:

PS C:\Users\janne_lnpq1lo\Desktop\test_lol\src> dumpbin /exports /symbols nvencodeapi.lib
Microsoft (R) COFF/PE Dumper Version 14.39.33523.0
Copyright (C) Microsoft Corporation.  All rights reserved.

Dump of file nvencodeapi.lib

File Type: LIBRARY

COFF SYMBOL TABLE
000 010161BB ABS    notype       Static       | @comp.id
001 00000000 SECT2  notype       External     | __IMPORT_DESCRIPTOR_nvEncodeAPI64
002 C0000040 SECT2  notype       Section      | .idata$2
003 00000000 SECT3  notype       Static       | .idata$6
004 C0000040 UNDEF  notype       Section      | .idata$4
005 C0000040 UNDEF  notype       Section      | .idata$5
006 00000000 UNDEF  notype       External     | __NULL_IMPORT_DESCRIPTOR
007 00000000 UNDEF  notype       External     | nvEncodeAPI64_NULL_THUNK_DATA

String Table Size = 0x5E bytes

COFF SYMBOL TABLE
000 010161BB ABS    notype       Static       | @comp.id
001 00000000 SECT2  notype       External     | __NULL_IMPORT_DESCRIPTOR

String Table Size = 0x1D bytes
COFF SYMBOL TABLE
001 00000000 SECT2  notype       External     | nvEncodeAPI64_NULL_THUNK_DATA
String Table Size = 0x23 bytes

     Exports

       ordinal    name

                  NvEncodeAPICreateInstance
                  NvEncodeAPIGetMaxSupportedVersion
  Summary
          D5 .debug$S
          14 .idata$2
          14 .idata$3
           8 .idata$4
           8 .idata$5
          12 .idata$6

The functions are indeed missing, but why are they in the .h file when I can't use them. The docs say I should just link to the functions. What can I do to fix this?

emilio commented 3 months ago

Hmm, I'm honestly not sure, but I don't work on Windows generally, and that seems outside the scope of bindgen... I'd cross-check with other dlls or so? Or maybe you need to dlopen(). Maybe the dynamic library feature in bindgen can help with that?