Rust Build Windows DLL on WSL

以前にこのような記事を書いたが、
e-tipsmemo.hatenablog.com

Rustupにformatterが標準機能になったらしいので
cargoからインストールするのではなく、

rustup component add rustfmt-preview

を行って、.vimrcに

let g:rustfmt_autosave = 1

だけを書けばよくなった。(と思われる)

Cross Compileの設定

$ rustup target list | grep windows
i586-pc-windows-msvc
i686-pc-windows-gnu
i686-pc-windows-msvc
x86_64-pc-windows-gnu
x86_64-pc-windows-msvc

x86のDLLが作りたいのでi686の方を入れる。

$ rustup target add x86_64-pc-windows-gnu
$ rustup target add i686-pc-windows-gnu

このままビルドするとエラーでるので

$ sudo apt install mingw-w64

プロジェクト作成

$ cargo new hello

これでsrcにlib.rsだけのcrateができる。

Cargo.tomlと同じ回想に.cargo/configを作って

$ cat .cargo/config
[target.i686-pc-windows-gnu]
linker = "/usr/bin/i686-w64-mingw32-gcc"

[target.x86_64-pc-windows-gnu]
linker = "/usr/bin/x86_64-w64-mingw32-gcc"

とする。

このプロジェクト自体を常にi686向けにビルドしたい場合、

[build]
target="i686-pc-windows-gnu"

を追加する。

DLL出力設定

Cargo.tomlに以下を追記する。

[dependencies]
winapi = "0.2.7"
user32-sys = "*"
libc = "*"

[lib]
path = "src/lib.rs"
crate-type = ["cdylib"]

[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3", features = ["winuser"] }

後々 kernel32 crateも必要になるかもしれない。

とりあえず

cargo build

でビルドできることを確認する。

DLL作成

lib.rs

呼び出し規約を合わせるための
"C"や"system"といった修飾子がよくわからない。
とりあえず"C"にしたところdependency_walkerでもdllexpでも、i686、x64のDLLともに、関数がexportされているのが確認できた。
DLLに対する様々なイベント時によばれるDllMain関数は”system”にした。
www.unknowncheats.me


lib.rsによって生成されたDLLをdependency_walkerで見たところ。
f:id:katakanan:20180320211425p:plain
helloが見えていればOK

動作を確かめるためにVisual Studio 2017で以下のプログラムを実行した。
生成されるexeと同じ場所にrustで作ったDLLを置くか、外部参照として追加する必要がある。

DLLのATTACHされたイベントが飛んできて、何回かDLLに関するイベントが飛んできた後に、helloが呼ばれたときのMessageBoxが出現する。
f:id:katakanan:20180320212426p:plainf:id:katakanan:20180320212351p:plain