que programas proceso para ejecutar compilar compilador compilacion como c gcc main

programas - que es el gcc



¿Cómo se compila y ejecuta este programa C con dos funciones principales? (3)

Citando ld (1):

El vinculador buscará un archivo solo una vez, en la ubicación donde se especifica en la línea de comando. Si el archivo define un símbolo que no estaba definido en algún objeto que apareció antes del archivo en la línea de comando, el vinculador incluirá los archivos apropiados del archivo.

Al vincular 2main, el símbolo principal se resuelve antes de que ld alcance -lstatic, porque ld lo recoge de prog.o.

Al vincular 1main, tiene undefined main para cuando llega a -lstatic, por lo que busca en el archivo main.

Esta lógica solo se aplica a archivos (bibliotecas estáticas), no a objetos normales. Cuando vincula prog.o y static.o, todos los símbolos de ambos objetos se incluyen incondicionalmente, por lo que obtiene un error de definición duplicado.

Hoy, mientras trabajaba con una biblioteca personalizada, encontré un comportamiento extraño. Un código de biblioteca estática contenía una función de depuración main() . No estaba dentro de una bandera #define . Por lo tanto, está presente en la biblioteca también. Y se utiliza el enlace a otro programa que contenía el verdadero main() .
Cuando ambos están vinculados, el vinculador no arrojó un error de declaración múltiple para main() . Me preguntaba cómo podría suceder esto.

Para hacerlo simple, he creado un programa de muestra que simula el mismo comportamiento:

$ cat prog.c #include <stdio.h> int main() { printf("Main in prog.c/n"); } $ cat static.c #include <stdio.h> int main() { printf("Main in static.c/n"); } $ gcc -c static.c $ ar rcs libstatic.a static.o $ gcc prog.c -L. -lstatic -o 2main $ gcc -L. -lstatic -o 1main $ ./2main Main in prog.c $ ./1main Main in static.c

¿Cómo encuentra el binario "2main" qué main ejecutar?

Pero compilar ambos juntos da un error de declaración múltiple:

$ gcc prog.c static.o static.o: In function `main'': static.c:(.text+0x0): multiple definition of `main'' /tmp/ccrFqgkh.o:prog.c:(.text+0x0): first defined here collect2: ld returned 1 exit status

¿Alguien puede explicar este comportamiento?


Cuando vincula una biblioteca estática (.a), el vinculador solo busca en el archivo si había algún símbolo indefinido rastreado hasta ahora. De lo contrario, no mira el archivo en absoluto. Entonces, su caso 2main , nunca mira el archivo ya que no tiene símbolos indefinidos para hacer la unidad de traducción.

Si incluye una función simple en static.c :

#include <stdio.h> void fun() { printf("This is fun/n"); } int main() { printf("Main in static.c/n"); }

y llamarlo desde prog.c , entonces el enlazador se verá obligado a mirar el archivo para encontrar el símbolo fun y obtendrá el mismo error de definición principal múltiple que el enlazador encontraría el símbolo duplicado main ahora.

Cuando compila directamente los archivos de objetos (como en gcc ao bo ), el enlazador no tiene ningún papel aquí y todos los símbolos se incluyen para hacer un solo binario y obviamente hay símbolos duplicados allí.

La conclusión es que el vinculador mira el archivo solo si faltan símbolos. De lo contrario, es tan bueno como no vincular con ninguna biblioteca.


Después de que el vinculador carga cualquier archivo de objeto, busca en las bibliotecas símbolos no definidos . Si no hay ninguno, entonces no es necesario leer las bibliotecas. Dado que se ha definido main, incluso si encuentra un main en cada biblioteca, no hay razón para cargar un segundo.

Sin embargo, los enlazadores tienen comportamientos dramáticamente diferentes. Por ejemplo, si su biblioteca incluye un archivo de objeto con main () y foo (), y foo no está definido, es muy probable que obtenga un error para un símbolo main () de definición múltiple.

Los enlazadores modernos (tautológicos) omitirán símbolos globales de objetos que no se pueden alcanzar, por ejemplo, AIX. Los enlazadores de estilo antiguo como los que se encuentran en Solaris, y los sistemas Linux aún se comportan como los enlazadores Unix de la década de 1970, cargando todos los símbolos de un módulo de objeto, accesible o no. Esto puede ser una fuente de hinchazón horrible, así como tiempos de enlace excesivos.

Otra característica de los enlazadores * nix es que buscan efectivamente una biblioteca solo una vez por cada vez que aparece en la lista. Esto exige al programador que ordene las bibliotecas en la línea de comando a un enlazador o en un archivo make, además de escribir un programa. No requerir una lista ordenada de bibliotecas no es moderno. Los sistemas operativos más antiguos a menudo tenían vinculadores que buscarían en todas las bibliotecas repetidamente hasta que un pase no resolviera un símbolo.