Tutorial de compilacion en C
Con anterioridad de la computacion hogarena, los sistemas multiusuari@ constituyeron el principal medio para programar.
Por tal motivo, este tutorial te ilustrara con ejemplos basicos como se traduce el codigo fuente de un programa en lenguaje C de alto nivel a un programa ejecutable en este sistema compartido y otros compatibles.
Este tutorial no es uno de programacion, utilizaremos codigo pre-hecho. Si deseas programar, puedes acceder a Wikilibro de Programacion en C o recursos en linea trspos, entre muchas otras recomendables.
Introduccion
Si bien es posible crear programas utilizando lenguajes de bajo nivel como el ensamblador, normalmente querras utilizar lenguajes de alto nivel.
La diferencia radica en que los lenguajes de alto nivel son portables, mientras que los de bajo nivel - ademas de ser mas dificiles de aprender - estan imbuidos de las particularidades del microprocesador en donde se ejecutan. Aprender los lenguajes de alto nivel permite escribir programas para multiples computadoras, que sean -ademas - mas simples de compartir.
El lenguaje C disenado por Dennis Ritchie (uno de los creadores de Unix) es uno de tales lenguajes de alto nivel, y se revela especialmente util para la programacion portable. Podras utilizarlo en Texto-plano no solo para emprender proyectos avanzados, sino tambien para aprender los pasos fundamentales para operar con lenguajes de alto nivel: lo que llamamos procesos de la programacion, o - de forma generica - la compilacion.
Programacion
La programacion es un arte. Involucra una serie de procesos mujer/maquina para resolver un problema determinado.
Consideremos el orden de los procesos de la programacion:
Accion realizada: | Genera: | Opcion de CC para detener en este paso: |
---|---|---|
Imaginar | Percepcion de un problema | |
Considerar un problema de programacion | codigo in mente | (esto es Cerebral) |
Edicion del codigo fuente | codigo fuente | (para esto usaras un editor) |
1. Preprocesado | codigo fuente preprocesado | -E |
2. Compilacion | codigo ensamblador | -S |
3. Ensamblado | codigo objeto | -c |
4. Enlazado | binario ejecutable |
Como puede verse, los ultimos 4 pasos maquinales de la programacion con lenguajes de alto nivel son practicados por medio de un Compilador, un programa de computadora capaz de traducir el codigo fuente escrito en un lenguaje en otro lenguaje de operacion distinto (el codigo destino).
En nuestro sistema compartido utilizaremos el conjunto de compiladores CC (en GNU/Linux puedes tambien utilizar GCC). Este super-compilador por linea de comandos es capaz de afrontar en traducir tu codigo fuente propio o bien cualquiera que te hayan compartido.
Compilacion basica
La manera mas simple de compilar consiste en llamar a CC, asi:
cc codigo_fuente.c –o binario_ejecutable
CC oficiara de compilador automatico, y procesara un fichero de
codigo fuente llamado codigo_fuente.c
para generar como
resultado un fichero de destino ejecutable, llamado
binario_ejecutable
. Si todo va bien, CC sera tan parco que
no informara nada, simplemente compilara y creara el ejecutable sin
decir mas.
Incluso es opcional la opcion
-o
que indica el fichero ejecutable de destino: si no la incluyes , CC almacenara el resultado de la compilacion en un fichero ejecutable de nombre llamado genericamentea.out
.
Hola Tercer Mundo!
Si hay un programa canonico a la hora de empezar a programar en cualquier lenguaje de programacion, ese es el mitico “Hola, Tercer Mundo!”.
La mania de utilizar un programa que de salida en un terminal la cadena “Hola, Tercer Mundo!” para ejemplificar el funcionamiento del proceso de compilacion en un determinado lenguaje se remonta –una vez mas- a los origenes del UNIX, el lenguaje C, con Kerningan, Ritchie, Thompson y compania haciendo de las suyas.
Para compilar este saludo universal es conveniente organizar un
directorio de trabajo ~/src/holamundo/
para destinar el
codigo fuente:
mkdir -p ~/src/holamundo ;
cd ~/src/holamundo/
Ya en tu directorio ~/src/holamundo
, usa tu editor favorito para crear un
fichero llamado holamundo.c
, e incorporale el siguiente
codigo fuente en lenguaje C:
// * * * Programa simple en C para mostrar "Hola Tercer Mundo!" * * *
#include <stdio.h>
int main()
{
printf("Hola Tercer Mundo!\n");
return 0;
}
Guarda los cambios y vuelve al Shell.
Compilacion Automatica
La manera mas simple de resolver los cuatro pasos maquinales con el compilador automatico CC (o GCC en GNU/Linux), es utilizar la siguiente sintaxis:
cc holamundo.c
Si todo marcha sobre ruedas, el compilador CC elaborara un fichero
ejecutable a.out
.
Comprueba su funcionamiento correcto con:
./a.out
...y en la terminal deberia aparecer el saludo:
Hola Tercer Mundo!
Si bien la compilacion automatica es sumamente simple y conveniente, ¡no nos muestra los pasos intermedios, y tampoco es tan divertida!
¡Aprendamos, en cambio, los cuatro pasos de la compilacion, esta vez compilando un juego!
Microtetris
Compila manualmente ahora un clon del Tetris.
Crea un directorio de trabajo para el juego:
mkdir -p ~/src/microtetris/ ; cd ~/src/microtetris/
...ya en este directorio, crea el fichero microtetris.c
.
El codigo fuente en lenguaje C requirio un gran trabajo de estudio a un
par de programador@s, y ocupa 9,6K. No olvides guardarlo y volver al
shell.
Ahora compila siguiendo los 4 pasos maquinales de la compilacion manual:
1. Preprocesar
Primero preprocesa este codigo fuente
microtetris.c
, analizandolo con el parser de
CC:
cc microtetris.c -E -o microtetris.i
Obtendras asi un fichero de codigo fuente preprocesado de
microtetris.i
(en este caso "se inflara" pensando unos
41K). Si deseas curiosear el codigo preprocesado (o "parseado"), utiliza
cat microtetris.i.
2. Compilar
Una vez parseado, podras compilar tu codigo fuente con:
cc microtetris.c -S
La compilacion del codigo fuente traducira el codigo fuente de alto
nivel en un codigo fuente de bajo nivel especifico para el procesador de
la maquina, llamado codigo de lenguaje ensamblador (el fiuchero
se llamara micreotetris.s
).
Puedes revisar la compilacion lenguaje ensamblador con cat microtetris.s. Veras un conjunto de mnemonicos que representan simbolicamente instrucciones basicas para el microprocesador. Dependiendo del tipo de arquitectura, este codigo puede resultar mas inflado aun, en este caso de 48K.
Recuerda, puedes programar en ensamblador, pero como ves ¡es 5 veces mas pesado (y dificil) de hacerlo!
3. Ensamblar
Ensambla el codigo en lenguaje ensamblador:
cc microtetris.s -c -o microtetris.o
Obtendras ahora el codigo objeto microtetris.o
,
que corresponda a la arquitectura del sistema. Este se ha reducido (en
este caso, hasta unos 17K).
El codigo objeto es el lenguaje interpretable directamente por una computadora o microcontrolador digital.
4. Enlazar
Para crear el ejecutable codigo maquina binario debes entrelazar este codigo objeto (incluyendo sus librerias, si las tuviese), y sumarle los encabezados. De todo ello se encarga el enlazador de CC:
cc microtetris.o -o microtetris.out
Lograras asi final el fichero ejecutable de salida, consistente en el
binario de codigo maquina microtetris.out
(ya de
15K, los que requerira para cargarse en la memoria de texto-plano).
Si utilizas cat para revisar el codigo objeto
microtetris.o
o el codigo maquinamicrotetris.out
, muy probablemente recibiras en tu terminal caracteres ininteligibles. No es basura, ¡solo una maquina de esta arquitectura podra ejecutarlo! (Que un humano comprenda el codigo maquina es un cliche tipico de la Ciencia Ficcion).
Ejecutar
Con todo cocinado, evalua correr el fichero del codigo maquina de salida ejecutandolo en tu sistema:
./microtetris.out
¡Felicitaciones! El programa corrio con exito.
Limpiar y ordenar
Opcionalmente puedes limpiar tu ambiente de programacion.
Podrias querer omitir la extension .out
del binario
final para simplificarla (no es comun que se use .out
para
los ejecutables distribuidos):
mv microtetris.out microtetris
Elimina los ficheros intermedios del proceso de compilacion:
rm ~/src/microtetris.i ~/src/microtetris.s ~/src/microtetris.o
Si lo deseas, tambien puedes eliminar el codigo fuente.
rm ~/src/microtetris.c
¡Ya has programado, compilado y probado!
Compilacion Avanzada
La mayoria de los proyectos de software no son tan simples: suelen estar compuestos por mas de un fichero de codigo fuente, por lo que habria que compilar varios de ellos de forma encadenada para generar un unico binario ejecutable. Esto se puede hacer indicandole a CC varios ficheros de codigo fuente y un ejecutable destino, de esta manera:
cc menu.c backend.c programa.c –o juego
Tambien es muy corriente que los ficheros fuente de un mismo proyecto
se encuentren desperdigados en distintos directorios, y que conforme el
proyecto crezca, existan muchos ficheros de cabeceras (de extension
.h
). Para evitar problemas a la hora de tratar con
proyectos semejantes, es posible hacer uso de la opcion de inclusion de
CC -I
, que incluye los ficheros necesarios.
En caso de tener todos los ficheros fuente de un proyecto dentro del
directorio ~/src/
, y todos los ficheros de cabeceras estan
en el directorio include
. Podriamos compilar el proyecto de
la siguiente manera:
cc ./src/*.c –I include –o juego
Tambien puede darse el caso que algunos fuentes dispongan de opciones de compilacion diferenciadas entre si. En tal caso es muy util generar separadamente los respectivos codigos objeto, y una vez que todos esten compilados, enlazarlos a todos para obtener el ejecutable binario final:
cc –c backend.c –o backend.o
cc –c programa.c –lgraficos –o programa.o
cc –c menu.c –lcurses –o menu.o
cc kackend.o programa.o menu.o –o juego
Librerias
Muchos programas de cierta entidad suelen hacer uso de librerias
de funciones (realmente son “bibliotecas”), que contienen funciones
pre-programadas. Para poder reutilizar estas librerias estandares del
sistema es necesario indicarlo a CC con la opcion -l
.
Por ejemplo, si nuestro fichero programa.c
requiere que
este instalada la libreria curses
o ncurses
en
el sistema (la libreria se llamara casi con seguridad
libncurses
), utilizarias:
cc –c programa.c –lcurses –o programa.o
Si la libreria no es una libreria estandar del sistema, sino una que
pertenece unicamente a nuestro proyecto, podremos indicar la ruta
empleando la opcion -L
y especificando su ruta:
cc –c programa.c –L./libs/libreria-programa –o programa.o
Arkurses
Sabiendo todo esto, introduce y compila el codigo fuente de Arkurses. Se trata de un clon del juego Arkanoid que utiliza la funciones de las librerias de graficas de terminal ncurses y panel. Aprovecharemos para indicar tambien el comando time, que nos indicara el tiempo de procesador requerido por cada tarea de computo.
Para afrontar las dificultades indicadas anteriormente, compilalo automaticamente de esta manera:
time cc arkurses.c -lpanel -lncurses -o arkurses -Os -march=native
...o bien podras realiza los 4 pasos de la compilacion manual, especificandole a CC las librerias ncurses y panel necesarias. Podras hacerlo con:
#preprocesa y muestra el codigo parseado
time cc arkurses.c -E -o arkurses.i -march=native ; cat arkurses.i ;
#compila arkurses.c con sus librerias y muestra el ensamblador resultante:
time cc arkurses.c -lpanel -lncurses -Os -S -march=native ; cat arkurses.s ;
#ensambla
time cc arkurses.s -lpanel -lncurses -c -Os -march=native -o arkurses.o ;
#enlaza todo y crea el binario de salida
time cc arkurses.o -lpanel -lncurses -o arkurses.out -Os -march=native ;
#Renombra el fichero de salida de compilacion
mv arkurses.out arkurses
Una vez obtenido el fichero binario ejecutable destino, evalualo con:
./arkurses
(Puedes salir del juego con la tecla q).
Luego elimina los sobrantes y deja el ejecutable, con
rm arkurses.c arkurses.i arkurses.s arkurses.o
Conclusion
Felicitaciones ¡Ya compilaste tu primer programa en C en texto-plano.xyz! Comparte tu logro con gab:
gab -m "¡Acabo de escribir, compilar y ejecutar mi primer programa en C!"
Preprocesar, base para compilar. Compilar, base para ensamblar. Ensamblar, base para enlazar. Y enlazar, base para Ejecutar.
Ver tambien: Tutorial de Compilacion en Fortran