Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rust cdylib crate, linking dll to C program in Windows

Tags:

c

gcc

rust

I have been trying to compile a simple rust cdylib crate in windows and linking it with a simple c program. Despite all my efforts I fail to link the dll file.

Minimal example

First of all my rustc version is:

C:\Users\User> rustc --version
rustc 1.50.0 (cb75ad5db 2021-02-10)

I have a basic Cargo.toml which includes a cbindgen and sets the crate type:

[package]
name = "mycrate"
version = "0.1.0"
authors = ["PauMAVA <--REDACTED-->"]
edition = "2018"

[lib]
name = "mycrate"
crate-type = ["cdylib"]

[build-dependencies]
cbindgen = "0.18.0"

Then the lib.rs only declares a really simple extern hello world function:

#[no_mangle]
pub extern "C" fn test_fn() {
    println!("Hello world from Rust!")
}

Finally, I generate the header file via cdbindgen in build.rs:

extern crate cbindgen;

use std::env;
use std::path::Path;
use cbindgen::{Config, Builder};

fn main() {
    let crate_env = env::var("CARGO_MANIFEST_DIR").unwrap();
    let crate_path = Path::new(&crate_env);
    let config = Config::from_root_or_default(crate_path);
    Builder::new().with_crate(crate_path.to_str().unwrap())
        .with_config(config)
        .generate()
        .expect("Cannot generate header file!")
        .write_to_file("testprogram/headers/mycrate.h");
}

The generated header is the following:

/* Generated with cbindgen:0.18.0 */

#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>

void test_fn(void);

The C code I have is the following simple program:

#include <stdio.h>
#include "headers/mycrate.h"

int main() {
    printf("Hello world from C!\n");
    test_fn();
}

Just to clarify, my file structure is the following:

testprogram
|-- headers
|    |-- mycrate.h
|
|-- main.c
|-- mycrate.dll

When I try to compile and link I get a linker error:

C:\Users\User\...\testprogram> gcc .\main.c -L.\mycrate.dll -o .\main
c:/mingw/bin/../lib/gcc/mingw32/8.2.0/../../../../mingw32/bin/ld.exe: C:\Users\Pau\AppData\Local\Temp\cccQGbDk.o:main.c:(.text+0x1b): undefined reference to `test_fn'
collect2.exe: error: ld returned 1 exit status

Additional Information

The weird thing is that when compiling in WSL (Linux) I get a .so Linux library that just links correctly:

$ gcc main.c -L./mycrate.so -o main
$ ./main
Hello world from C!
Hello world from Rust!

What am I missing here? I guess this is merely a linking issue but I can't find the source of it. Any help is appreciated!

EDIT

I have also tried using an absolute path when linking. I am currently using MinGW.

EDIT 2

Also tried linking with the include library mycrate.dll.lib generated by cargo:

C:\Users\User\...\testprogram> gcc .\main.c -L.\mycrate.dll.lib -o .\main
c:/mingw/bin/../lib/gcc/mingw32/8.2.0/../../../../mingw32/bin/ld.exe: C:\Users\Pau\AppData\Local\Temp\ccL0sH7B.o:main.c:(.text+0x1b): undefined reference to `test_fn'
collect2.exe: error: ld returned 1 exit status

The rustc --version --verbose output is:

C:\Users\User\...\testprogram> rustc --version --verbose
rustc 1.50.0 (cb75ad5db 2021-02-10)
binary: rustc
commit-hash: cb75ad5db02783e8b0222fee363c5f63f7e2cf5b
commit-date: 2021-02-10
host: x86_64-pc-windows-msvc
release: 1.50.0
like image 974
PauMAVA Avatar asked Nov 04 '25 08:11

PauMAVA


1 Answers

I think there are multiple problems here.

  1. You compile the library for a 64bit system (because Rust is x86_64), but you try to link it with 32bit MinGW
  2. Rust is using the MSVC toolchain and you try to compile the C program with MinGW
  3. I am not entirely sure about that, but I think you linked the mycrate.dll.lib incorrectly. According to that answer you should prefix it with l like so: -L -lmycrate.dll.lib

Obviously there are multiple ways to fix that. For example you can install Rust, so that it uses the MinGW toolchain as explained here.

Or you can use Visual Studio to compile your C code. That is what I did, because I did not want to bother with reinstalling Rust (Please correct me if am wrong, but I think there is no easy way to configure both MSVC and MinGW backends, so that one can switch easily between them in Rust).

The steps to compile and link with VisualStudio 2019 are as follows:

  1. Build the Rust project cargo build --release with your 64 bit Rust installation using MSVC
  2. Create a new Empty C++ project
  3. Add main.c and insert your code
  4. In the same directory where your solution file is placed put headers/mycrate.h
  5. Copy mycrate.dll and mycrate.dll.lib into the same directory where your Solution file is placed
  6. Right click the C++ project in VisualStudio and select Properties
  7. Select Configuration=Release and Platform=x64
  8. Add $(SolutionDir)\headers; to C/C++ -> General -> Additional Include Directories
  9. Add $(SolutionDir)mycrate.dll.lib; to Linker -> Input -> Additional Dependencies
  10. Apply all changes and close the properties pane
  11. Build the project in Release mode with the x64 platform

If you build the Rust project in debug mode (e.g. cargo build) you will have to do the same for Debug mode.

I know it is kind of a convoluted process, so let me know if I should make Repo that serves as a demo for that process...

As I said, if you like to build using MinGW, you will have to setup Rust differently as explained here.

like image 180
frankenapps Avatar answered Nov 07 '25 04:11

frankenapps



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!