共有ライブラリ内の未解決のシンボルを簡単にチェックできますか?
-
06-07-2019 - |
質問
かなり大きなC ++共有オブジェクトライブラリを書いていますが、デバッグが苦痛になる小さな問題にぶつかりました:
ヘッダーファイルで関数/メソッドを定義し、そのスタブを作成するのを忘れた場合(開発中)、実行可能ファイルではなく共有オブジェクトライブラリとしてビルドしているため、コンパイル時に通知する際にエラーは表示されません私はその機能を実装するのを忘れました。何かがおかしいとわかる唯一の方法は、実行時に、最終的にこのライブラリにリンクするアプリケーションが「未定義のシンボル」エラーで倒れるときです。
コンパイル時に必要なすべてのシンボルがあるかどうかを確認する簡単な方法を探しています。おそらく、Makefileに追加できるものです。
私が思いついた解決策の1つは、コンパイルされたライブラリを nm -C -U
で実行して、すべての未定義の参照のデマングルリストを取得することです。問題は、これがGLibCなどの他のライブラリ内にあるすべての参照のリストにもなることです。もちろん、最終アプリケーションが組み立てられると、このライブラリとともにリンクされます。すべてのヘッダーファイルで nm
から grep
への出力を使用して、対応する名前があるかどうかを確認することもできます。確かにこれは珍しい問題ではなく、それを解決するより良い方法がありますか?
解決
リンカーオプション -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
他のヒント
Linux(使用しているように見える) ldd -r a.out
では、探している答えを正確に表示できます。
UPDATE:確認する a.out
を作成する簡単な方法:
echo "int main() { return 0; }" | g++ -xc++ - ./libMySharedLib.so
ldd -r ./a.out
テストスイートはどうですか?必要なシンボルにリンクする模擬実行可能ファイルを作成します。リンクに失敗した場合、ライブラリインターフェイスが不完全であることを意味します。
同じ問題が一度発生しました。私はC ++でコンポーネントモデルを開発していましたが、もちろん、コンポーネントは実行時に動的にロードする必要があります。 3つの解決策が思い浮かびます。それが私が適用したものです。
- 時間をかけて、静的にコンパイルできるビルドシステムを定義します。エンジニアリングの時間はいくらか減りますが、これらの迷惑なランタイムエラーをキャッチする時間を大幅に節約できます。
- 関数をよく知られたセクションでグループ化し、関数/スタブをグループ化して、対応する各関数にスタブがあることを確認できます。文書化に時間をかければ、おそらく定義をチェックするスクリプト(たとえば、doxygenコメントを使用して)を作成し、対応する.cppファイルをチェックできます。
- 同じライブラリセットをロードする複数のテスト実行ファイルを実行し、RTLD_NOWフラグをdlopenに指定します(* NIXを使用している場合)。不足しているシンボルを通知します。
役立つこと。