26

次の状況があるとします。

  • program動的に依存するという名前のプログラムlibfoo.so
  • libfoo.soそれは何にも依存していません (まあ、それは何かに依存していますが、それはlibstdc++省略できると思います)

program完璧に動作します。

突然、コードが変更され、一部の関数が別のライブラリによって提供される関数をlibfoo内部的に使用するようになりました。func_bar()libbar.so

libfoo.soが再コンパイルされ、依存するようになりましたlibbar.soprogramは変更されず、 のみに依存しlibfoo.soます。

今私が実行するprogramと、彼が見つけることができないと不平を言いますfunc_bar()

ここに私の質問があります:

  • libfoo.soインターフェイスは変更されず、その実装のみが変更されました。と明示的にリンクするprogram必要があるのはなぜですか?libbar.so
  • 依存関係ツリーは再帰的ではありませんか? libfoo.soに依存しているためlibbar.so、再コンパイルせずに の依存関係リストにlibbar.so自動的に追加されたと思います。しかし、そうではないことを示しています。programldd program

ライブラリの依存関係が変更されるたびに、そのライブラリに依存するすべてのバイナリを再コンパイル (再リンク)しなければならないのは奇妙に思えます。これを防ぐためにここにどのような解決策がありますか?

4

5 に答える 5

18

libfoo.soに対してリンクしていない場合に問題が発生しますlibbar。実行可能ファイルをコンパイルするとき、デフォルトでは、リンカは未定義の参照を残すことを許可しません。ただし、共有ライブラリをコンパイルしているときは、リンク時にそれらが満たされることを期待しますこれは、 がそれ自体libfooによってエクスポートされた関数を使用できるようにするためprogramです。実行しようとすると、動的リンカーはfunc_bar()によって提供されることを期待していますprogram。問題は次のように示されます。

(foo.c自己完結型です)

export LD_RUN_PATH=`pwd`
gcc -Wall -shared foo.c -o libfoo.so
gcc -Wall -L. p.c -lfoo -o p

この時点で、./p期待どおりに正しく実行されます。次に、それを使用するために作成libbar.soおよび変更foo.cします。

gcc -Wall -shared bar.c -o libbar.so
gcc -Wall -shared foo.c -o libfoo.so

この時点で、./p説明したエラーが表示されます。を確認すると、依存関係がないldd libfoo.soことがわかります。これがエラーです。エラーを修正するには、正しくリンクする必要があります。libbar.solibfoo.so

gcc -Wall -L. -lbar -shared foo.c -o libfoo.so

この時点で、 は./p再び正しく実行ldd libfoo.soされ、 への依存関係が示されlibbar.soます。

于 2010-11-08T06:16:49.183 に答える
9

Fedora では、動的リンクは ld-linux.so.2 によって実行されます。動的リンカーは、/etc/ld.so.cache および /etc/ld.so.preload を使用してライブラリ ファイルを検索します。

ldconfig を実行して、libfoo が libbar を探す場所をシステムに伝えます。

ldconfig は、/lib、/usr/lib、および /etc/ld.so.conf にリストされている任意のディレクトリを調べます。プログラムがどのライブラリを使用しているかは、ldd で確認できます。

詳細については、各コマンドのマニュアル ページを参照してください。

共有ライブラリを使用したアプリケーションの例を次に示します。
プログラム.cc

#include "foo.h"
#include <iostream>

int main(int argc, char *argv[])
{
    for (int i = 0; i < argc; ++i) {
        std::cout << func_foo(argv[i]) << std::endl;
    }
}

foo.h

#ifndef FOO_H
#define FOO_H
#include <string>
std::string func_foo(std::string const &);
#endif

foo.cc

#include "foo.h"

std::string func_foo(std::string const &arg)
{
    return arg + "|" + __func__;
}

bar.h

#ifndef BAR_H
#define BAR_H
#include <string>
std::string func_bar();
#endif

bar.cc

#include "bar.h"

std::string func_bar()
{
    return __func__;
}

libfoo.so を共有ライブラリとしてビルドします。
g++ -Wall -Wextra -fPIC -shared foo.cc -o libfoo.so
g++ -lfoo -L./ -Wall -Wextra program.cc foo.h -o program
ldd program
...
libfoo.so => 見つかりません

/etc/ld.so.cache
sudo ldconfig /home/tobias/projects/stubs/so/ を 更新します

ldd は、動的リンカーが libfoo.so
ldd プログラム を見つけたことを示してい
ます ...
libfoo.so => /home/tobias/projects/stubs/so/libfoo.so (0x00007f0bb9f15000)

libfoo.so に libbar.so への呼び出しを追加
新しい foo.cc

#include "foo.h"
#include "bar.h"

std::string func_foo(std::string const &arg)
{
    return arg + "|" + __func__ + "|" + func_bar();
}

libbar.so をビルドし、libfoo.so を再ビルドします
g++ -Wall -Wextra -fPIC -shared bar.cc -o libbar.so
g++ -Wall -Wextra -fPIC -shared libbar.so foo.cc -o libfoo.so
ldd libfoo.so
...
libbar.so => 見つかりません

ldd program
...
libfoo.so => /home/tobias/projects/stubs/so/libfoo.so (0x00007f49236c7000)
libbar.so => not found
これは、ダイナミック リンカが libfoo.so をまだ見つけているが、libbar.so を見つけてい ないことを示しています。
再度 /etc/ld.so.cache を更新して再チェックします。
sudo ldconfig /home/tobias/projects/stubs/so/
ldd libfoo.so
...
libbar.so => /home/tobias/projects/stubs/so/libbar.so (0x00007f935e0bd000)

ldd プログラム
...
libfoo.so => /home/tobias/projects/stubs/so/libfoo.so (0x00007f2be4f11000)
libbar.so => /home/tobias/projects/stubs/so/libbar.so (0x00007f2be4d0e000)

libfoo.so と libbar.so の両方が見つかります。

この最後の手順は、アプリケーション プログラムに影響を与えないことに注意してください。本当に厳密な場合、ldconfig の実行は一種の再リンクです。奇妙なことに、リンカーはリンクするライブラリの依存関係を知る必要があります。これを実装するには他にも多くの方法がありますが、これが選択されました。

于 2010-11-05T17:40:34.703 に答える
2

システム情報を提供していません。glibc を使用していますか? はいの場合、このコマンドの出力は次のとおりです。

LD_DEBUG=ファイル プログラム

「共有(ELF)ライブラリの書き方」 (pdf)もチェック(glibcを使っているかどうか)

于 2010-11-05T16:29:14.463 に答える
1

プログラムはlibbar.soとリンクする必要はありません。

後で構築するときにlibbar.soの依存関係として指定しなかったことが問題の原因だと思います。libfoo.so使用しているビルドシステムはわかりませんが、CMakeでは次のように実行できます。

add_library(bar SHARED bar.c)

add_library(foo SHARED foo.c)
target_link_libraries(foo bar)

add_executable(program program.c)
target_link_libraries(program foo)

ご覧のとおり、 ( )と()のみprogramにリンクされています。foolibfoo.sofoobarlibbar.so

または、それがlibbar.so見つからない可能性があります。LD_LIBRARY_PATH環境変数でそのディレクトリへのパスを指定してみてください。

于 2010-11-05T16:34:51.703 に答える
1

bar_funcシンボルに関する何かが変更されない限り、これは当てはまりません。「nm」コマンドを使用して、プログラムと共有オブジェクトの両方のシンボルのダンプを取得します。不一致があるかどうかとその理由を確認してください。

于 2010-11-05T17:42:43.317 に答える