質問
多くの静的ライブラリ (a_1 ~ a_n) に依存する小さなコードがあります。そのコードを静的ライブラリにパッケージ化して、他の人が利用できるようにしたいと考えています。
私の静的ライブラリ (X と呼びます) は正常にコンパイルされます。
X の関数を使用する簡単なサンプル プログラムを作成しましたが、それを X にリンクしようとすると、ライブラリ a_1 ~ a_n にシンボルがないというエラーが多数発生します。
X と X に必要なすべての機能 (a_1 ~ a_n から選択されたビット) を含む新しい静的ライブラリ Y を作成して、プログラムをリンクするために Y だけを配布できるようにする方法はありますか?
アップデート:
すべてをダンプすることを検討しました あーる ただし、1 つの mega-lib を作成すると、不要なシンボルが多数含まれることになります (すべての .o ファイルは約 700 MB ですが、静的にリンクされた実行可能ファイルは 7 MB です)。実際に必要なものだけを含める良い方法はありますか?
これは密接に関連しているように見えます 複数の C/C++ ライブラリを 1 つに結合するにはどうすればよいですか?.
解決
静的ライブラリは他の静的ライブラリとリンクしません。これを行う唯一の方法は、ライブラリアン/アーカイバ ツールを使用することです (たとえば、 あーる Linux では)、複数のライブラリを連結して単一の新しい静的ライブラリを作成します。
編集: あなたの更新に応じて、必要なシンボルのみを選択する唯一の方法は、それらを含む .o ファイルのサブセットからライブラリを手動で作成することです。これは難しく、時間がかかり、エラーが発生しやすくなります。これを支援するツールを私は知りません (存在しないとは言っていません) が、それを作成できれば非常に興味深いプロジェクトになるでしょう。
他のヒント
Visual Studioを使用している場合は[はい、あなたがこれを行うことができます。
のVisual Studioに付属しているライブラリビルダツールを使用すると、コマンドラインで一緒に図書館に参加することができます。でも、私はビジュアル・エディタでこれを行うにはどのような方法を知りません。
lib.exe /OUT:compositelib.lib lib1.lib lib2.lib
、
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
MSVCツールチェーンを使用してWindows上で、
lib.exe /OUT:libab.lib liba.lib libb.lib
静的ライブラリは.o
のオブジェクトファイルの単なるアーカイブです。 ar
(Unixのを想定)でそれらを抽出し、バック一つの大きなライブラリにそれらをパックします。
あるいは、 Link Library Dependencies
プロジェクトのプロパティでは、Visual Studio でライブラリをリンクする別の方法があります。
- 他のライブラリと結合したいライブラリ(X)のプロジェクトを開きます。
- X と組み合わせたい他のライブラリを追加します (右クリック、
Add Existing Item...
). - プロパティにアクセスして確認してください
Item Type
はLibrary
これには、次のように実行した場合と同様に、X 内の他のライブラリが含まれます。
lib /out:X.lib X.lib other1.lib other2.lib
注あなたは残りの部分を読む前に:ここに示したシェルスクリプトは確かに安全に使用でき、よくテストされていません。ご自身の責任で使用してください!
私はそのタスクを達成するためにbashスクリプトを書きました。あなたのライブラリがLIB1であると仮定し、1あなたがLIB2あるから一部の記号を含める必要があります。スクリプトはLIB1からシンボルを未定義これは、最初に確認がLIB2に見出すことができるループで実行されます。その後、ar
とLIB2から対応するオブジェクトファイルを抽出し、それらを少しの名前を変更し、LIB1に入れ、それらを。あなたはLIB2から付属のものは、ループを再度実行する必要があるので、我々は、まだ含まれていないLIB2、から他のものを必要とするため、今、多くの行方不明の記号があるかもしれません。ループのいくつかのパスの後に何も変更はもう存在しない場合は、LIB1に追加LIB2から、すなわち何のオブジェクトファイルは、ループが停止することはできません。
注、私はLIB1に追加されたオブジェクト・ファイルの追跡をしていますので、自分自身は、順番にループを停止させることができるかどうかを判断するために、nm
によって未定義として含まシンボルはまだ報告されていること。
#! /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コンパイラスイッチことを残すことができる)そんなに私のスクリプトを信頼しないでしょう。