web-dev-qa-db-ja.com

gccはmath.hを適切にインクルードしません

ここに私の問題を概説する最小限の例があります

test.c:

#include <stdio.h>
#include <math.h>

main ()
{
   fmod ( 3, 2 );
}

そして、これはコンパイルするために発行しているコマンドですtest.c

gcc -lm test.c -o test

そして、これは上記のコマンドを発行したときに得られる出力です

/tmp/ccQmRk99.o: In function `main':
test.c:(.text+0x3e): undefined reference to `fmod'
collect2: ld returned 1 exit status

代わりにccを使用すると、同じ出力が得られます。次のバージョンのgccを使用しています

gcc-4.6.real (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1

プログラムがコンパイルされない理由はありますか?

19
puk

問題は、gccではなく、リンカldから発生しています(そのため、終了ステータスメッセージ)。一般に、ldはオブジェクトとライブラリをusersupplierの順序で指定する必要があります。ここで、userはライブラリ関数を使用するオブジェクトであり、supplierはそれを提供するオブジェクト。

test.cは、コンパイラがfmodが未定義の参照であることを示すオブジェクトにコンパイルされます。

$ gcc -c test.c
$ nm test.o
                 U fmod
0000000000000000 T main

(nmは、オブジェクトファイルによって参照されるすべての関数をリストします)

リンカは未定義の参照を定義済みの参照に変更し、参照を検索してそれらが他のファイルで提供されているかどうかを確認します。

$ gcc -lm test.o
$ nm a.out
0000000000600e30 d _DYNAMIC
0000000000600fe8 d _GLOBAL_OFFSET_TABLE_
00000000004006a8 R _IO_stdin_used
                 w _Jv_RegisterClasses
0000000000600e10 d __CTOR_END__
...
0000000000601018 D __dso_handle
                 w __gmon_start__
...
                 U __libc_start_main@@GLIBC_2.2.5
0000000000601020 A _edata
0000000000601030 A _end
0000000000400698 T _fini
0000000000400448 T _init
0000000000400490 T _start
00000000004004bc t call_gmon_start
0000000000601020 b completed.7382
0000000000601010 W data_start
0000000000601028 b dtor_idx.7384
                 U fmod@@GLIBC_2.2.5
0000000000400550 t frame_dummy
0000000000400574 T main

これらのほとんどは、環境を設定するためにmainの前後に実行されるlibc関数を参照しています。 fmodがglibcを指していることがわかります。glibcでは、共有ライブラリシステムによって解決されます。

システムはデフォルトで共有ライブラリを使用するように設定されています。代わりに静的リンクを強制すると、表示される順序の依存関係が取得されます

$ gcc -static -lm test.o
test.o: In function `main':
test.c:(.text+0x40): undefined reference to `fmod'
collect2: ld returned 1 exit status

置く-lmリンカコマンドの後半、test.o、正常にリンクできるようにします。シンボルfmodをチェックすると、実際のアドレスに解決されるはずです。実際、

$ gcc -static test.o -lm
$ nm a.out | grep fmod
0000000000400480 T __fmod
0000000000402b80 T __ieee754_fmod
0000000000400480 W fmod
52
Scott Wales

Gcc(1)マンページから:「-lオプションの配置は重要です。」

具体的には:

   -llibrary
   -l library
       Search the library named library when linking.  (The second alternative with the library as a
       separate argument is only for POSIX compliance and is not recommended.)

       It makes a difference where in the command you write this option; the linker searches and processes
       libraries and object files in the order they are specified.  Thus, foo.o -lz bar.o searches library z
       after file foo.o but before bar.o.  If bar.o refers to functions in z, those functions may not be
       loaded.

       The linker searches a standard list of directories for the library, which is actually a file named
       liblibrary.a.  The linker then uses this file as if it had been specified precisely by name.

       The directories searched include several standard system directories plus any that you specify with
       -L.

       Normally the files found this way are library files---archive files whose members are object files.
       The linker handles an archive file by scanning through it for members which define symbols that have
       so far been referenced but not defined.  But if the file that is found is an ordinary object file, it
       is linked in the usual fashion.  The only difference between using an -l option and specifying a file
       name is that -l surrounds library with lib and .a and searches several directories.
3
Toybuilder