C desde la línea de comandos (parte 2)

En este vídeo hablo del resto de parámetros que quedan por contar para invocar a gcc y clang desde la línea de comandos y continúo mostrando cómo podría usarse tal cual gcc o clang sin ningún IDE para compilar nuestros programas.

Después de haber transformado nuestro código fuente en C a código ensamblador, el siguiente paso en el proceso de compilación es generar el archivo de código objeto. Este archivo, con extensión .o, contiene instrucciones en lenguaje máquina que el procesador puede entender directamente. Para obtenerlo, utilizamos el compilador GCC con la opción -c, por ejemplo, gcc -c hello.c. Esto produce un archivo binario que no es legible como texto, ya que contiene datos en formato máquina.

Aunque el archivo .o contiene instrucciones que el procesador reconoce, no es un programa ejecutable por sí mismo. Le falta una estructura fundamental que los sistemas operativos requieren para ejecutar un programa. Por ejemplo, en sistemas Linux, los ejecutables en formato ELF incluyen información sobre el espacio de memoria necesario, el tamaño de la pila y del heap, entre otros detalles. En Windows, los archivos .exe son aún más complejos, ya que pueden contener iconos, cadenas y otros recursos embebidos.

Para convertir estos archivos objeto en un programa ejecutable, necesitamos la etapa de enlazado. El enlazador, que en sistemas Unix suele ser ld y forma parte de Binutils, toma todos los archivos .o que componen nuestro programa y los une, resolviendo referencias entre funciones y variables, y añadiendo la estructura necesaria para que el sistema operativo reconozca el archivo como un ejecutable válido.

Podemos realizar el enlazado usando GCC directamente, pasando los archivos objeto como argumentos. Por defecto, el ejecutable resultante se llama a.out en sistemas Unix o a.exe en Windows con MinGW, aunque podemos cambiar el nombre con la opción -o. Por ejemplo:

gcc -o hello hello.o

También es posible compilar y enlazar en un solo paso, pasando directamente los archivos fuente a GCC:

gcc -o hello hello.c

GCC se encargará de realizar todas las etapas necesarias para generar el ejecutable final.

Cuando trabajamos en proyectos con múltiples archivos fuente, como en un programa que consta de empleados.c, sueldos.c y main.c, podemos compilar todo junto con:

gcc -o empleados empleados.c sueldos.c main.c

En este proceso, GCC compila cada archivo fuente por separado a código objeto y luego enlaza todos los objetos para crear el ejecutable final. Sin embargo, compilar todo de nuevo cada vez que hacemos un cambio puede ser ineficiente, especialmente en proyectos grandes.

Por eso, es recomendable compilar primero cada archivo fuente a su correspondiente archivo objeto con -c:

gcc -c main.c
gcc -c sueldos.c
gcc -c empleados.c

De esta forma, si modificamos solo uno de los archivos, solo necesitamos recompilar ese archivo y luego enlazar todos los objetos para obtener el ejecutable. Esto ahorra tiempo de compilación.

Para automatizar este proceso y evitar tener que escribir manualmente todos los comandos, podemos usar herramientas como make. Make permite definir reglas que indican cómo compilar cada archivo y cómo enlazarlos, de modo que solo recompila lo que ha cambiado y enlaza automáticamente. Esto es especialmente útil en proyectos con muchos archivos y dependencias.

En resumen, el flujo completo desde el código fuente hasta el ejecutable implica preprocesado, compilación a ensamblador, ensamblado a código objeto y finalmente enlazado. Entender cada etapa y cómo manejar los archivos .o nos permite optimizar el proceso de compilación y trabajar de forma más eficiente en proyectos complejos. Además, aprovechar herramientas como make facilita enormemente la gestión de compilaciones en proyectos con múltiples archivos.

Lista de reproducción
  1. 1
    Instalar CodeBlocks
    15 minutos
  2. 2
    Funciones y hola mundo
    17 minutos
  3. 3
    Variables y tipos de datos
    17 minutos
  4. 4
    Condicionales y operadores lógicos
    16 minutos
  5. 5
    Bucles
    11 minutos
  6. 6
    Punteros
    12 minutos
  7. 7
    Arrays
    14 minutos
  8. 8
    Estructuras
    12 minutos
  9. 9
    Otras construcciones de C
    9 minutos
  10. 10
    Memoria dinámica
    8 minutos
  11. 11
    El preprocesador (parte 1)
    10 minutos
  12. 12
    El preprocesador (parte 2)
    9 minutos
  13. 13
    Archivos de cabecera y múltiples .c (parte 1)
    8 minutos
  14. 14
    Archivos de cabecera y múltiples .c (parte 2)
    9 minutos
  15. 15
    C desde la línea de comandos (parte 1)
    8 minutos
  16. 16
    C desde la línea de comandos (parte 2)
    9 minutos
  17. 17
    Break y continue
    10 minutos
  18. 18
    Goto
    13 minutos
  19. 19
    Manipulación de bits
    15 minutos
  20. 20
    Máscaras de bit
    19 minutos
  21. 21
    Archivos (1): fopen y fclose
    13 minutos
  22. 22
    Archivos (2): leer con fgetc
    9 minutos
  23. 23
    Archivos (3): fseek y ftell
    11 minutos
  24. 24
    Archivos (4): leer con fgets
    9 minutos
  25. 25
    Archivos (5): fputc y fputs
    7 minutos
  26. 26
    Archivos (6): volcar en archivos con fwrite
    10 minutos
  27. 27
    Archivos (7): fread, fwrite y los arrays
    10 minutos
  28. 28
    Archivos (8): entrada estándar y salida estándar
    9 minutos
  29. 29
    Archivos (9): buffers
    14 minutos
  30. 30
    Archivos (y 10): otras funciones útiles con archivos
    5 minutos
  31. 31
    printf (1)
    18 minutos
  32. 32
    printf (parte 2)
    12 minutos
  33. 33
    scanf (parte 1)
    17 minutos
  34. 34
    scanf (parte 2)
    17 minutos
  35. 35
    fprintf, sprintf y snprintf
    8 minutos
  36. 36
    Tipos de datos opacos
    13 minutos
  37. 37
    Bibliotecas estáticas
    13 minutos
  38. 38
    Bibliotecas dinámicas
    15 minutos
  39. 39
    Más flags: i mayúscula (include), wall, werror, pedantic...
    12 minutos
  40. 40
    pkg-config
    12 minutos
  41. 41
    Make
    17 minutos
  42. 42
    GDB
    21 minutos
  43. 43
    Variables globales
    6 minutos
  44. 44
    extern
    9 minutos
  45. 45
    Funciones variádicas
    12 minutos
  46. 46
    El optimizador de GCC y la opción -O
    12 minutos
  47. 47
    Volatile
    6 minutos