多くの静的ライブラリ(a_1-a_n)に依存する小さなコードがあります。そのコードを静的ライブラリにパッケージ化し、他の人が利用できるようにしたいと思います。
私の静的ライブラリ、それをXと呼べばうまくコンパイルできます。
Xの関数を使用する簡単なサンプルプログラムを作成しましたが、Xにリンクしようとすると、ライブラリa_1-a_nから欠落しているシンボルに関する多くのエラーが発生します。
XとX(a_1-a_nから選択したビット)に必要なすべての機能を含む新しい静的ライブラリYを作成して、プログラムをリンクする人々にYだけを配布できるようにする方法はありますか?
更新:
arですべてをダンプし、1つのmega-libを作成することだけを見てきましたが、最終的には不要な多くのシンボルが含まれます(すべての.oファイルは約700 MBですが、静的にリンクされた実行可能ファイルは7 MBです)。実際に必要なものだけを含める良い方法はありますか?
これは、 複数のC/C++ライブラリを1つに結合する方法 と密接に関連しています。
静的ライブラリは、他の静的ライブラリとリンクしません。これを行う唯一の方法は、ライブラリアン/アーカイバツール(Linuxではarなど)を使用して、複数のライブラリを連結して単一の新しい静的ライブラリを作成することです。
編集:更新に応じて、必要なシンボルのみを選択する唯一の方法は、それらを含む.oファイルのサブセットから手動でライブラリを作成することです。これは難しく、時間がかかり、エラーが発生しやすくなります。これを支援するツールは存在しませんが(存在しないとは言いませんが)、それを作成するのは非常に興味深いプロジェクトになります。
Visual Studioを使用している場合、はい、できます。
Visual Studioに付属のライブラリビルダーツールを使用すると、コマンドラインでライブラリを結合できます。ただし、ビジュアルエディターでこれを行う方法はわかりません。
lib.exe /OUT:compositelib.lib lib1.lib lib2.lib
LinuxまたはMingWで、GNUツールチェーンを使用:
ar -M <<EOM
CREATE libab.a
ADDLIB liba.a
ADDLIB libb.a
SAVE
END
EOM
ranlib libab.a
liba.a
とlibb.a
を削除しない場合、「シンアーカイブ」を作成できます。
ar crsT libab.a liba.a libb.a
Windowsで、MSVCツールチェーンを使用:
lib.exe /OUT:libab.lib liba.lib libb.lib
静的ライブラリは、.o
オブジェクトファイルの単なるアーカイブです。それらをar
(Unixを想定)で抽出し、1つの大きなライブラリにパックします。
プロジェクトプロパティのLink Library Dependencies
の代わりに、Visual Studioでライブラリをリンクする別の方法があります。
Add Existing Item...
)。Item Type
がLibrary
であることを確認しますこれには、実行したかのようにXの他のライブラリが含まれます
lib /out:X.lib X.lib other1.lib other2.lib
残りを読む前に注意してください:ここに示されているシェルスクリプトは、使用するのが安全ではなく、十分にテストされていることは確かです。自己責任!
そのタスクを達成するために、bashスクリプトを作成しました。ライブラリがlib1であり、いくつかのシンボルを含める必要があるライブラリがlib2であるとします。スクリプトはループ内で実行され、lib1の未定義のシンボルがlib2で見つかるかどうかを最初にチェックします。次に、ar
を使用してlib2から対応するオブジェクトファイルを抽出し、それらの名前を少し変更して、lib1に配置します。 lib2からインクルードしたものには、まだ含まれていないlib2からの他のものが必要なため、ループが再び実行される必要があるため、より多くの欠落シンボルが存在する可能性があります。ループのいくつかのパス後に変更がなくなった場合、つまりlib2のオブジェクトファイルがlib1に追加されなかった場合、ループは停止します。
含まれているシンボルはnm
によって未定義として報告されるため、ループを停止できるかどうかを判断するために、lib1自体に追加されたオブジェクトファイルを追跡しています。
#! /bin/bash
lib1="$1"
lib2="$2"
if [ ! -e $lib1.backup ]; then
echo backing up
cp $lib1 $lib1.backup
fi
remove_later=""
new_tmp_file() {
file=$(mktemp)
remove_later="$remove_later $file"
eval $1=$file
}
remove_tmp_files() {
rm $remove_later
}
trap remove_tmp_files EXIT
find_symbols() {
nm $1 $2 | cut -c20- | sort | uniq
}
new_tmp_file lib2symbols
new_tmp_file currsymbols
nm $lib2 -s --defined-only > $lib2symbols
prefix="xyz_import_"
pass=0
while true; do
((pass++))
echo "Starting pass #$pass"
curr=$lib1
find_symbols $curr "--undefined-only" > $currsymbols
changed=0
for sym in $(cat $currsymbols); do
for obj in $(egrep "^$sym in .*\.o" $lib2symbols | cut -d" " -f3); do
echo " Found $sym in $obj."
if [ -e "$prefix$obj" ]; then continue; fi
echo " -> Adding $obj to $lib1"
ar x $lib2 $obj
mv $obj "$prefix$obj"
ar -r -s $lib1 "$prefix$obj"
remove_later="$remove_later $prefix$obj"
((changed=changed+1))
done
done
echo "Found $changed changes in pass #$pass"
if [[ $changed == 0 ]]; then break; fi
done
そのスクリプトにlibcomp
という名前を付けたので、次に呼び出すことができます。と
./libcomp libmylib.a libwhatever.a
libwhateverは、シンボルを含める場所です。ただし、最初にすべてを別のディレクトリにコピーするのが最も安全だと思います。私は自分のスクリプトをそれほど信用しません(ただし、私にとってはうまくいきました;それを使って数値ライブラリにlibgsl.aを含めて、その-lgslコンパイラスイッチを省略できます)。