Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

gcc will not properly include math.h

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?

like image 678
puk Avatar asked Jul 04 '12 23:07

puk


People also ask

Does gcc include math H?

h.

How does gcc link to math library in C?

To link in these libraries, use -lname. For example, the math library is in the file /usr/lib/libm.so (and the static version of the library is in /usr/lib/libm. a). To link the math library into your program you include -lm on the gcc command line (as in the example above).

What is LIBM A?

Description. The alternate math library, `libm. a', originally written by Cygnus support, provides versions of mathematical functions which comply to several different standards of behavior in abnormal cases, and are sometimes more accurate than those included in the default `libc.


2 Answers

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 
like image 182
Scott Wales Avatar answered Oct 13 '22 00:10

Scott Wales


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. 
like image 41
Toybuilder Avatar answered Oct 13 '22 00:10

Toybuilder