はじめに
私が扱う特殊な環境のひとつに、mingw-w64
でビルドしたVimと、msys2
でビルドしたVimが共存している環境がある。
どちらも$HOME
を同じ場所にしているため、同一の.vimrc
、runtimepath
を見に行くようになっている。
このような環境で問題になるのは各環境用にビルドが必要なvimprocで、以前pathogenで管理していたときはそれぞれの環境でmake
を手動実行すればよかったのだが、dein.vimに乗り換えてからはそれだけでは済まなくなってしまった。
特殊な状況なので同一のことに悩まれている方は少ないかと思うが、ひとまず解決に至ったので記事にまとめることにする。
前提となる環境
下記の環境でVimを扱う場合を想定している。
- Windowsネイティブ環境:
mingw-w64
でビルドしたVim、またはvim-jpで配布されているVim - msys2のシェル内:
vim
パッケージのvim - mingw32/64のシェル内:
vim
パッケージのvim
また、vimproc
はTOMLに以下のように書いてあると想定する。
[[plugins]]
repo = 'Shougo/vimproc'
hook_post_update = '''
if dein#util#_is_windows()
let cmd = 'tools\\update-dll-mingw'
elseif dein#util#_is_cygwin()
let cmd = 'make -f make_cygwin.mak'
elseif executable('gmake')
let cmd = 'gmake'
else
let cmd = 'make'
endif
let g:dein#plugin.build = cmd
'''
問題点
1. どちらかのDLLしか作られない
前提とする環境だと2種類のDLL(Windows用のDLLとCygwin用のDLL)を作らなければならないのだが、この設定だとdein#install()
やdein#update()
した環境のDLLしか作られない。
DLLが作られなかった環境でdein#reinstall('vimproc')
すればよいのかとも思ったが、「そんなプラグインはねーよ!」と怒られてしまった。
2. mingw32/64のシェルでVimを立ち上げるとvimprocのビルドに失敗する
前提とする環境の場合、WindowsネイティブなVimではなくmingw32/64でもmsysでビルドしたVimを利用するようにしている。
dein#install()
やdein#update()
でvimprocのビルドが走るのだが、msysでビルドしたVimなのでdein#util#_is_cygwin()
が1
を返すこととなり、上記の設定だとmake -f make_cygwin.mak
が走ることとなる。
ただし、シェル環境自体はmingw32/64なので、このままだとビルドに失敗してしまう。
解決策
2016/10/31 Update
以下のようにTOMLを修正することでとりあえずうまく動くようになった。
[[plugins]]
repo = 'Shougo/vimproc'
merged = 0
hook_add = '''
if dein#util#_is_windows()
let s:vimproc_dll_basename = has('win64') ?
\ 'vimproc_win64.dll' : 'vimproc_win32.dll'
elseif dein#util#_is_cygwin()
let s:vimproc_dll_basename = 'vimproc_cygwin.dll'
elseif dein#util#_is_mac()
let s:vimproc_dll_basename = 'vimproc_mac.so'
elseif glob('/lib*/ld-linux*64.so.2', 1) != ''
let s:vimproc_dll_basename = 'vimproc_linux64.so'
elseif glob('/lib*/ld-linux*.so.2', 1) != ''
let s:vimproc_dll_basename = 'vimproc_linux32.so'
elseif system('uname -s') =~? '^.\+BSD\n$'
let s:vimproc_dll_basename = system(
\ 'uname -sm | tr "[:upper:]" "[:lower:]"'
\ .' | sed -e "s/ /_/" | xargs -I "{}" echo "vimproc_{}.so"')[0 : -2]
else
let s:vimproc_dll_basename = 'vimproc_unix.so'
endif
let s:vimproc_dll = get(g:, 'vimproc#dll_path', dein#get('vimproc').path . '/lib/'. s:vimproc_dll_basename)
if !filereadable(s:vimproc_dll)
call dein#call_hook('post_update')
call dein#build('vimproc')
endif
'''
hook_post_update = '''
if dein#util#_is_windows()
let cmd = 'tools\\update-dll-mingw'
elseif dein#util#_is_cygwin()
let cmd = 'make -f make_cygwin.mak'
if $MSYSTEM == "MINGW32" || $MSYSTEM == "MINGW64"
let cmd = "MSYSTEM=MSYS bash --login -c 'cd " . g:dein#plugin.path . ";" . cmd . "'"
endif
elseif executable('gmake')
let cmd = 'gmake'
else
let cmd = 'make'
endif
let g:dein#plugin.build = cmd
'''
mingw32/64のシェルからmsysのVimが起動された場合はmsysのシェルからmake
を叩くようにしてみた。
さらに、hook_add
フックでg:vimproc#dll_path
にファイルがあるかを調べ、なければビルドしてdein#recache_runtimepath()
でキャッシュを再構築するようにしている。
このタイミングでdein#recache_runtimepath()
して問題ないのかはよく調べていないが、今のところ問題なく動いているようだ。
dein.vim作者のShougo氏がコメント欄にmore betterな解決方法を教えてくださったので反映を行った。
-
merged = 0
とする -
dein#build
を使用する
さらに上記修正を行うと、私の環境では稀にg:vimproc#dll_path
に値がセットされる前にhook_add
フックが呼ばれることがあったため、hook_add
内の判定を若干修正した。
恐らくdein#build
はこの記事で私がビルドし直そうとしていたがために実装してくれたのだろう。非常に感謝である。
本来ならばbuild = "make"
としておけば解決なのだが、MinGW32/64なシェルでMSYSビルドのVimを使おうとしているためにmake
だけの場合だとmake -f make_mingw32.mak
またはmake -f make_mingw63.mak
が走ることになり、vimproc_cygwin.dllが作られないためにこのようなトリッキーな手法をキメなければならなくなっている。
MinGW32/64なシェルでMSYSビルドのVimを使うことがなければこのような手法は不要なので、どうかbuild = make
だけ書いて、必要なときに手動でcall dein#build('vimproc')
するようにしてほしい。