vimでvim-quickrunというプラグインを使ってRustコンパイルする設定をしていた時、つまづいたところがあったんですが、 他に情報が載っていなかったので、メモします。
起きた問題
vim-quickrunは、vimのコマンドラインモードで:QuickRun
と打ち込むだけで任意のプログラムを実行し、結果を表示してくれる便利なプラグインです。
デフォルトでRustに対応しており、filetypeがRustの時はrustcでコンパイルした結果を表示してくれるはずでした。
しかし、以下のようなエラーが表示されてしまいました。
'"D:\Documents\rust-test\hello_world\src\main"' は、内部コマンドまたは外部コマンド、 操作可能なプログラムまたはバッチ ファイルとして認識されていません。
結論
g:quickrun_config
に以下のように記せば良いことがわかりました。
let g:quickrun_config = {
\ 'rust': {
\ 'exec': ['%c %o %s', '%s:p:r %a'],
\ 'tempfile': 'tmp.rs',
\ 'hook/sweep/files': ['%S:p:r', '%S:p:r.pdb', '%S:p:r.exe', 'tmp.pdb' ,'tmp.exe'],
\ },
\ }
検証
QuickRunは、デフォルトのquickrun_config
で、Rustを以下のように実行するよう設定されています。
let g:quickrun_config = {
\ 'rust': {
\ 'command': 'rustc',
\ 'exec': ['%c %o %s -o %s:p:r', '%s:p:r %a'],
\ 'tempfile': '%{tempname()}.rs',
\ 'hook/shebang/enable': 0,
\ 'hook/sweep/files': '%S:p:r',
\ },
では、これがどのように実行されているのか。
QuickRunにはデバッグ機能があるそうで、:QuickRun -debug a
とやると変数a
に結果が保存されます。
そして、echo g:a.commands
とやると、以下のように実行されたことがわかります。
'"C:\Users\isudzumi\.cargo\bin\rustc.EXE" "D:\Documents\rust-test\hello_world\src\main.rs" -o "D:\Documents\rust-test\hello_world\src\main"', '"D:\Documents\rust-test\hello_world\src\main" ']
-o
で指定されているところがポイントになります。
rustcでも、gccなどと同様、-o
オプションは出力ファイル名を指定します。
しかし、拡張子も指定しないといけないという制約があります。
試しにrustc main.rs -o main
と実行すると、拡張子なしのmain
という実行ファイルが生成されます。
ここが問題だったんですね。
つまり、g:quickrun_config
に
'rust': {
'exec': ['%c %o %s -o %s:p:r.exe', '%s:p:r %a'],
}
としてやれば良いわけです。
ただ、これだとWindowsでしか実行できません。
rustcでは、-o
オプションを指定しなくても、ソースファイルと同じ名前の実行ファイルを生成してくれます。
そこで、-o
自体を取ってしまいました。
'rust': {
'exec': ['%c %o %s', '%s:p:r %a'],
}
言うのを忘れていましたが、ここで使っているrustcのバージョンは1.24.1です。
じゃあこれで出来たかというと、まだ終わりではありませんでした。
これを:w
で保存せずに実行すると、以下のようなエラーが表示されます。
error: invalid character `.` in crate name: `VIG2253.tmp`
error: aborting due to previous error
要はソースファイル名に.
が含まれているから怒られたわけです。
デバッグ結果は以下になります。
'"C:\Users\isudzumi\.cargo\bin\rustc.EXE" "C:\Users\isudzumi\AppData\Local\Temp\VIG2253.tmp.rs"',
'"C:\Users\isudzumi\AppData\Local\Temp\VIG2253.tmp" ']
QuickRunはソースファイルを保存せすに実行する際、tempファイルを作成します。
これがデフォルトでは.
を含むため、こうしたエラーが出てしまいました。
デフォルトの%{tempname()}
のままではどうしても解決できないので、
'rust': {
'tempfile': 'tmp.rs',
}
という風に、tempファイルの名前を決めてしまいました。
こうすると、tmp.pdb
とtmp.exe
が生成され、tmp.exe
の実行結果が表示されます。
tempファイルが残るのはちょっと汚いので、以下の設定を追加し、実行後に生成されたファイルが消えるようにしました。
'rust': {
'hook/sweep/files': ['%S:p:r', %S:p:r.pdb', '%S:p:r.exe', 'tmp.pdb' ,'tmp.exe']
}
これで想定通りに動くようになりました。