RustからC/C++のDLLを呼び出してDLLにアタッチ
はじめに
RustからVisual Studio 2022で作成したDLLを呼び出す設定と、Visual Studio 2022からC/C++のDLLにアタッチしてデバッグするまでの手順を記載します。
記事を書こうと思ったのは、デバッグしてみたら思わぬ現象(良い方)に出くわしたのがきっかけです。
Windows 11
- Rust
- Visual Studio Code(VSCode)
- C++
- Visual Studio Community 2022 (以下VS2022)
ソース
プロジェクト作成/実装
1つのフォルダにC++とRustのプロジェクトをそれぞれ作成していきます。
- root
- C++ (ソリューション名:sample_dll)
- Rust (パッケージ名:rust_c)
C/C++ VS2022
-
VS2022でダイナミックリンクライブラリ(DLL)
C++
Windows
ライブラリ
を作成 -
最初から用意されているファイル(pch.h/pch.c)にexport関数を定義/実装
pch.h
#include "stdint.h"
extern "C" {
__declspec(dllexport) uint32_t __stdcall add(uint32_t, uint32_t);
}
pch.c
uint32_t add(uint32_t a, uint32_t b) {
return a + b;
}
- ビルド
いったん完成です。
Rust VSCode
- cargo new
> cargo new rust_c
- VSCodeで main.rs 追記
fn main() {
let get_u32 = ||{
let mut a = String::new();
std::io::stdin().read_line(&mut a).unwrap();
a.trim().parse::<u32>().unwrap_or_default()
};
loop {
let a = get_u32();
let b = get_u32();
let ans = unsafe { add(a,b) };
println!("{}",ans);
if ans == 100{
break;
}
}
}
extern "C" {
fn add(a:u32,b:u32)->u32;
}
- *.libのリンクと場所を指示
この状態でビルドすると
error LNK2019: 未解決の外部シンボル add
となるのでbuild.rsで*.libのリンク方法と場所を設定します。
リンク方法はダイナミックリンクにします。
use std::env;
fn main(){
let dir = env::var("CARGO_MANIFEST_DIR").unwrap();
println!(r"cargo:rustc-link-search=native={}/../sampl_dll/x64/Debug",dir);
println!("cargo:rustc-link-lib=dylib={}","sampl_dll");
}
これでビルドが通ります。
動作確認
VSCodeでfn main()のRunを実行すると
error: process didn't exit successfully: `target\debug\rust_c.exe` (exit code: 0xc0000135, STATUS_DLL_NOT_FOUND)
STATUS_DLL_NOT_FOUNDのとおり、dllが見つけられずに実行できません。
コピーしてくれば実行できるが、今回はVS2022の出力ディレクトリを変更することにします。
ということで、VS2022で出力ディレクトリを変更して再ビルドします。
プロジェクトのプロパティ > 全般 > 出力ディレクトリ
変更前
$(SolutionDir)$(Platform)\$(Configuration)\
修正後
$(SolutionDir)..\rust_c\target\$(Configuration)\
build.rsも修正します。
use std::env;
fn main(){
let dir = env::var("CARGO_MANIFEST_DIR").unwrap();
let deb_rel = env::var("PROFILE").unwrap();
println!(r"cargo:rustc-link-search=native={}/target/{}",dir,deb_rel);
println!("cargo:rustc-link-lib=dylib={}","sampl_dll");
}
アタッチ
- VSCodeからfn main()のRunを実行
DebugだとVSCodeがアタッチしているためVS2022がアタッチできないです
実行直後は標準入力待ちのため停止しているので、この隙にアタッチします。
- VS2022でアタッチ/ブレークポイント設定
デバッグ > プロセスにアタッチ
アタッチする実行ファイルはRustのパッケージ名(今回はrust_c)で検索してください。
アタッチに成功するとブレークポイントが設定可能になります。
以下のように設定します。
3.Rustのプログラムを進める
数字を2つ入力し、プログラムを進めると設定したブレークポイントで停止します。
あとがき
ここからブレークポイントを進めると、VS2022のままRustコードに入ることができます。
これがVSCode LLDB拡張よりも見やすくて感動しました。
同時にVSCode以外のIDEをきちんと試すべきだと思いました。
RustRoverとかを触っておけばよかったと後悔しています。😭
Discussion