web-dev-qa-db-ja.com

静的ライブラリを他の静的ライブラリにリンクする

多くの静的ライブラリ(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つに結合する方法 と密接に関連しています。

121
Jason Sundram

静的ライブラリは、他の静的ライブラリとリンクしません。これを行う唯一の方法は、ライブラリアン/アーカイバツール(Linuxではarなど)を使用して、複数のライブラリを連結して単一の新しい静的ライブラリを作成することです。

編集:更新に応じて、必要なシンボルのみを選択する唯一の方法は、それらを含む.oファイルのサブセットから手動でライブラリを作成することです。これは難しく、時間がかかり、エラーが発生しやすくなります。これを支援するツールは存在しませんが(存在しないとは言いませんが)、それを作成するのは非常に興味深いプロジェクトになります。

63
anon

Visual Studioを使用している場合、はい、できます。

Visual Studioに付属のライブラリビルダーツールを使用すると、コマンドラインでライブラリを結合できます。ただし、ビジュアルエディターでこれを行う方法はわかりません。

lib.exe /OUT:compositelib.lib  lib1.lib lib2.lib
42
John Knoeller

LinuxまたはMingWで、GNUツールチェーンを使用:

ar -M <<EOM
    CREATE libab.a
    ADDLIB liba.a
    ADDLIB libb.a
    SAVE
    END
EOM
ranlib libab.a

liba.alibb.aを削除しない場合、「シンアーカイブ」を作成できます。

ar crsT libab.a liba.a libb.a

Windowsで、MSVCツールチェーンを使用:

lib.exe /OUT:libab.lib liba.lib libb.lib
19
Star Brilliant

静的ライブラリは、.oオブジェクトファイルの単なるアーカイブです。それらをar(Unixを想定)で抽出し、1つの大きなライブラリにパックします。

8

プロジェクトプロパティのLink Library Dependenciesの代わりに、Visual Studioでライブラリをリンクする別の方法があります。

  1. 他のライブラリと組み合わせたいライブラリ(X)のプロジェクトを開きます。
  2. Xと組み合わせたい他のライブラリを追加します(右クリック、Add Existing Item...)。
  3. それらのプロパティに移動し、Item TypeLibraryであることを確認します

これには、実行したかのようにXの他のライブラリが含まれます

lib /out:X.lib X.lib other1.lib other2.lib
6
evpo

残りを読む前に注意してください:ここに示されているシェルスクリプトは、使用するのが安全ではなく、十分にテストされていることは確かです。自己責任!

そのタスクを達成するために、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コンパイラスイッチを省略できます)。

3
Elmar Zander