Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Debian系のLinuxでPython 2.xと3.xが同時利用できない問題の原因と対策 #301

Open
koron opened this issue Jan 31, 2013 · 72 comments

Comments

@koron
Copy link
Member

koron commented Jan 31, 2013

Ubuntuを始めDebian系のLinuxでPython 2.xと3.xが同時利用できません。

直接の原因はPythonがstatic linkで作られるのと同時に.soも提供されているからです。
Pythonが利用するモジュールはstatic linkでPythonに繋がるのに、
Vimは.soのほうに繋がるのでdlopenにRTLD_GLOBALが設定されてないと、
それらのモジュールを正しくロードできずに落ちてしまいます。
過去のvim-devの議論によれば「 落ちるよりは使えないほうがマシ 」と結論され
現在に至ったようです。

一番簡単な解決方法は、Pythonと関連モジュール一式を --enable-shared でコンパイルし直すことです。
デメリットは x86(32ビット)系で遅くなる ことですが、どうやら 64ビットではそのデメリットは無さそう です。

で本Issueのポイントは以下のとおりです:

  • このあたりの事情と対策が知られていないことが問題: ちゃんと解説をまとめておきたい
  • Debian方面に --enable-shared するように働きかけられないだろうか検討したい
@henrich
Copy link

henrich commented Jan 31, 2013

できると思いますよ。問題の事例とこうなってほしいという例が頂きたいです。

デメリットは x86(32ビット)系で遅くなる ことですが、どうやら 64ビットではそのデメリットは無さそう です。

これは数字がどこかにあったりしますかね?あると説得しやすいです。

@koron
Copy link
Member Author

koron commented Jan 31, 2013

問題の事例とこうなってほしいという例が頂きたいです。

「Vim から Python 2 とPython 3 の同時利用ができない」 というのがこのIssueで提示できる問題です。
もうちょっと具体的にいうと、Python2 を使うVimプラグインとPython 3を使うVimプラグインを同時に使うことができない、となりますね。
模式的ですが例としては

:py print(sys.version)
2.7.3 (...
:py3 print(sys.version)
E837: ...

もしくは

:py3 print(sys.version)
3.3.0 (...
:py print(sys.version)
E836

となってしまいますが

:py print(sys.version)
2.7.3 (...
:py3 print(sys.version)
3.3.0 (...

こうなって欲しいと言えます。が、あまりに一般性に欠けるとも思います。

これは数字がどこかにあったりしますかね?あると説得しやすいです。

私は持っていませんが、ちょっと聞いてみます。

@koron
Copy link
Member Author

koron commented Jan 31, 2013

問い合わせ中

@henrich
Copy link

henrich commented Jan 31, 2013

過去のchangelogみたらpystoneというので測ってたようなので、それを使えばいいかもしれませんね。

@k-takata
Copy link
Member

  • このあたりの事情と対策が知られていないことが問題: ちゃんと解説をまとめておきたい

一応公式ドキュメントに記載されていますが、もっと詳しくということでしょうか。
http://vim-jp.org/vimdoc-ja/if_pyth.html#E836

@koron
Copy link
Member Author

koron commented Jan 31, 2013

一応公式ドキュメントに記載されていますが、もっと詳しくということでしょうか。

各プラグインを使う人向けの文章もしくは記事が欲しい、と捉えてください。

指摘のドキュメントは if_python を使ってプラグインを書く人は読むでしょうが、
ただプラグインを使う人は読まないです。
そうなるとユーザはプラグインの相性、さらに読み込まれた順番に依存して症状が異なる
というわけのわからない問題に遭遇するので、それを救えないかなぁという動機です。

@methane
Copy link

methane commented Jan 31, 2013

https://gist.github.com/4681131
amd64でも結構性能差出てしまいました。
CPU が Core2 Duo という一応amd64動きますというモデルだからという可能性もありますが、
レジスタ数増えたから PIC のオーバーヘッド少ないはずというのは勘違いだったようです。

@koron
Copy link
Member Author

koron commented Jan 31, 2013

@methane Thanks!

ところでこれの読み方は

  • this が shared版
  • other が static版
  • 数字はそれぞれの項目にかかった時間(msec)
  • 殆どの項目で this > other なので shared版 遅すぎ

ってことで良いですか?

@koron
Copy link
Member Author

koron commented Jan 31, 2013

うげ。FreeBSDには shared 版と static 版、両方のpythonコマンドがインストールされてるっぽいw

@koron
Copy link
Member Author

koron commented Jan 31, 2013

https://gist.github.com/4681320

32bit はかなり遅いのね。やっぱディストリに働きかけるのはむりっぽい数字だわw

@ynkdir
Copy link
Member

ynkdir commented Jun 21, 2013

ubuntu は --enable-shared なってませんか
最近入った?

$ python -c 'import distutils.sysconfig; print(distutils.sysconfig.get_config_var("CONFIG_ARGS"))'
'--enable-shared' '--prefix=/usr' '--enable-ipv6' '--enable-unicode=ucs4' '--with-dbmliborder=bdb:gdbm' '--with-system-expat' '--with-system-ffi' '--with-fpectl' 'CC=x86_64-linux-gnu-gcc' 'CFLAGS=-D_FORTIFY_SOURCE=2 -g -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security ' 'LDFLAGS=-Wl,-Bsymbolic-functions -Wl,-z,relro'

@crazymaster
Copy link
Member

Ubuntu 13.04 64bit で --enable-shared になってることを確認

@msmhrt
Copy link

msmhrt commented Aug 10, 2013

別途、Issueを立てたほうが良いのかもしれませんが、とりあえずここに追記します。

先ほど、Ubuntu 12.04.2 LTSで、自前でビルドした--enable-sharedしてないPython 3.3.2を使って、-python / +python3なVimをビルドしようとしたのですが、:py3 print("A"):py3 import sys は問題ないのに、:py3 import timeで .soファイルのロードに失敗してエラーになるという現象が発生しました。

少し急ぎだったので、--enable-shared付きでPythonを再ビルドして、Vimの./configureで--enable-python3interp=dynamicを指定して解決したのですが、結局--enable-shared抜きのPythonでは、:py3 import timeができなかったのが気になっています。

もし既知の問題でなければ、どなたか追試をお願いできないでしょうか?

発生したエラーの具体的な内容は今すぐはちょっと確認できないので、後でコメントを追加します。

@msmhrt
Copy link

msmhrt commented Aug 10, 2013

下記が、:py3 import timeで発生したエラーの具体的な内容です。

Traceback (most recent call last):
  File "<string>", line 1, in <module>
ImportError: /home/msmhrt/local/lib/python3.3/lib-dynload/time.cpython-33m.so: u
ndefined symbol: PyExc_OSError
Press ENTER or type command to continue

先ほど書き忘れたのですが、OSはUbuntu 12.04.2 LTSの64ビット版、Vimは7.4b.022です。

@methane
Copy link

methane commented Aug 11, 2013

@msmhrt まさにこの issue の問題で、 Python 2 と Python 3 で名前がぶつからないように vim がlibpythonXY.so を読み込むときに読み込み元の名前が見えないようにしています。それが Python の拡張モジュール time*.so などが読み込まれる時も適用されます。
なので拡張モジュールは自身が libpythonXY.so に依存するようにリンクしておいて、自力で Python のAPIを見つけないといけないのですが、 --enable-shared されていないとそうなりません。

@methane
Copy link

methane commented Aug 11, 2013

13.04 で試してみましたが、やはり python コマンドは libpython を利用していません。

$ ldd /usr/bin/python3
    linux-vdso.so.1 =>  (0x00007fff5f96f000)
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f8019bbe000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f80199ba000)
    libutil.so.1 => /lib/x86_64-linux-gnu/libutil.so.1 (0x00007f80197b6000)
    librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f80195ae000)
    libexpat.so.1 => /lib/x86_64-linux-gnu/libexpat.so.1 (0x00007f8019385000)
    libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f801916d000)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f8018e68000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f8018aa0000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f8019df2000)
$ ldd /usr/bin/python2
    linux-vdso.so.1 =>  (0x00007fff465fe000)
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f2fcc2d6000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f2fcc0d2000)
    libutil.so.1 => /lib/x86_64-linux-gnu/libutil.so.1 (0x00007f2fcbece000)
    libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f2fcbcb7000)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f2fcb9b2000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f2fcb5e9000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f2fcc50a000)

Python コマンドと libpython で同一の拡張モジュールを利用するために、拡張モジュールが libpython に依存していないのも変わってません。

$ ldd /usr/lib/python3.3/lib-dynload/_json.cpython-33m-x86_64-linux-gnu.so 
    linux-vdso.so.1 =>  (0x00007fff5b9d5000)
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f7a8c0dd000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f7a8bd15000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f7a8c51b000)

@ynkdir
Copy link
Member

ynkdir commented Aug 11, 2013

libpython を static link する場合は vim のリンク時に -export-dynamic を付ければいけると思います。
python3-config --ldflags には付いてますが vim の configure は見てないようです。

@msmhrt
Copy link

msmhrt commented Aug 11, 2013

Vimのconfigureを、LDFLAGS=-export-dynamic ./configure ...で実行して、問題なきことを確認しました。

ちなみに、--enable-sharedしてないPython 2.7.5だけの場合は問題がなく、--enable-sharedしてないPython 3.2.5だけでも問題が発生しました。
どうやら、--enable-sharedしないと問題が発生するのは、Python 3だけで、3.3以外でも発生するようですね。

@koron
Copy link
Member Author

koron commented Aug 11, 2013

つまり autoconf 関連を直すか、http://vim-jp.org/docs/build_linux.html ここの記述に追加したほうが良い感じですか?

@msmhrt
Copy link

msmhrt commented Aug 11, 2013

あ、「問題なきことを確認」というのは、-python / +python3の話です。
残念ながら、--enable-sharedなしで、+python / +python3した場合については解決しませんでした。

@msmhrt
Copy link

msmhrt commented Aug 11, 2013

すみません。一点確認させてください。
+python / +python3を試そうとして、configureオプションで--enable-pythoninterp=yes --enable-python3interp=yesを指定したら、勝手に+python/dyn / +python3/dynになったのですが、+python / +python3にするconfigureオプションは現状存在しないのでしょうか?

@k-takata
Copy link
Member

両方使う場合は必ず /dyn になります。

@methane
Copy link

methane commented Aug 11, 2013

@msmhrt Python 2.7 で time を import できるのは、 time が Python 2.7 では extension module ではなくて builtin module だからだと思います。 datetime などではやっぱりダメなんでは無いでしょうか?

/usr/lib/python2.7/lib-dynload/ や /usr/lib/python3.3/lib-dynload/ のなかにあるモジュールで確認しないといけません。

@ynkdir
Copy link
Member

ynkdir commented Aug 11, 2013

@koron

つまり autoconf 関連を直すか、http://vim-jp.org/docs/build_linux.html ここの記述に追加したほうが良い感じですか?

ubuntu の python のパッケージは --enable-shared 付きなので今の記述で大丈夫と思います。debian はわかりません。

@msmhrt
Copy link

msmhrt commented Aug 11, 2013

@k-takata :

両方使う場合は必ず /dyn になります。

了解です。

@methane :

@msmhrt Python 2.7 で time を import できるのは、 time が Python 2.7 では extension module ではなくて builtin module だからだと思います。 datetime などではやっぱりダメなんでは無いでしょうか?

いえ、datetimeでも大丈夫でした。:version で確認したところ、リンクオプションに-export-dynamicが含まれていましたので、Python 3インターフェイスだけ修正が漏れていたのかもしれませんね。

@koron
Copy link
Member Author

koron commented Aug 11, 2013

@ynkdir Thanks!

そうなると autoconf で検出して正しくconfigureできると良さそうですね。

@koron
Copy link
Member Author

koron commented Jul 31, 2014

Ubuntu 14.04 で http://vim-jp.org/docs/build_linux.html とほぼいっしょな方法でビルドした場合、やはり同時ロードできてないっぽい。

なんか必要な作業ありましたっけ?

@ichizok
Copy link
Member

ichizok commented Jul 31, 2014

diff --git a/src/auto/configure b/src/auto/configure
--- a/src/auto/configure
+++ b/src/auto/configure
@@ -6352,6 +6352,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;}
@@ -6410,6 +6412,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; }
@@ -6417,6 +6420,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;}
@@ -6476,6 +6481,7 @@

   CFLAGS=$cflags_save
   LDFLAGS=$ldflags_save
+  LIBS=$libs_save

   PYTHON_SRC="if_python.c"
   PYTHON_OBJ="objects/if_python.o"

Ubuntu ではこれでいけると思います。
ただ、src/configure.in:1439 にある ArchLinux に何か影響しないかは気になりますが..

@koron
Copy link
Member Author

koron commented Jul 31, 2014

@ichizok

ポイントは「configure時に-ldl を付けること」ではなく、
その結果として「コンパイル時になんらかのオプションが付くこと」だと推測しているのですが
あっていますか?

あっているならばそのオプションを教えてください。

@k-takata
Copy link
Member

python2.7-dev ではなく python-dev の方には python2-config が入っているようです。
http://packages.ubuntu.com/ja/precise/amd64/python-dev/filelist

@k-takata
Copy link
Member

configure.in:3854 以降の "dnl Check for dynamic linking loader" のブロックって実は、python*/dyn のチェックより前にやるべきな気が。そうすれば "-ldl" の細工は不要になりそう?

@mattn
Copy link
Member

mattn commented Jul 31, 2014

ちなみに、僕が確認したサーバ(借り物)には python2-config は入っておらず python2.7-config しか入ってません。

@koron
Copy link
Member Author

koron commented Jul 31, 2014

python2-config があったらそれ使う。なかったら今のままの値を使う。
python3-configについても同様。

程度の修正で、ubuntuが救えれば良いと思ってます。

@ichizok
Copy link
Member

ichizok commented Jul 31, 2014

@koron

ということは既存の部分を流用するのではなく、

すみません、これってどういう意味でしょうか?

@koron
Copy link
Member Author

koron commented Jul 31, 2014

@ichizok #301 (comment)

で示してもらったパッチは、既存の「RTLD_GLOBAL が必要かどうかを判断する」
コードをUbuntuで動くように修正したものです。
そのために、他のディストリで動くかどうか再検証・テストする必要があります。

しかし新たに「UbuntuならばRTDL_GLOBAL が必要かどうかを判断する」
コードを 追加 できれば、他のディストリでの動作確認をすることなく採用できます。

@ichizok
Copy link
Member

ichizok commented Jul 31, 2014

そのために、他のディストリで動くかどうか再検証・テストする必要があります。

それはそうなんですが、ld のデフォルトオプションが原因なので
Ubuntu 以外のディストリでも(現在・今後)同じ問題になる可能性はあります。

根本の原因は -ldl を付ける位置がおかしいことなので..
(LDFLAGS ではなく LIBS に付けるのが適切なはずで、configure の他の部分ではそうしている)

@koron
Copy link
Member Author

koron commented Jul 31, 2014

私は「場当たり的な」パッチの、受け入れられやすい代替案を示したのです。
なにも正しい解決策までとは考えていません。

@koron
Copy link
Member Author

koron commented Jul 31, 2014

ついでに正しい解決策について言えば、
-ldl を付けるかどうかの判断をpythonより先にやる、はあまりよい案に思えていません。
なぜなら -ldl を付けたら現在のpythonの問題が直るのは副作用にすぎないからです。

いまある問題の本質は
「python を組み込む上で必要となるフラグやオプションが(決め打ちのために)間違っている」
であって 「それらに -ldl が含まれてないこと」ではありません。

@ichizok
Copy link
Member

ichizok commented Jul 31, 2014

-ldl を付けるかどうかの判断をpythonより先にやる、はあまりよい案に思えていません。

いや、libpython*.so を dlopen() でロードする等を実行する部分なので
-ldl をつけるのは python 関係ないです

@koron
Copy link
Member Author

koron commented Jul 31, 2014

いや、libpython*.so を dlopen() でロードする等を実行する部分なので
-ldl をつけるのは python 関係ないです

それは本issueのスコープではありません。
あくまでもこのissueの目的は
「Debian系のLinuxでPython 2.xと3.xが同時利用できない問題の原因と対策」
です。

@koron
Copy link
Member Author

koron commented Jul 31, 2014

仮に「python関係ない」が真ならば
-ldl をどのようにに付けるかの議論」
は本issueでする必要はないでしょう。

それを踏まえて

いまある問題の本質は
「python を組み込む上で必要となるフラグやオプションが(決め打ちのために)間違っている」
であって 「それらに -ldl が含まれてないこと」ではありません。

ということです。

@mattn
Copy link
Member

mattn commented Jul 31, 2014

-ldl はそもそも libcall に必要なので python に関係なく付くはずです。

@k-takata
Copy link
Member

Ubuntu 14.04 64bit で確認してみました。

Python 2.7, 3.4 ともに sysconfig.get_config_var("CONFIG_ARGS") の結果に --enabled-shared が含まれていることを確認。

configure 未修正のまま、configure を実行すると、

checking whether we can do without RTLD_GLOBAL for Python... no
checking whether we can do without RTLD_GLOBAL for Python3... no

の表示。config.log を確認すると、conftest.c に dlsym() がリンクできず、リンクエラー。

次に、configure をいじって、-ldl の調整を行ってから、configure を実行すると、やはり、

checking whether we can do without RTLD_GLOBAL for Python... no
checking whether we can do without RTLD_GLOBAL for Python3... no

の表示。config.log を確認すると、今度はリンクは成功しているが、import termios 実行中に、

ImportError: /usr/lib/python2.7/lib-dynload/termios.x86_64-linux-gnu.so: undefined symbol: PyExc_TypeError

の表示。

これは結局、モジュールが --enable-shared でコンパイルされていないということなのでしょうか?

@msmhrt
Copy link

msmhrt commented Jul 31, 2014

これは結局、モジュールが --enable-shared でコンパイルされていないということなのでしょうか?

はい、おっしゃる通りです。恐らくは、

$ objdump -p /usr/lib/python2.7/lib-dynload/termios.x86_64-linux-gnu.so | grep -e NEEDED
  NEEDED               libpthread.so.0
  NEEDED               libc.so.6
  NEEDED               libgcc_s.so.1

のように表示されると思いますのでご確認ください。

これがもし --enable-shared を有効にしてビルドしたモジュールであれば、

  NEEDED               libpython2.7.so.1.0
  NEEDED               libpthread.so.0
  NEEDED               libc.so.6
  NEEDED               libgcc_s.so.1

のように libpython* が結果に含まれます。

@k-takata
Copy link
Member

なるほど、

$ objdump -p /usr/lib/python2.7/lib-dynload/termios.x86_64-linux-gnu.so | grep -e NEEDED
  NEEDED               libpthread.so.0
  NEEDED               libc.so.6

でした。--enable-shared 無効のようですね。

@msmhrt
Copy link

msmhrt commented Jul 31, 2014

そういえば、 python*-condig は virtualenv環境にはコピーされなかったはずなので、もし今後 python*-config に頼るようにするのであれば、ドキュメントで注意を促した方がよいかもしれませんね。

※※※ 以下、単なる愚痴です ※※※
Python 3はABIフラグ(python3.4m の "m" の部分です)に --enable-shared でビルドしたかどうかのフラグを含めるべきだったのだと思います。

もしそうなっていれば、termios.cpython-34m.sotermios.cpython-34ms.sopython3.4m-configpython3.4ms-config のように異なるファイル名になるのでバッティングを気にする必要がなかったんですよね。

.so ファイル以外のファイルも共用できなくなりますのでファイルサイズを浪費することになったかもしれませんが、現状よりははるかにマシだったと思います。

@methane
Copy link

methane commented Jul 31, 2014

$ ldd /usr/bin/python2.7
    linux-vdso.so.1 =>  (0x00007ffff2ffe000)
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f9abf325000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f9abef5f000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f9abed5a000)
    libutil.so.1 => /lib/x86_64-linux-gnu/libutil.so.1 (0x00007f9abeb57000)
    libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f9abe93e000)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f9abe637000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f9abf552000)

実行ファイル版の python を --enable-shared=no でビルドして速度を稼いでるので、
ライブラリが libpython27.so に依存してしまうと、 /usr/bin/python2.7 と libpython2.7.so が競合してしまう。
それを回避するために、ライブラリは /usr/bin/python2.7 と一緒に --enable-shared=no でビルドして、
libpython27.so を埋め込んだアプリから読み込むときは RTLD_GLOBAL を使って Python/C API を呼ぶ様になってるんだと思います。

なので、 python-config 等を使うのではなくて、実際に RTLD_GLOBAL 無しで import termios ができるかチェックする今の configure 方式が一番いい気がします。

@methane
Copy link

methane commented Jul 31, 2014

@msmhrt Python 自体のビルドシステムはこんな変態的な構成をサポートしていません。
Debian が勝手にディスクサイズを軽量化するためにやってることです。
--enable-shared かどうかは ABI に関係しないので、 ABI フラグに含めるのは違う気がします。

@splhack
Copy link
Member

splhack commented Nov 1, 2015

:py print(sys.version)
2.7.3 (...
:py3 print(sys.version)
3.3.0 (...

こうなる環境は存在しますか?

@splhack
Copy link
Member

splhack commented Nov 1, 2015

$ vim --cmd 'py print("test")' --cmd 'py3 print("test")' --cmd 'quit'
Vim: Caught deadly signal SEGV
Vim: Finished.
$ vim --cmd 'py3 print("test")' --cmd 'py print("test")' --cmd 'quit'
Vim: Caught deadly signal SEGV
Vim: Finished.

OS Xの場合、configureは、RTLD_GLOBAL不要と判断するので、python_loaded python3_loaded のチェックは動きません。

/* Define if dynamic python does not require RTLD_GLOBAL */
#define PY_NO_RTLD_GLOBAL 1

/* Define if dynamic python3 does not require RTLD_GLOBAL */
#define PY3_NO_RTLD_GLOBAL 1

UNIXがdefineされてる環境で、py, py3が同時に動く環境て存在しますか?

OS Xだけが特殊なんでしょうか? PY_NO_RTLD_GLOBALとかをundefすれば、SEGV受けずには済みますが。

$ vim --cmd 'py print("test")' --cmd 'py3 print("test")' --cmd 'quit'
test
Error detected while processing pre-vimrc command line:
E837: This Vim cannot execute :py3 after using :python
E263: Sorry, this command is disabled, the Python library could not be loaded.

@k-takata
Copy link
Member

k-takata commented Nov 2, 2015

UNIXがdefineされてる環境で、py, py3が同時に動く環境て存在しますか?

Linuxでは python2/3 ともに --enable-shared でビルドしておけば両方同時に使えるという結論でした。(私自身は試していませんが。)

@ichizok
Copy link
Member

ichizok commented Nov 2, 2015

私が試した範囲では、Linux, Solaris は py/py3 の同時利用が可能です。
(おそらく *BSD でも可能と思います)

OS Xだけが特殊なんでしょうか?

OS X というか、OS X での python モジュールのビルド設定が原因です。

python の各モジュール Python.Framework/Versions/<ver>/lib/python<ver>/lib-dynload/*.so-undefined dynamic_lookup オプションとともにビルドされるため、参照すべき python lib の情報を持っていません。(otool -L で確認できます)

そのため、Vim が libpython (2.x) と libpython3 両方をロードした場合、python モジュールが「どちらの lib にも含まれる関数」を呼び出そうとした際には、自分のバージョンに合致した lib を選択することはできず、先にロードされた lib の関数を呼ぶことになります。

具体的には、

$ vim --cmd 'py print("test")' --cmd 'py3 print("test")' --cmd 'quit'

py print("test")
-> libpython (2.x) をロード
-> (snip) -> PyInit__heapq コールのため python2.x/lib-dynload/_heapq.so をロード
-> PyInit__heapq 内で PyModule_AddObject をコール
-> libpython (2.x) の PyModule_AddObject をコール (OK)

py3 print("test")
-> libpython3 をロード
-> (snip) -> PyInit__heapq コールのため python3.x/lib-dynload/_heapq.cpython-35m-darwin.so をロード
-> PyInit__heapq 内で PyModule_AddObject をコール
-> libpython3 でなく、先にロードされた libpython (2.x) の PyModule_AddObject をコール
-> SEGV

各モジュールのビルド時に、linkage 情報 (-lpython とか) を与えるようにすれば同時に使えるようになるのでは?と思うのですが、確認していません。

[追記]
ビルドフラグを変更して python モジュールをビルドすることで、py/py3 を同時利用できることを確認しました。
[/追記]

@splhack
Copy link
Member

splhack commented Nov 3, 2015

ありがとうございます。
py/py3を同時利用できるかどうか、Vimランタイムから知ることは可能でしょうか?

otool -Lで何かを確認できるなら、Vimのpython_loadedあたりでプログラム的に同じことをして、SIGSEGVせずに、py→py3もしくはpy3→pyを拒否したい。

  • 現状SIGSEGVして困っている
  • py/py3を同時に使いたいわけではない
  • py/py3を同時に使いたい人がいたら、自力でPython 2/3をビルドして使えることを否定しない(だけど、ランタイムでpy/py3が同時利用できるかできないか判断できないなら、少なくとも、MacVimでは強制的にpython_loaded python3_loadedで落として、SIGSEGVを防がないとだめだなと)

@ichizok
Copy link
Member

ichizok commented Nov 3, 2015

python3 の場合、otool でモジュールの状態を確認すると以下のようになります。

デフォルト (libSystem.B.dylib のみリンク)

$ otool -L /usr/local/Frameworks/Python.framework/Versions/3.5/lib/python3.5/lib-dynload/_ctypes.cpython-35m-darwin.so
/usr/local/Frameworks/Python.framework/Versions/3.5/lib/python3.5/lib-dynload/_ctypes.cpython-35m-darwin.so:
        /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1213.0.0)

py→py3 で同時利用可能 (Python (libpython3) がリンクされている)

$ otool -L /usr/local/Frameworks/Python.framework/Versions/3.5/lib/python3.5/lib-dynload/_ctypes.cpython-35m-darwin.so
/usr/local/Frameworks/Python.framework/Versions/3.5/lib/python3.5/lib-dynload/_ctypes.cpython-35m-darwin.so:
        /usr/local/Frameworks/Python.framework/Versions/3.5/Python (compatibility version 3.5.0, current version 3.5.0)
        /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1225.1.1)
  • py→py3 では、 py3 モジュールが libpython3 をリンクしていること
  • py3→py では、 py モジュールが libpython をリンクしていること

...を確認できれば良いかと思います。

@splhack
Copy link
Member

splhack commented Nov 3, 2015

ありがとうございます。しかし、考えてみると、どのsoファイルが読み込まれるかわからないのではないかという結論に達しました(dlopenがどのdylibを読むかわからない(DYLD_FRAMEWORK_PATHとか使ってdlopenの挙動を再実装するとか)、dylibが特定できてもどのsoファイルを読みに行くかわからない(いろいろやればできなくもないでしょうけど))。MacVimはconfigureいじって、PY*_NO_RTLD_GLOBAL=0になるようにしてしまいます。

@splhack
Copy link
Member

splhack commented Dec 19, 2015

あやしげなconfigureオプションを追加してみました macvim-dev/macvim#181

@splhack
Copy link
Member

splhack commented May 18, 2016

同時使用に成功しました https://gist.github.com/splhack/4ec93591aec286beac496bbd5cc8d764

2も3もPYTHONHOME環境変数に依存してるので、どうしたもんだろうかと思ったんですが、一旦初期化してしまえば、問題なしぽいですね。

@methane
Copy link

methane commented May 18, 2016

Ubuntu はデフォルトは Python 3 にして、 Python 2 を使いたい人は vim-nox-py2 などを
別にインストールさせるようにしていますね。

一番重要そう(かつ開発者が Python 3対応に消極的)だった YouCompleteMe がもう Python 3 に対応したので、
同時ロードを頑張るよりも未だに Python 2 にしか対応してない vim plugin の Python 3 対応を
手助けするなり代替を用意するほうが建設的な気がします。

@k-takata
Copy link
Member

本家で同様の話題が出ていた (vim/vim#1504) ので、ここでのやりとりを元にコメントをしておきましたが、Debian/Ubuntu がどうやってビルドしているのかをちゃんと把握していないので間違ったことを書いていないか心配…。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

10 participants