Imprimir

Manual de C/C++ en Linux: El compilador GCC

Vamos a ver el proceso de compilación de hello.c, que consta de cuatro pasos. Partimos de un archivo de texto con el código fuente (.c):

$ ls -l hello.c
-rw-r--r--  1 francis francis  102 2007-09-16 13:10 hello.c
  1. Preprocesado: el preprocesador traduce las llamadas directivas de preprocesador: quita los comentarios, inserta el contenido de los archivos incluidos con #include y sustituye por su valor las constantes definidas con #define.
    • Comando:
      $ gcc -E hello.c > hello.pp
    • Salida: código fuente preprocesado (.pp)
      $ ls -l hello.pp
      -rw-r--r--  1 francis francis 17873 2007-09-16 13:11 hello.pp
  2. Compilado propiamente dicho: el compilador traduce el código fuente al ensamblador propio del procesador de nuestra máquina.
    • Comando (realiza los pasos 1 y 2):
      $ gcc -S hello.c
    • Salida: ensamblador (.s)
      $ ls -l hello.s
      -rw-r--r--  1 francis francis   455 2007-09-16 13:12 hello.s
  3. Ensamblado: el ensamblador crea el código objeto, que es lenguaje máquina entendible por el procesador.
    • Comando (realiza los pasos 1, 2 y 3):
      $ gcc -c hello.c
    • Salida: código objeto (.o)
      $ ls -l hello.o
      -rw-r--r--  1 francis francis   884 2007-09-16 13:12 hello.o
  4. Enlazado: aunque el código objeto (.o) es comprensible para el ordenador (ya que es binario) no puede ser ejecutado porque que no está enlazado: es necesario combinarlo con las librerías y crear un archivo ejecutable. Esta tarea es el enlazado y la realiza el enlazador.
    • Comando (realiza los pasos 1, 2, 3 y 4):
      $ gcc -o hello hello.c
    • Salida: código binario (ejecutable)
      $ ls -l hello
      -rwxr-xr-x  1 francis francis  7021 2007-09-16 13:13 hello

    El enlazado puede ser dinámico o estático:

    1. enlazado dinámico: en este caso, las librerías no se insertan en nuestro programa al compilarlo. Cuando ejecutemos nuestro programa, cada vez que necesite algo de una librería irá a buscarlo a ésta. Si borramos alguna librería nuestro programa dará un error de que no la encuentra ya que accede a la librería en tiempo de ejecución. El ejecutable es más pequeño y se verá afectado si hacemos cambios en las librerías. Esto es una ventaja si lo que hemos hecho ha sido corregir un error en la librería pero es un inconveniente si nos obliga a recompilar el ejecutable (por ejemplo, si hemos añadido un parámetro a una función). Las librerías dinámicas suelen llamarse libnombre.so (shared object) y se suelen usar en programas grandes o de sistema. Por defecto el enlazado es dinámico:
      $ gcc -o hello hello.c
      $ ls -l hello
      -rwxr-xr-x  1 francis francis  7021 2007-09-16 13:13 hello

      El comando ldd muestra las librerías dinámicas que usa un ejecutable (en cada línea aparece el nombre de la librería, la ruta completa y dónde está mapeada en el espacio de direcciones virtuales):

      $ ldd hello
              linux-gate.so.1 =>(0xb7f9d000)
              libc.so.6 =>/lib/tls/i686/cmov/libc.so.6 (0xb7e4f000)
              /lib/ld-linux.so.2 (0xb7f9e000)

      Si ldd muestra como salida not found para alguna librería quiere decir que no la encuentra por lo que el programa no podrá ser ejecutado. Tendremos que buscar la librería y colocarla en el lugar correcto, que por defecto es /lib y /usr/lib.

    2. enlazado estático: en este caso, las librerías se insertan en nuestro programa cuando lo compilamos de manera que el ejecutable resultante incluye las funciones de las librerías y ya no necesita acceder a éstas en tiempo de ejecución. El ejecutable es más grande pero más rápido, podemos llevarlo a otro ordenador sin tener que llevar las librerías y no se verá afectado por cambios en las librerías. Las librerías estáticas suelen llamarse libnombre.a (archive) y se suelen usar en programas pequeños.

      Para que el enlazado sea estático debemos especificar la opción -static (vemos la diferencia de tamaño entre el ejecutable con enlazado estático y el ejecutable con enlazado dinámico):

      $ gcc -static -o hello hello.c
      $ ls -l hello
      -rwxr-xr-x  1 francis francis 495407 2007-09-16 13:22 hello

      Los ejecutables con enlazado estático no dependen de ninguna librería:

      $ ldd hello
              not a dynamic executable - statically linked

    El compilador tiene varias opciones que se utilizan en la fase de enlazado:

    • -l<nombre_librería>: si el programa emplea alguna librería diferente de la librería E/S estándar stdio hay que incluirla en el comando de compilación. Por ejemplo, si se utilizan funciones matemáticas tendremos que enlazar la librería matemática math (y no olvidar la sentencia #include <math.h>):
      $ gcc -o arch1 arch1.c -lmath
    • -L<ruta_librería>: añade un directorio a la lista de directorios donde el compilador busca librerías (por defecto /lib y /usr/lib):
      $ gcc -o arch1 arch1.c -L/home/francis/lib milib.a
    • -I<ruta_header>: añade un directorio a la lista de directorios donde el compilador busca archivos de cabecera #include (por defecto /usr/include):
      $ gcc -o arch1 arch1.c -I/home/francis/include

Deja un comentario