web-dev-qa-db-ja.com

共有ライブラリを構築するための「soname」オプションとは何ですか?

Program Library HOWTO)」を学びました。 sonameを使用して、次のようにバージョンを管理することに言及しています。

gcc -shared -fPIC -Wl,-soname,libfoo.so.1  -o libfoo.so.1.0.0 foo.c
ln -s libfoo.so.1.0.0  libfoo.so.1
ln -s libfoo.so.1 libfoo.so

そして、sonameが設定されていないという情報を取得します。 libfoo.so.1.0.0と等しくなります。 here からの回答を参照してください。

そして、次のようにsonameなしでも動作することがわかります

 gcc -shared -fPIC -o libfoo.so.1.0.0 foo.c
 ln -s libfoo.so.1.0.0  libfoo.so.1
 ln -s libfoo.so.1 libfoo.so

そのため、readelf -d libfoo.soコマンドを使用してチェックするときに、sonameオプションが共有ライブラリのバージョンを通知できることが唯一の有用なポイントだと思います。

他に何ができますか?

48
Samuel

sonameは、ライブラリがサポートするバイナリAPIの互換性を示すために使用されます。

SONAMEは、コンパイル時にリンカーによって使用され、ライブラリファイルから実際のターゲットライブラリのバージョンを判別します。 gcc -l NAMEはlib NAME。soリンクまたはファイルを探してから、より具体的になるSONAMEをキャプチャします(ex libnuke.so SONAME libnukeを含むlibnuke.so.0.1.4へのリンク) .so.0)。

実行時にリンクされ、これがELF動的セクションNEEDEDに設定され、この名前のライブラリ(またはそのリンク)が存在するはずです。実行時にはSONAMEは無視されるため、リンクまたはファイルの存在だけで十分です。

注:SONAMEは、実行時ではなく、リンク/ビルド時にのみ適用されます。

ライブラリの「SONAME」は「objdump -p file | grep SONAME」で確認できます。バイナリの「必要」は、「objdump -p file | grep NEEDED」で確認できます。

[編集]警告以下は一般的な意見であり、Linuxにデプロイされたものではありません。最後に参照してください。

Libnuke.so.1.2という名前のライブラリがあり、新しいlibnukeライブラリを開発するとします。

  • 新しいライブラリが以前のAPIの変更なしの修正である場合は、同じsonameをそのままにして、ファイル名のバージョンを増やす必要があります。つまり、ファイルはlibnuke.so.1.2.1になりますが、sonameは引き続きlibnuke.so.1.2になります。
  • 新しい関数を追加しただけで、機能を壊さず、以前と互換性のある新しいライブラリがある場合は、以前と同じsonameに加えて、1。つまり、ファイルとsonameはlibnuke.so.1.2.1になります。 libnuke.1.2にリンクされたプログラムは、それでも引き続き機能します。 libnuke.1.2.1とリンクされた新しいプログラムは、そのプログラムでのみ動作します(新しいSubversionがlibnuke.1.2.1.1のようになるまで)。
  • 新しいライブラリがlibnukeと互換性がない場合:libnuke.so.2
  • 新しいライブラリがベア古いバージョンと互換性がある場合:libnuke.so.1.3 [つまり、libnuke.so.1と互換性があります]

[編集]完了:Linuxケース。

Linuxの実生活では、SONAMEを特定の形式として:lib [NAME] [API-VERSION] .so。[major-version] major-versionは、メジャーライブラリが変更されるたびに増加する1つの整数値です。 API-VERSIONはデフォルトでは空です

ex libnuke.so.0

次に、実際のファイル名には、マイナーバージョンとサブバージョンexが含まれます:libnuke.so.0.1.5

ファイルの名前を変更すると動作が変わるため、sonameを指定しないことは悪い習慣だと思います。

49
philippe lhardy

LibA.soがlibB.soに依存しており、それらがすべてディレクトリ内にあると仮定しましょう(もちろん、ディレクトリは動的リンカーによって見つけることができません)。 sonameを設定しなかった場合、dlopenは機能しません。

auto pB = dlopen("./libB.so", RTLD_LAZY | RTLD_GLOBAL);
auto pA = dlopen("./libA.so", RTLD_LAZY | RTLD_GLOBAL);

実行時リンカーはlibB.soを見つけることができないため、pANULLに設定されます。

この場合、sonameはあなたを地獄から救います...

2
Lw Cui

Johann Klasekの答え をサポートする例を次に示します。

つまり、実行時にSONAMEが必要です。コンパイル時には、リンカー名または実名のみが必要です(例:g++ main.cpp -L. -laddまたはg++ main.cpp -L. -l:libadd.so.1.1)。リンカ名と実名の定義は Program Library HOWTO:3. Shared Libraries に従います。

ソースツリー:

├── add.cpp
├── add.h
├── main.cpp
└── Makefile

メイクファイル:

SOURCE_FILE=add.cpp
# main.cpp includes `add.h`, whose implementation is `add.cpp`
MAIN_FILE=main.cpp
SONAME=libadd.so.1
REAL_NAME=libadd.so.1.1
LINKER_NAME=libadd.so
OUTPUT_FILE=a.out

all:
   g++ -shared -fPIC -Wl,-soname,${SONAME} -o ${REAL_NAME} ${SOURCE_FILE}
   ln -s ${REAL_NAME} ${LINKER_NAME}
   g++ main.cpp -I. -L. -ladd -o ${OUTPUT_FILE} 
   # Same as `ldconfig -n .`, creates a symbolic link
   ln -s ${REAL_NAME} ${SONAME}
   #./a.out: error while loading shared libraries: libadd.so.1: cannot open 
   # shared object file: No such file or directory
   LD_LIBRARY_PATH=. ./${OUTPUT_FILE}
clean:
   rm ${SONAME} ${REAL_NAME} ${LINKER_NAME} ${OUTPUT_FILE}
2
BugKiller

命名規則libname。{a}。{b}。{c}にlibx.1.0.0という名前の動的ライブラリを作成しました

{a} stand for primary version, should changes when APIs changes(which making things incompatible).
{b} stand for sub version, should changes by adding APIs.
{c} stand for mirror version, should changes by bug fixing or optimizing

これでlibx.1.2.0がリリースされます。関数を追加するだけで、人々の実行可能ファイルがクラッシュしないため、libx.1.2.0がlibx.1.0.0と互換性があることを宣言する必要があります。

Libx.1.0.0とlibx.1.2.0を同じsonameに設定する(例:libx.1)

これがsonameの機能です。

2
igonejack

別の側面:少なくともLinuxでは、SONAMEエントリは、/ lib、/ lib64などに適切なリンクを作成する方法に関するランタイムリンカーシステムのヒントを提供します。コマンドldconfigを実行すると、SONAMEという名前のシンボリックリンクが作成されます実行時リンカーキャッシュに。同じSONAMEをタグ付けするライブラリの最新のものがリンク競合に勝ちます。一部のソフトウェアが特定のSONAMEに依存しており、ライブラリを更新する場合は、このSONAMEを指定して、この新しいライブラリにldconfigスティックを取得する必要があります(ldconfigを使用してキャッシュとリンクを再構築する場合)。例えば。 libssl.so.6とlibcrypto.so.6はそのような場合です。

0
Johann Klasek