Blank File

LinuxとかPythonとかVimとか、趣味でいじる感じで

Ubuntuのvimで :python と :python3 を同時に有効にする(リベンジ)

Ubuntu 14.04 + Vim 7.4.507 でPythonインターフェイスとPython3インターフェイスを同時に使えるようにします。 筆者はUbuntuを使いましたが、Debian系のディストリであれば同じ方法でできると思います。

この記事は素人がよく理解せずに書いています。色々とアレな方法な気がします。何が起きても自己責任でお願いします。

[2014/11/14 追記] Pyenvを使う方法をコメントで教えていただだきました。 VimPythonで2/3系両方使えず困っていることがある方は、下記のid:lambdalisueさんの記事をご参照ください。

はじめに

半年ほど前の記事(Debian: vimでPythonとPython3の両方使えるようになってた(ように見えたけどそうでもなかった) - Blank File)で挫折したような内容です。 ちょうどLinuxでPythonをビルドするときの --enable-shared オプションについて - Qiitaという記事が公開されたので、こちらを参考にUbuntuでリベンジしました。

Debian系のディストリではPythonが2系/3系ともに特殊な構成でビルドされているようです *1 。 そのせいで、Debian系のディストリでは単純にはVimからpython2とpython3を同時に使用できません。 UbuntuにデフォルトでインストールされるVimもpython2インターフェイスだけが有効になっています *2

というわけで、なんとかUbuntuでPython2/3が両方有効なVimを使ってやろうというのが本記事の趣旨です。 ざっくりとした手順は以下のとおりです。

  1. --enable-shared オプション付きでビルドされたPython2とPython3を用意する
  2. Vimにパッチを適用する
  3. 用意したPython2とPython3に PATHを通した状態で Vimをビルド

Python2とPython3のビルド

VimでPython2とPython3を同時に使うためには、両方のバイナリが--enable-sharedオプション付きでビルドされている必要があります。 しかし、UbuntuDebian系ディストリ)のシステムデフォルトのPythonはこのオプションなしらしいので、2と3両方を別途自分で用意しなくてはなりません。

まずPythonのソースを適当なディレクトリに持ってきます。 ソースコードは公式サイト(Download Python)から必要なバージョンをダウンロードするか、開発用のリポジトリをローカルにcloneしてくるかの二択になります。 リポジトリを使う場合は、リリースバージョンごとにタグが打たれているのでバージョンを指定してhg updateします。

hg clone https://hg.python.org/cpython
cd cpython
hg update -r v3.4.2

後述しますが、ここで使うPythonのバージョンはシステムのもの(普段PATHを通しているもの)とマイナーバージョンまで同じものがいいと思います。 Ubuntu 14.04の場合は、通常 Python 2.7.6 と Python 3.4.0 のはずです。 私は今回 Python 2.7.8Python 3.4.2 をビルドしました。

ビルドする環境の整え方については以下の記事を参照してください。

私は上記methaneさんのQiitaの記事の「対策1 rpath を設定する」の方法を使いました。 公式のリポジトリをクローンし、そのディレクトリ内で以下のコマンドを実行しました。 --prefixのパスなどは適宜変更してください。

hg update -r v2.7.8
./configure \
    --prefix=$HOME/Applications/python2.7.8-vim \
    --enable-shared \
    LDFLAGS=-Wl,-rpath,$HOME/Applications/python2.7.8-vim/lib \
make j -4
make install

make distclean

hg update -r v3.4.2
./configure \
    --prefix=$HOME/Applications/python3.4.2-vim \
    --enable-shared \
    LDFLAGS=-Wl,-rpath,$HOME/Applications/python3.4.2-vim/lib \
make j -4
make install

ついでにPython2の方にpipを入れておきます *3

curl -kL https://raw.github.com/pypa/pip/master/contrib/get-pip.py | $HOME/Applications/python2.7.8-vim/bin/python

Python3の方は、3.4以上のバージョンであれば勝手にpipが入っているはずです。 もし3.4なのにpipが自動インストールされていない場合は、libssl-devがインストールされているか確認してください。 このライブラリがなくてもビルドは成功してエラーは出ないのですが、pipの自動インストールに失敗します。 なかなかのハマりポイントだと思います。

Vimにパッチを当てる

以下を参考に、Vimソースコードからビルドする環境整えます。

./configure を実行する手前までは同じです。 ./configureする前に、VimソースコードIchizok氏のパッチ を当てます。

TortoiseHGを使っている場合は、パッチをクリップボードにコピーし、「リポジトリ」→ 「パッチの取り込み(import)」→ 「クリップボードからインポート」でパッチを読み込み、「パッチの適用先」で「作業領域」を指定すれば適用できます。

一応、適用できない時のために執筆時現在での最新版(7.4.507)用に微調整(行番号変更)したパッチを置いておきます。 最悪、パッチの行番号と前後のコードを参考に手作業でsrc/auto/configureファイルを修正してもそんなに手間ではないと思います。

diff -r 9dff716fb9aa src/auto/configure
--- a/src/auto/configure    Thu Nov 06 10:03:01 2014 +0100
+++ b/src/auto/configure    Sat Nov 08 02:04:14 2014 +0900
@@ -6361,6 +6361,8 @@
   CFLAGS="$CFLAGS $PYTHON_CFLAGS"
   ldflags_save=$LDFLAGS
     LDFLAGS="-ldl $LDFLAGS"
+  libs_save=$LIBS
+  LIBS="$LIBS -ldl"
   if test "$cross_compiling" = yes; then :
   { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
@@ -6419,6 +6421,7 @@
 
   CFLAGS=$cflags_save
   LDFLAGS=$ldflags_save
+  LIBS=$libs_save
 
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we can do without RTLD_GLOBAL for Python3" >&5
 $as_echo_n "checking whether we can do without RTLD_GLOBAL for Python3... " >&6; }
@@ -6426,6 +6429,8 @@
   CFLAGS="$CFLAGS $PYTHON3_CFLAGS"
   ldflags_save=$LDFLAGS
     LDFLAGS="-ldl $LDFLAGS"
+  libs_save=$LIBS
+  LIBS="$LIBS -ldl"
   if test "$cross_compiling" = yes; then :
   { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
@@ -6485,6 +6490,7 @@
 
   CFLAGS=$cflags_save
   LDFLAGS=$ldflags_save
+  LIBS=$libs_save
 
   PYTHON_SRC="if_python.c"
   PYTHON_OBJ="objects/if_python.o"

Vimをビルドする

修正したソースでVimをビルドします。 ポイントは、先ほどビルドした--enable-shared付きのPythonにPATHを通した状態でビルドすることです。

私は以下のスクリプトvimのソースの親ディレクトリで実行しました。 python以外のオプションは必要に応じて変更してください。

#!/bin/sh

cd vim/src
make distclean

OLDPATH=$PATH
export PATH=$HOME/Applications/python3.4.2-vim/bin:$PATH
export PATH=$HOME/Applications/python2.7.8-vim/bin:$PATH

./configure \
    --prefix=$HOME/usr \
    --with-features=huge \
    --enable-multibyte \
    --enable-gui=gtk2 \
    --enable-pythoninterp=dynamic \
    --enable-python3interp=dynamic \
    --enable-luainterp=dynamic \
    --with-lua-prefix=/usr \
    --with-luajit \
    --enable-gpm \
    --enable-acl \
    --enable-xim \
    --enable-fail-if-missing

export PATH=$OLDPATH

上記のスクリプトでは、一時的にPATHの設定を変え、--enable-sharedオプション付きのpythonとpython3を見に行かせています。 --with-python-config-dirオプションは指定しなくてもいい感じに処理してくれます。

ログがずらずらと出てきますが、以下のような部分で今回インストールしたpythonを見に行っていれば成功です *4

checking ...
checking ...
checking for python2... /home/[username]/Applications/python2.7.8-vim/bin/python2
checking Python version... 2.7
checking Python is 2.3 or better... yep
checking Python's install prefix... /home/[username]/Applications/python2.7.8-vim
checking Python's execution prefix... /home/[username]/Applications/python2.7.8-vim
checking Python's configuration directory... /home/[username]/Applications/python2.7.8-vim/lib/python2.7/config
checking if -pthread should be used... yes
checking if compile and link flags for Python are sane... yes
checking --enable-python3interp argument... dynamic
checking for python3... /home/[username]/Applications/python3.4.2-vim/bin/python3
checking Python version... 3.4
checking Python is 3.0 or better... yep
checking Python's abiflags... m
checking Python's install prefix... /home/[username]/Applications/python3.4.2-vim
checking Python's execution prefix... /home/[username]/Applications/python3.4.2-vim
checking Python's configuration directory... /home/[username]/Applications/python3.4.2-vim/lib/python3.4/config-3.4m
checking if -pthread should be used... yes
checking if compile and link flags for Python 3 are sane... yes
checking whether we can do without RTLD_GLOBAL for Python... yes
checking whether we can do without RTLD_GLOBAL for Python3... yes
checking ...
checking ...

エラーがなければ、make して make install すれば指定したディレクトリにインストールされます。

確認

新しくインストールしたVimを起動し、確認してみます。

:versionの出力で +python/dyn+python3/dyn が含まれていれば、とりあえず両方使えます。 ただ、:pythonしてから:python3した時(逆の順番でも)にエラー(E837)になる事もあるので、両方実行するまで安心できません。

私は以下のようなスクリプトを実行して確認しました。 ついでにバイナリやライブラリのパスを確認しています。

echo "---- Python3 ----"
python3 <<EOF
from pprint import pprint
import sys
print(sys.executable)
print(sys.prefix)
print(sys.exec_prefix)
pprint(sys.path)
print(sys.version_info)
import datetime
print(datetime.__file__)
EOF
echo "\n---- Python2 ----"
python <<EOF
from pprint import pprint
import sys
print(sys.executable)
print(sys.prefix)
print(sys.exec_prefix)
pprint(sys.path)
print(sys.version_info)
import datetime
print(datetime.__file__)
EOF

出力

---- Python3 ----
/usr/bin/python3
/home/[username]/Applications/python3.4.2-vim
/home/[username]/Applications/python3.4.2-vim
['/home/[username]/Applications/python3.4.2-vim/lib/python3.4',
 '/home/[username]/Applications/python3.4.2-vim/lib/python3.4/plat-x86_64-linux-gnu',
 '/home/[username]/Applications/python3.4.2-vim/lib/python3.4/lib-dynload',
 '/home/[username]/Applications/python3.4.2-vim/lib/python3.4/site-packages',
 '_vim_path_']
sys.version_info(major=3, minor=4, micro=0, releaselevel='final', serial=0)
/home/[username]/Applications/python3.4.2-vim/lib/python3.4/datetime.py

---- Python2 ----
/usr/bin/python
/home/[username]/Applications/python2.7.8-vim
/home/[username]/Applications/python2.7.8-vim
['/home/[username]/Applications/python2.7.8-vim/lib/python2.7',
 '/home/[username]/Applications/python2.7.8-vim/lib/python2.7/plat-x86_64-linux-gnu',
 '/home/[username]/Applications/python2.7.8-vim/lib/python2.7/lib-tk',
 '/home/[username]/Applications/python2.7.8-vim/lib/python2.7/lib-old',
 '/home/[username]/Applications/python2.7.8-vim/lib/python2.7/lib-dynload',
 '/home/[username]/.local/lib/python2.7/site-packages',
 '/home/[username]/Applications/python2.7.8-vim/lib/python2.7/site-packages',
 '_vim_path_']
sys.version_info(major=2, minor=7, micro=6, releaselevel='final', serial=0)
/home/[username]/Applications/python2.7.8-vim/lib/python2.7/lib-dynload/datetime.so

Pythonのバイナリはシステムの/usr/bin以下のものを使っていますが、ライブラリは今回ビルドしたものを参照しています。 これは標準モジュールも例外ではないので、Pythonのバージョンが異なるとエラーの原因になりかねません。 したがって、Pythonのビルドの説明で書いたように、Pythonのバージョンは揃えておいたほうが無難です。 ちなみに、原因不明ですが、私の場合は:python import pipはエラーになりました。 マイクロバージョン(三桁目)まで揃えたほうがいいのかもしれません。

また、:python:python3で外部モジュールをimportする場合、今回ビルドしたPythonにインストールしておく必要があります。 そのような必要に迫られる機会は少ないと思いますが、一応方法を書いておくと、今回インストールしたPythonのpipでインストールするだけです。

~/Applications/python2.7.8-vim/bin/pip install [module]
~/Applications/python3.4.2-vim/bin/pip3 install [module]

Virtualenv(miyakogi/vim-virtualenvを利用)の仮想環境内では、:pythonはきちんとvirtualenvで指定されたバイナリとライブラリを使っていました。 一方、:python3の方はバイナリは仮想環境のものでしたが、ライブラリは変わっていませんでした。 これはプラグインの方を修正すれば直るんでしょうか *5

終わりに

この記事は上記の方法でビルドしたVimを使ってMarkdownで書いています。 ついでにPythonインターフェイスを使ったプラグイン(未公開)でライブプレビューもしていますが、今の所不具合なく使えています。

Pythonのバイナリと参照するライブラリの食い違いが非常に気持ち悪いのですが、WindowsやArchLinuxなどではどうなっているんでしょう? 特にArchはシステムデフォルトのPythonが3系なのにVimPythonインターフェイスではpyhton2.7を使っているので、いい感じに何かしてありそうです。

なお、現状python3インターフェイスを使っているVimプラグインは皆無に等しいので、両方使えてもあまり意味ないと思います。

*1:LinuxでPythonをビルドするときの --enable-shared オプションについて - Qiita の末尾や このあたりの議論 を参照

*2:Vimのpython2とかpython3って何?って方はこちらを参照してください。 - VimとPythonのバージョン — KaoriYa

*3:Python - いつの間にかpipのインストールが楽になってた件 - Qiita

*4:書きながら気づきましたが、この時python2を見に行って実行時にはpythonを使うのってどうなんでしょう?ログがそうなってるだけ?(コード見てない)

*5:簡単な修正では直りませんでした