gcc will not properly include math.h
Asked Answered
O

2

31

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?

Ouster answered 4/7, 2012 at 23:56 Comment(11)
This code compiles and links fine for me with GCC 4.1.2 and 4.3.4...Palpitation
@OliCharlesworth I literally copy pasted all of it, and it obviously does not work for meOuster
@OliCharlesworth Is it possible math.h is not being included?Ouster
This is a linker error message, not a compiler error message. So the #include is fine.Palpitation
Can you try nm /usr/lib/libm.a | grep fmod (may need to substitute /lib64/ in place of /lib/), to check that the library really does contain an fmod symbol?Palpitation
Works for me too w/ gcc 4.4.3. Try moving -lm to the end of the command & check that /usr/lib/libm.so exists on your machineHooch
@ScottWales And Bingo was his name! Just moving it to the end did the trick. Put it as an answer and I will accept it (make sure to make it verbose and include historical context)Ouster
Wow, is this a bug? Order of parameters should not matter in this case…Waylin
@ckruse: See comments to the answer here: https://mcmap.net/q/66538/-c-math-linker-problems-on-ubuntu-11-10-duplicate.Palpitation
possible duplicate of Undefined reference to sin in CPlath
Your code did compile. It just failed to link.Plath
H
68

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
Hooch answered 5/7, 2012 at 0:24 Comment(3)
A very nice explanation of linkage process, but the bottom line is vague. Are you saying that the change from -lm test.o to test.o -lm solves the problem (and therefore, he should change gcc -lm test.c -o test to gcc test.c -lm -o test)?Recidivism
Yes. Unless you have a specific reason to need otherwise, libraries always belong at the end of your link command line. And they belong in dependency order, i.e. if A depends on B, B must always come after A on the command line.Nard
Nice answer, I never knew of "nm".Endarch
A
4

From the gcc(1) manpage: "the placement of the -l option is significant."

Specifically:

   -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.
Achates answered 6/7, 2015 at 14:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.