¿Te resulta más fácil leer con fondo crema, un tono de color, más contraste o un texto más grande? Elige tus colores y tu texto una sola vez, para todas las páginas.

Lección gratuita

Del código fuente al programa que funciona (gcc)

Después de esta lección: Puedo nombrar las etapas por las que un compilador lleva un programa.

Lección de 50 min10 comandosLaboratorio de compiladores y arquitectura: gcc, flex, bison y RISC-V en una VM

El error que llegó al final

Una clínica tiene un programa que envía avisos de citas por SMS. Tras un cambio, ya no se compila. El mensaje dice undefined reference to send_sms.

Una compañera revisa el código C línea a línea durante una hora. El código está bien. El error lo dio el último paso, que ni siquiera lee el código. Saber qué paso habla ahorra esa hora.

Al final de esta lección

Nota

Puedo nombrar las etapas por las que un compilador lleva un programa.

Palabras clave

PalabraQué significaEjemplo
Driverel programa que lanza las demás herramientas en ordengcc
Preprocesadorla etapa que pega archivos y sustituye macros
Ensambladorel programa que pasa el ensamblador a código máquinaas
Archivo objetocódigo máquina que aún no es un programa enterohello.o
Símboloun nombre que el enlazador tiene que encontrar
Enlazadorel programa que une archivos objeto y bibliotecasld

Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.

La primera etapa sustituye macros

El archivo hello.c tiene una macro, GREETING, y una línea #include.

El preprocesador trabaja antes que nada. Pega el contenido de stdio.h y cambia cada macro por su texto. La opción -E detiene gcc justo ahí y escribe el resultado en pantalla. El primer Run entra en la carpeta. El segundo muestra solo el final.

Entra en la carpeta del compilador

Comando
cd ~/compiler

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

El final del código preprocesado

Comando
gcc -E hello.c | tail -n 6

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

gcc lanza otros programas por ti

Cuando escribes gcc hello.c, gcc hace muy poco por sí mismo. Es un driver: lanza otros programas, uno tras otro, y pasa a cada uno el archivo del anterior.

La opción -### hace que gcc escriba esas órdenes sin ejecutar ninguna. El Run se queda solo con el programa de cada orden.

Los programas que gcc lanzaría

Comando
gcc -### -o hello hello.c 2>&1 | grep "^ " | cut -d " " -f 2

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Ejemplo: tres programas, cuatro etapas

ProgramaEtapas que haceLo que escribe
cc1Preprocesar y compilarEnsamblador, un archivo .s
asEnsamblarUn archivo objeto, .o
collect2Enlazar, llamando a ldEl programa

Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.

Guarda el archivo de cada etapa

Normalmente los archivos intermedios van a una carpeta temporal y se borran. La opción -save-temps los deja junto al código.

Una sola compilación deja entonces cuatro archivos: hello.i, hello.s, hello.o y hello. La orden file lee el principio de cada uno y dice de qué tipo es.

Compila una vez y guárdalo todo

Comando
gcc -save-temps -o hello hello.c

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

¿Qué es cada archivo?

Comando
file hello.i hello.s hello.o hello

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Ejemplo: lo que dijo file

ArchivoLo hizoCómo lo llama file
hello.iEl preprocesadorC source, ASCII text
hello.sEl compiladorassembler source, ASCII text
hello.oEl ensambladorELF 64-bit LSB relocatable
helloEl enlazadorELF 64-bit LSB pie executable

Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.

Un archivo objeto tiene huecos

hello.o contiene el código de square y de main. Pero main llama a printf, y printf no está en este archivo. Vive en la biblioteca de C.

nm lista los símbolos de un archivo objeto. T significa que el código está aquí. U significa sin definir: un hueco que el enlazador debe llenar.

Después lanza tú el enlazador ld, sin biblioteca de C. Lee lo que dice.

Los símbolos de hello.o

Comando
nm hello.o

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Enlaza sin nada más

Comando
ld hello.o -o broken

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Un error frecuente

Advertencia

Mucha gente cree que todo error de compilación es un fallo en su código. Un undefined reference viene del enlazador, cuando el código ya compiló bien. Significa que el cuerpo de un símbolo no llegó al último paso. Revisa qué se enlaza, no la línea de C.

Cuando el que habla es el compilador

Ahora el caso contrario. El primer Run hace una copia, cube.c, que llama a cube(7), una función que no existe en ningún sitio. hello.c no cambia.

El segundo Run compila la copia con -c, así que gcc no llega a enlazar. El tercero busca el archivo objeto.

Haz una copia con otra función

Comando
sed 's/square(7)/cube(7)/' hello.c > cube.c

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Compila la copia sin enlazar

Comando
gcc -c cube.c

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

¿Se escribió cube.o?

Comando
ls cube.o

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Para ir más lejos

Escríbelo tú. Añade a cube.c la línea int cube(int n); encima de main, con un editor de texto. Compila con gcc -c cube.c y lee nm cube.o. Después compila con gcc cube.c.

Explica por qué ahora el error sale de otra etapa, y qué tendrías que añadir para que el programa se cree.

Sobre este laboratorio y su código: Laboratorio de compiladores y arquitectura: gcc, flex, bison y RISC-V en una VM

¿Enseñas a una clase? Asigna este módulo a tus alumnos con guía del profesor, tareas con corrección automática y un laboratorio para cada alumno.