純粋なPython不明なシステムに配布したいスクリプト$ Python構成。したがって、Pythonスタンドアロン実行可能ファイルへのコード。
走る cython --embed ./foo.py
は問題なくfoo.c
。次に、私は走る
gcc $(python3-config --cflags) $(python3-config --ldflags) ./foo.c
どこ python3-config --cflags
与える
-I/usr/include/python3.5m -I/usr/include/python3.5m -Wno-unused-result -Wsign-compare -g -fdebug-prefix-map=/build/python3.5-MLq5fN/python3.5-3.5.3=. -fstack-protector-strong -Wformat -Werror=format-security -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes
およびpython3-config --ldflags
与える
-L/usr/lib/python3.5/config-3.5m-x86_64-linux-gnu -L/usr/lib -lpython3.5m -lpthread -ldl -lutil -lm -Xlinker -export-dynamic -Wl,-O1 -Wl,-Bsymbolic-functions
この方法で、問題なく実行される動的にリンクされた実行可能ファイルを取得します。 ldd a.out
収量
linux-vdso.so.1 (0x00007ffcd57fd000)
libpython3.5m.so.1.0 => /usr/lib/x86_64-linux-gnu/libpython3.5m.so.1.0 (0x00007fda76823000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fda76603000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fda763fb000)
libutil.so.1 => /lib/x86_64-linux-gnu/libutil.so.1 (0x00007fda761f3000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fda75eeb000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fda75b4b000)
libexpat.so.1 => /lib/x86_64-linux-gnu/libexpat.so.1 (0x00007fda7591b000)
libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007fda756fb000)
/lib64/ld-linux-x86-64.so.2 (0x00007fda77103000)
今、私はオプションを追加しようとします-static
をgccに送信しますが、これはエラーになります。
/usr/bin/ld: dynamic STT_GNU_IFUNC symbol `strcmp' with pointer equality in `/usr/lib/gcc/x86_64-linux-gnu/6/../../../x86_64-linux-gnu/libc.a(strcmp.o)' can not be used when making an executable; recompile with -fPIE and relink with -pie
collect2: error: ld returned 1 exit status
Lddが提供するすべての共有ライブラリも静的ライブラリとしてインストールされることを確認しました。
それで、これはpython3-configで指定されたオプションとの非互換性ですか?
経験した問題は、明らかにリンカに由来します(gccはそれを確認するために、内部でリンカを起動しました--v
でgccを起動するだけです-冗長モードで)。それでは、リンケージプロセスがどのように機能するかを簡単に思い出してみましょう。
リンカは、解決する必要があるすべてのシンボルの名前を保持します。最初はシンボルmain
のみです。リンカがライブラリを検査するとどうなりますか?
静的ライブラリの場合、リンカーはこのライブラリ内のすべてのオブジェクトファイルを参照し、このオブジェクトファイルが検索対象のシンボルを定義する場合、オブジェクトファイル全体が含まれます(つまり、一部のシンボルは解決されますが、さらに新しい未解決のシンボルは追加されます)。リンカーは、静的ライブラリを複数回渡す必要がある場合があります。
共有ライブラリの場合、リンカからは単一の巨大なオブジェクトファイルで構成されるライブラリと見なされます(結局、実行時にこのライブラリをロードする必要があり、何度も何度も渡す必要はありません)未使用のシンボルをプルーニングする):必要なシンボルが少なくとも1つある場合、ライブラリ全体が「リンク」されます(実際には実行時にリンクは行われません。これは一種のドライランです)。破棄され、二度と見られません。
たとえば、次とリンクする場合:
gcc -L/path -lpython3.x <other libs> foo.o
python3.x
が共有ライブラリであるか静的ライブラリであるかに関係なく、問題が発生します。リンカがそれを見ると、シンボルmain
のみを探しますが、このシンボルはPythonで定義されていません-lib。したがって、python-libは破棄され、再度参照されることはありません。リンカがオブジェクトファイルfoo.o
を検出した場合にのみ、Pythonシンボル全体が必要であることを認識しますが、今ではすでに手遅れです。
この問題を処理する簡単なルールがあります:オブジェクトファイルを最初に置く!つまり:
gcc -L/path foo.o -lpython3.x <other libs>
これで、リンカは、最初に表示されたときに、python-libから必要なものを認識します。
同様の結果を達成する方法は他にもあります。
A)スイープごとに少なくとも1つの新しいシンボル定義が追加されている限り、リンカーがアーカイブのグループを繰り返すようにします。
gcc -L/path --Wl,-start-group -lpython3.x <other libs> foo.o -Wl,-end-group
リンカオプション-Wl,-start-group
および-Wl,-end-group
は、このアーカイブのグループでリンカを複数回反復するように指示しているため、リンカはシンボルを含める2回目(またはそれ以上)のチャンスがあります。このオプションにより、リンケージ時間が長くなる可能性があります。
B)オプション--no-as-needed
をオンにすると、このライブラリで定義されたシンボルが必要かどうかに関係なく、共有ライブラリ(および共有ライブラリのみ)がリンクされます。
gcc -L/path -Wl,-no-as-needed -lpython3.x -Wl,-as-needed <other libs> foo.o
実際には、デフォルトのld-behaviorは--no-as-needed
ですが、gcc-frontendはオプション--as-needed
でldを呼び出すため、python-libraryの前に-no-as-needed
を追加してから動作を復元できます。再びオフにします。
次に、静的リンクの問題について説明します。すべての標準ライブラリの静的バージョン(すべてglibcより上)を使用することはお勧めできません。おそらく、python-libraryのみを静的にリンクする必要があります。
リンケージのルールは簡単です。デフォルトでは、リンカーは静的バージョンよりも先に共有バージョンのライブラリを開こうとします。つまりライブラリlibmylib
およびパスA
およびB
の場合、つまり.
-L/A -L/B lmylib
次の順序でライブラリを開こうとします。
A/libmylib.so
A/libmylib.a
B/libmylib.so
B/libmylib.a
したがって、フォルダーA
に静的バージョンのみがある場合、この静的バージョンが使用されます(フォルダーB
に共有バージョンがあるかどうかは関係ありません)。
どのライブラリが実際に使用されるかは非常に不透明であるため、システムのセットアップに依存します。通常、-Wl,-verbose
を介してリンカーのログをオンにしてトラブルシューティングを行います。
オプション-Bstatic
を使用すると、ライブラリの静的バージョンの使用を強制できます。
gcc foo.o -L/path -Wl,-Bstatic -lpython3.x -Wl,-Bdynamic <other libs> -Wl,-verbose -o foo
注目すべきこと:
foo.o
はライブラリの前にリンクされます。そしていま:
gcc <cflags> L/paths foo.c -Wl,-Bstatic -lpython3.X -Wl,-Bdynamic <other libs> -o foo -Wl,-verbose
...
attempt to open path/libpython3.6m.a succeeded
...
ldd foo shows no dependency on python-lib
./foo
It works!
はい、静的glibc
にリンクする場合(お勧めしません)、コマンドラインから-Xlinker -export-dynamic
を削除する必要があります。
-Xlinker -export-dynamic
なしでコンパイルされた実行可能ファイルは、ldopen
でロードされる実行可能ファイルのこのプロパティに依存するc-extensionの一部をロードできません。