gcc will not properly include math.h

puk picture puk · Jul 5, 2012 · Viewed 69k times · Source

Here is a minimal example outlining my problem

test.c:

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

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

And here is the command I am issuing to compile test.c

gcc -lm test.c -o test

And here is the output I get when I issue the above command

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

I get the same output if instead I use cc. I am using the following version of gcc

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

Any ideas why my program won't compile?

Answer

Scott Wales picture Scott Wales · Jul 5, 2012

The problem is coming from the linker, ld, rather than gcc (hence the exit status message). In general ld requires objects and libraries to be specified in the order user supplier, where user is an object that uses a library function and supplier is the object which provides it.

When your test.c is compiled to an object the compiler states that fmod is an undefined reference

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

(nm lists all the functions referred to by an object file)

The linker changes the undefined references to defined ones, looking up the references to see if they are supplied in other files.

$ 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

Most of these refer to libc functions that are run before and after main to set the environment up. You can see that fmod now points to glibc, where it will be resolved by the shared library system.

My system is set up to use shared libraries by default. If I instead force static linking I get the order dependency you see

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

Putting -lm later in the linker command, after test.o, allows it to link successfully. Checking the symbols fmod should now be resolved to an actual address, and indeed it is

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