私は naty という 1 つのプログラムをコンパイルしています。このプログラムは、標準の GNU C ライブラリの一部でもある正規関数名 getline を使用します。
このプログラムで定義された関数を使用するようにコンパイル時に GCC に指示することは可能ですか?
私は naty という 1 つのプログラムをコンパイルしています。このプログラムは、標準の GNU C ライブラリの一部でもある正規関数名 getline を使用します。
このプログラムで定義された関数を使用するようにコンパイル時に GCC に指示することは可能ですか?
1 つの解決策:
.h
これで、次のようなアプリケーション ファイルで関数の宣言ができました。
int getline(...); // the custon getline
それを次のように変更します。
int application_getline(...); // the custon getline
#define getline application_getline
そうすべきだと思います。.c
また、そのファイルが含まれていると仮定して、関数が定義されているファイルも修正し.h
ます。
また、grep
エディターの「ファイル内を検索」を使用して、そのマクロが有効になるすべての場所で問題が発生しないことを確認してください。
重要: すべてのファイルで、シンボルを使用する可能性のある標準ヘッダーの後.h
にファイルが含まれていることを確認してください。そのマクロをそれらで有効にしたくない...getline
注: これは醜いハックです。繰り返しになりますが、C プリプロセッサ マクロに関連するほとんどすべてのものは、いくつかの基準によっては醜いハックと見なすことができます ;)。繰り返しになりますが、既存の互換性のないコード ベースを連携させて連携させることは、特に長期的なメンテナンスが問題にならない場合は、ハッキングが許容される場合がよくあります。
注2:この回答とコメントで指摘されているように、これはC標準では未定義の動作です。ソフトウェアをより長く維持することが意図されている場合は、一度だけ動作する実行可能バイナリを取得することを念頭に置いてください。しかし、より良い解決策を追加しました。
getline
標準が定義されている GCC ヘッダーが実際にコードで使用されている場合、未定義の動作をトリガーする可能性があることに注意してください。これらは関連する情報源です(強調鉱山):
libcマニュアル:
1.3.3 予約名
ISO C 標準に由来するすべてのライブラリ タイプ、マクロ、変数、および関数の名前は、無条件に予約されています。プログラムでこれらの名前を再定義することはできません。他のすべてのライブラリ名は、それらを定義または宣言するヘッダー ファイルがプログラムに明示的に含まれている場合は予約されています。これらの制限にはいくつかの理由があります。
[...]
および C99 ドラフト標準 (N1256):
7.1.3 予約済み識別子
1
各ヘッダーは、関連する副次節にリストされているすべての識別子を宣言または定義し、オプションで、関連する将来のライブラリ指示の副次節にリストされている識別子と、任意の使用またはファイルスコープ識別子として使用するために常に予約されている識別子を宣言または定義します。
[...]
2
他の識別子は予約されていません。プログラムが予約されているコンテキストで識別子を宣言または定義する場合 (7.1.4 で許可されている場合を除く)、または予約された識別子をマクロ名として定義する場合、動作は未定義です。
3
プログラムが上記の最初のグループの識別子のマクロ定義を (#undef で) 削除した場合、動作は未定義です。
したがって、コードにヘッダーを含めると、別の投稿で提案されているマクロ トリックでさえ、未定義の動作を引き起こしgetline
ます。
getline
残念ながら、この場合の唯一の安全策は、すべての呼び出しの名前を手動で変更することです。
C では、一意の関数名が要求されます。-fno-builtin または -ffreestanding gcc フラグを使用できます。gcc の man ページで、このフラグに関する説明を参照してください。
この標準準拠の問題に悩まされ始めたので、少し実験してみました。これは、現在受け入れられている私の回答よりも優れている可能性があります。
まず、解決策:
これをコンパイラのコマンドラインオプションに追加して、_XOPEN_SOURCE
valueでマクロを定義するだけです699
-D_XOPEN_SOURCE=699
正確には、アプリケーションのビルド システムによって異なりますが、おそらく有効な方法の 1 つは、CFLAGS 環境変数を定義し、再構築時に有効になるかどうかを確認することです。
export CFLAGS="-D_XOPEN_SOURCE=699"
難解なビルドシステムを使用していて、コンパイルオプションに追加できない場合に備えて、アプリケーションの#define _XOPEN_SOURCE 699
すべてのファイルにインクルードする前に追加することもできますが、コマンドラインから実行する方がはるかに望ましいです。.c
次に、いくつかの説明:
getline の man ページはgetline
、 if などの特定の基準の下でのみ定義されることを指定します_XOPEN_SOURCE>=700
。そのため、関連するファイルを含める前に小さい値を定義することで、ライブラリ宣言を除外します。これらの機能テスト マクロの詳細については、GNU libc manual を参照してください。
リンカーの問題もいくつかあると予想していましたが、そうではなかったので、調査の結果、この質問がここにありました。要約すると、リンカはリンクされたオブジェクト ファイルからのシンボルを (少なくともgccで) 優先し、それ以外のシンボルが見つからない場合にのみ動的ライブラリを調べます。したがって、はISO C シンボルでgetline
はないため、この回答で引用されている GNU libc ドキュメントは、この回答のトリックを使用した後_XOPEN_SOURCE
、アプリケーションで使用しても問題ないことを暗示しているようです。それでも、 POSIXを使用してアプリケーションの関数を呼び出してしまう他のライブラリに注意してください(おそらく異なるパラメーターを使用して、未定義の動作を引き起こし、おそらくクラッシュします)。getline
一般的なアプローチは、ある種の名前空間を形成するプレフィックスを使用することです。名前空間名を簡単に変更できるようにするために、これに使用されるマクロが表示されることがあります。
#define MYAPP(f) myapp_##f
次に、次のように使用されます
int MYAPP(add)(int a, int b) {
return a + b;
}
myapp_add
これは、次のように呼び出すこともできる関数を定義します
MYAPP(add)(3, 5);
これがあなたの問題に対するきちんとした解決策です。トリックは LD_PRELOAD です。質問投稿の 1 つで同様のことを行いました。以下を参照してください。 ライブラリの標準関数をハックし、その後ネイティブ ライブラリ関数を呼び出す
別のファイルで getline() を定義できます。これでデザインもすっきりします。次に、その c ファイルをコンパイルします。
$gcc -c -g -fPIC <file.c>
. これにより、ファイル .o が作成されます。次に、その共有オブジェクトを作成します。-g デバッグ用。-位置に依存しないコードの fPIC。これにより、RAM サイズを節約できます。-fPIC オプションを指定すると、テキスト セグメントが共有されます。
$gcc -shared libfile.so file.o
次に、メイン ファイルをこの共有オブジェクトにリンクします。
実行中に LD_PRELOAD を使用すると、ネイティブ API の代わりにライブラリが使用されます。
$LD_PRELOAD=<path to libfile.so>/libfile.so ./main.out
私の答えが気に入ったら、よろしくお願いします。以前の投稿で、ライブラリ内の標準関数をハックし、後でネイティブライブラリ関数を呼び出すという同様の種類のことを行いまし た。