2012-07-04 10 views
16

He aquí un ejemplo mínimo delineando mi problemagcc no incluirá adecuadamente math.h

test.c:

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

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

Y aquí es el comando estoy emitiendo para compilar test.c

gcc -lm test.c -o test 

Y aquí está la salida que obtengo cuando publico el comando anterior

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

Obtengo la misma salida si en cambio uso cc. Estoy usando la siguiente versión de gcc

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

¿Alguna idea de por qué mi programa no se compila?

+0

Este código se compila y enlaza bien para mí con GCC 4.1.2 y 4.3.4 ... –

+0

@OliCharlesworth literalmente copia pegada todos de la misma, y, obviamente, no funciona para mí – puk

+0

@OliCharlesworth ¿Es posible que math.h no esté incluido? – puk

Respuesta

46

El problema proviene del enlazador, ld, en lugar de gcc (de ahí el mensaje de estado de salida). En general, ld requiere que los objetos y las bibliotecas se especifiquen en el orden usersupplier, donde user es un objeto que utiliza una función de biblioteca y supplier es el objeto que lo proporciona.

Cuando su test.c se compila a un objeto el compilador establece que HOQF es una referencia indefinida

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

(nm enumera todas las funciones mencionadas mediante un fichero objeto)

El enlazador cambia el indefinido referencias a las definidas, buscando las referencias para ver si se suministran en otros archivos.

$ 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 [email protected]@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 [email protected]@GLIBC_2.2.5 
0000000000400550 t frame_dummy 
0000000000400574 T main 

La mayoría de estos se refieren a las funciones libc que se ejecutan antes y después de main para configurar el entorno. Puede ver que fmod ahora apunta a glibc, donde será resuelto por el sistema de biblioteca compartida.

Mi sistema está configurado para usar bibliotecas compartidas de forma predeterminada. Si en lugar fuerzo vinculación estática Me da la orden de dependencia se ve

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

Poner -lm más tarde en el comando enlazador, después test.o, que permite enlazar con éxito. Comprobación del HOQF símbolos ahora debe resolverse a una dirección real, y de hecho lo es

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

Una muy buena explicación del proceso de vinculación, pero la conclusión es vaga. ¿Estás diciendo que el cambio de '-lm test.o' a' test.o -lm' resuelve el problema (y por lo tanto, debe cambiar 'gcc -lm test.c -o test' a' gcc test.c - lm -o test')? – ugoren

+7

Sí. A menos que tenga una razón específica para necesitar lo contrario, las bibliotecas ** siempre pertenecen al final ** de su línea de comandos de enlace. Y pertenecen al orden de dependencia, es decir, si A depende de B, B siempre debe aparecer después de A en la línea de comando. –

+0

Buena respuesta, nunca supe de "nm". –

2

Desde el gcc (1) página de manual: "la colocación de la opción -l es significativo."

Específicamente:

-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. 
Cuestiones relacionadas