web-dev-qa-db-ja.com

共有ライブラリ内の未解決のシンボルを簡単にチェックできますか?

私はかなり大きなC++共有オブジェクトライブラリを書いていますが、デバッグが苦痛になる小さな問題に遭遇しました:

ヘッダーファイルで関数/メソッドを定義し、そのスタブを作成するのを忘れた場合(開発中)、実行可能ファイルではなく共有オブジェクトライブラリとしてビルドしているため、コンパイル時にエラーが表示されませんその機能を実装するのを忘れました。何かがおかしいとわかる唯一の方法は、実行時に、最終的にこのライブラリにリンクするアプリケーションが「未定義のシンボル」エラーで倒れるときです。

コンパイル時に必要なすべてのシンボル、おそらくMakefileに追加できるものがあるかどうかを確認する簡単な方法を探しています。

私が思いついた解決策の1つは、コンパイル済みライブラリをnm -C -Uすべての未定義参照のデマングル化されたリストを取得します。問題は、これがGLibCなどの他のライブラリ内にあるすべての参照のリストにもなることです。もちろん、最終的なアプリケーションが組み立てられると、このライブラリとともにリンクされます。すべてのヘッダーファイルでnmからgrepへの出力を使用し、対応する名前のいずれかを確認することは可能ですが、これは異常なようです。確かにこれは珍しい問題ではなく、それを解決するより良い方法がありますか?

75
David Claridge

リンカオプション-z defs/--no-undefinedを確認してください。共有オブジェクトを作成するとき、未解決のシンボルがあるとリンクが失敗します。

Gccを使用してリンカーを呼び出す場合、コンパイラー-Wlオプションを使用して、オプションをリンカーに渡します。

gcc -shared ... -Wl,-z,defs

例として、次のファイルを検討してください。

#include <stdio.h>

void forgot_to_define(FILE *fp);

void doit(const char *filename)
{
    FILE *fp = fopen(filename, "r");
    if (fp != NULL)
    {
        forgot_to_define(fp);
        fclose(fp);
    }
}

さて、それを共有オブジェクトに組み込むと、成功します:

> gcc -shared -fPIC -o libsilly.so silly.c && echo succeeded || echo failed
succeeded

ただし、-z defsを追加すると、リンクは失敗し、不足しているシンボルについて通知されます。

> gcc -shared -fPIC -o libsilly.so silly.c -Wl,-z,defs && echo succeeded || echo failed
/tmp/cccIwwbn.o: In function `doit':
silly.c:(.text+0x2c): undefined reference to `forgot_to_define'
collect2: ld returned 1 exit status
failed
88

Linux(使用しているように見える)ldd -r a.outでは、探している答えを正確に提供する必要があります。

更新:確認するa.outを作成する簡単な方法:

 echo "int main() { return 0; }" | g++ -xc++ - ./libMySharedLib.so
 ldd -r ./a.out
14

テストスイートはどうですか?必要なシンボルにリンクする模擬実行可能ファイルを作成します。リンクに失敗した場合、ライブラリインターフェイスが不完全であることを意味します。

8
Stefano Borini

一度同じ問題がありました。私はC++でコンポーネントモデルを開発していましたが、もちろん、コンポーネントは実行時に動的にロードする必要があります。 3つのソリューションが思い浮かびますが、それが私が適用したものです。

  1. 静的にコンパイルできるビルドシステムを定義するのに時間をかけます。エンジニアリングに時間を費やすことはできませんが、これらの迷惑なランタイムエラーをキャッチする時間を大幅に節約できます。
  2. 関数をよく知られたセクションでグループ化し、関数/スタブをグループ化して、対応する各関数にスタブがあることを確認できます。文書化に時間をかければ、おそらく(doxygenコメントなどを介して)定義をチェックし、対応する.cppファイルをチェックするスクリプトを作成できます。
  3. 同じライブラリセットをロードする複数のテスト実行可能ファイルを実行し、RTLD_NOWフラグをdlopenに指定します(* NIXの場合)。それらは、欠落しているシンボルを通知します。

お役に立てば幸いです。

3
Diego Sevilla