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


138

多くの静的ライブラリ(a_1-a_n)に依存する小さなコードがあります。そのコードを静的ライブラリにパッケージ化して、他の人が利用できるようにしたいと考えています。

私の静的ライブラリは、Xと呼んでも問題なくコンパイルされます。

Xの関数を使用する簡単なサンプルプログラムを作成しましたが、Xにリンクしようとすると、ライブラリa_1-a_nからシンボルが欠落しているという多くのエラーが発生します。

XとXに必要なすべての機能(a_1-a_nから選択されたビット)を含む新しい静的ライブラリYを作成して、プログラムをリンクする人々にYだけを配布できる方法はありますか?


更新:

私はarですべてをダンプして1つのメガライブラリを作成することだけを見てきましたが、必要のない多くのシンボルが含まれます(すべての.oファイルは約700 MBですが、静的にリンクされた実行可能ファイルは7です) MB)。実際に必要なものだけを含める良い方法はありますか?


これは、複数のC / C ++ライブラリを1つに結合する方法に密接に関連しているように見えますか?

回答:


76

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

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


こんにちはニール、質問を更新しました-必要な.oファイルのみを含める方法を知っていますか?
Jason Sundram 2010年

更新-これを実行したい場合は、前に戻って別のことを実行してください(John Knoellerが指摘している場合を除き、Visual Studioを使用しています)。私はこのアプローチに多くの時間を費やしましたが、何も役に立ちませんでした。
ジェイソンサンドラム

GNU ldツールは-r、出力をldの入力として使用できるオプションを提供します。いったんリンクすると、再配置可能ファイルを取得する必要があるため、ライブラリを代理することができます。(試してみました)。
14

49

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

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

lib.exe /OUT:compositelib.lib  lib1.lib lib2.lib

5
VS2008では、Librarian / Generalの下のcompositelibのプロジェクトプロパティで、[x] Link Library Dependenciesをオンにすると、lib1とlib2がcompositelibの依存関係である場合に、これが行われます。少しバグがあるようです。「すべての構成」ではなく、ビルド構成ごとに個別にチェックボックスを設定します。
Spike0xff 2013

2
VS2015 IDE-Librarian / Generalで「Additional Dependencies」を使用して、プロジェクトが構築しているライブラリに直接リンクされている追加のライブラリを取得しませんか?
davidbak 2016年

@davidbak私は過去数日間でこれを理解しようとしています、そしてどうやらこのオプションは時代遅れで何もしませんか?
モンタルド

20

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

知っておくと便利ですが、libb.aからのすべてを結合libに含めるため、OPの問題は実際には解決しません。libbのモジュールがいくつか必要なだけの場合は、非常に大きくなる可能性があります。
Elmar Zander

1
@ElmarZanderしかしar crsT、コピーの代わりに「シンボリックリンク」のようなことを行うを使用することができ、データのコピーを1つ送るだけで済みます。
スターブリリアント

シンアーカイブは、特にLinux上で使用されているカーネルv4.19:unix.stackexchange.com/questions/5518/...
チロSantilli郝海东冠状病六四事件法轮功

10

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


6

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

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

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

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

こんにちは、私はIntel IPPを使用していて、すべてを1つの(静的)libにラップしたい独自の関数を作成しました。しかし、libを作成してから、プロジェクトを他のコンピューターに送信すると、作成したlibだけを使用してプロジェクトをコンパイルできるようになり、インテルIPPライブラリの.hファイルが必要であるというエラーが表示されます。何か案が?
Royi 2015

通常、libファイルでは不十分です。使用する場合は、ヘッダーファイルも含める必要があります。ただし、このスレッドはリンクについて話しているため、問題はコンパイル段階にあるため、ここではトピックから外れています。
evpo 2015

OK。あなたを助けるために私はより多くの情報が必要になります。ビルド出力またはログを見て、欠落している.hファイルの問題点を確認します。cl.exeだと思います。その場合は、ヘッダーを使用するコンパイル済みの.cpp / .cc / .cファイルの名前が表示されます。その.cppファイルの名前は何で、どのプロジェクトに属していますか?
evpo 2015年

私はとても混乱しています。これを読む前は、うまくいかなかったようです(これが私のプロジェクトの構成方法です)。しかし、これを読んでプロジェクトをリセットしたので、明らかに機能しています。ゴーゴー!:(
モルダチャイ2018年

1
@Mordachai以下のこの俳句はあなたの経験を完全に説明しています:昨日はうまく
いき

5

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

私はそのタスクを達成するためにbashスクリプトを書きました。ライブラリがlib1で、いくつかのシンボルを含める必要があるのはlib2だとします。スクリプトはループで実行されるようになり、最初にlib1のどの未定義のシンボルがlib2にあるかをチェックします。次に、対応するオブジェクトファイルをlib2からで抽出しar、名前を少し変更して、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コンパイラスイッチを省略できます)。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.