Compilación, enlazado, make,...
Este
apartado tiene cierta dificultad para aquellos que se inician en C++,
la idea es que el código fuente (archivo de texto) hay que
convertirlo en un programa ejecutable (código máquina),
esto en aplicaciones extensas entraña cierta dificultad, pero
afortunadamente Anjuta lo hace por nosotros. Con ello, pagamos un
precio, aparecen muchos archivos en nuestro proyecto que no son
código fuente.De código fuente a archivo ejecutable
El código fuente escrito en C++, no deja de ser un archivo de texto
incomprensible para el microprocesador. Es necesario pasar este texto
escrito en el lenguaje C++ al lenguaje comprensible por el ordenador:
el código máquina. Este proceso se denomina compilación. La
compilación requiere normalmente dos pasos: el compilado en sí, donde
el código fuente se convierte a código máquina, y el enlazado (linker),
donde distintos códigos objetos son enlazados para construir un archivo
ejecutable. Lo normal es que una aplicación la compongan una serie de
archivos, de lo contrario el código fuente sería un archivo enorme, con
el que sería muy difícil trabajar. La
compilación de C++ incluye un paso previo, que es el
preprocesado. En C++ se distinguen dos tipos de texto, las directivas
del preprocesador y el código en sí. El primer paso es
coger estas directivas (que se caracterizan por empezar por #) e
interpretarlas, pasarlas a código. Veamos un ejemplo:
Crea
una carpeta en el directorio /home/usuario, por ejemplo
programauno. En él edita el siguiente código (con el
editor de textos) y grabalo como kk.cc:
#define ketonta 1 int main () { int x=10;
x= x*ketonta; return 0; }
Abrimos
un terminal [Aplicaciones->Accesorios->Terminal], en éste,
nos vamos al directorio de trabajo, y ejecutamos la primera fase del
prepocesado: ~$ cd /home/usuario/programauno ~/programauno$ g++ -E kk.cc > prepocesado.txt Observarás
que en la carpeta se ha creado un archivo de texto - de nombre
prepocesado.txt -que básicamente sustituye el sinónimo
establecido en el programa con la directiva define.
| |
El
siguiente paso, es la compilación en sí, pasar el
código fuente a código objeto, lo cual se puede
realizar así:
~/programauno$ g++ -c kk.ccse
creará un kk.o que no podrás editar como archivo de
texto, pues es un binario (debes instalar un editor como bless).
Si
alguna vez deseamos "pulir" nuestro programa en ensamblador, yo nunca
lo he hecho, pero más de una vez leí sobre ello (con
antiguos procesadores, microchips programables), podemos obtener la
versión en ensamblador con:
~/programauno$ g++ -S kk.cc te
aparecerá un nuevo archivo kk.s con el código en
ensamblador, lo cual es más inteligible que el código
objeto.
Un último paso es el enlazado, que nos permite
la creación de un ejecutable. Antes de proceder vamos a borrar
todos los archivos anteriores y reeditamos kk.cc con el siguiente
texto, para que el programa haga algo (no te preocupes si ahora no lo
entiendes).
#include <iostream>
#define ketonta 2
int main ()
{
int x=10;
x= x*ketonta;
std::cout<<" el doble de 10 es: "<<x<< std::endl;
std::cout<<" ¡¡ Que tontá !!"<<std::endl;
return 0;
}Vamos
a preprocesar y compilar en un primer paso (obtendremos kk.o) [si
preprocesas únicamente verás porque razón
utilizamos el programa anterior] y luego vamos a enlazar:
~/programauno$ g++ -c kk.cc
~/programauno$ g++ kk.o
Te
aparecerá un nuevo archivo a.out, éste es un archivo
ejecutable. Para ejecutarlo, desde la consola, lo llamamos, pero
recuerda que si pongo solo a.out el sistema busca en los directorios de
ejecutables del sistema y nos da un error [bash: a.out: orden no
encontrada], es necesario buscar en el directorio actual, por lo que
escribimos
./a.out, y obtendremos la siguiente salida:
~/programauno$ ./a.out
el doble de 10 es: 20
¡¡ Que tontá !!
~/programauno$Ahora, renombro este archivo a mi gusto y se acabó.
Todo en unoEn realidad, g++ nos permite realizar todo en un paso:
g++ -o minombre kk.ccy obtendremos un programa ejecutable con el archivo minombre.
Volviendo
al enlazado existen dos posibilidades, que este sea estático o
dinámico. El enlazado estático implica que las funciones
de una librería externa se incorporan a nuestro ejecutable, no
siendo necesario las mismas para su ejecución (por si luego
ejecutamos nuestra aplicación en otro ordenador donde no tenemos
acceso como root y no podemos instalar las librerías); mientras
que en el dinámico, opción por defecto, la
aplicación requiere la existencia en el ordenador de las
librerías.
Para realizar un enlazado estático utilizamos:
g++ -static -o minombre2 kk.ccSi
observas la diferencia entre minombre, 8,8 Kb, y minombre2, 1,2Mb,
verás porque normalmente los programadores utilizan el enlace
dinámico.
Para una aplicación con varios archivos, la compilación se realiza:
g++ -o nombreejecutable archivo1.cc archivo2.cc archivo3.cc archivon.ccMake y makefile
Antes hemos visto que se puede realizar todo el proceso en una sola fase, así es, pero no es lo habitual.
La
razón es muy sencilla, cuando un programa tiene varios archivos
y modificamos uno, en la compilación se vuelven a compilar
todos otra vez, aunque no se hayan modificado. Esto en pequeños
programas no tiene mayor problema, pero cuando éste alcanza
cierta dimensión, la pérdida de tiempo es considerable.
Por
ello, se ideo una compilación separada donde al realizar una
pequeña modificación solo se compilan los archivos
afectados y no todos. Y este es el propósito del comando make.
Cuando en un directorio, ejecutamos make, él busca
rápidamente las reglas de compilación establecidas en el
archivo makefile.
No es el propósito de este manual
explicar (por ahora) como escribir los makefile, porque precisamente
Anjuta se va a encargar de eso por nosotros.