11
1 CURSO DE PROGRAMACIÓN EN C PARA GNU/LINUX (II) 26Oct06 En la pasada entrega ; de este curso de programación en C para GNU/Linux hablamos de procesos, tareas, hilos, planificación, y demás. En esta ocasión, hablaremos del GCC (antiguamente conocido como GNU C Compiler y actualmente como GNU Compiler Collection), de los Makefiles y de cómo escribir y ejecutar nuestro primer programa en C para GNU/Linux. El GCC Las siglas GCC significan actualmente “GNU Compiler Collection“ (“Colección de compiladores GNU”). Antes estas mismas siglas significaban “GNU C Compiler” (“Compilador C de GNU”), si bien ahora se utilizan para denominar a toda una colección de compiladores de diversos lenguajes como C, C++, Objetive C, Chill, Fortran, y Java. Esta colección de compiladores está disponible para prácticamente todos los Sistemas Operativos, si bien es característica de entornos UNIX libres y se incluye en la práctica totalidad de distribuciones de GNU/Linux. En su desarrollo participan voluntarios de todas las partes del mundo y se distribuye bajo la licencia GPL (“General Public License”) lo que lo hace de libre distribución: está permitido hacer copias de él y regalarlas o venderlas siempre que se incluya su código fuente y se mantenga la licencia. Nosotros nos referiremos al GCC únicamente como el compilador de C estándar en GNU/Linux. COMPILACIÓN BÁSICA GCC es un compilador de línea de comandos, aunque existen numerosos IDE o entornos de desarrollo que incluyen a GCC como su motor de compilación. La manera más simple de llamar a GCC es esta: gcc codigo.c –o ejecutable Así el GCC compilará el código fuente que haya en “codigo.c” y generará un fichero ejecutable en “ejecutable”. Si todo el proceso se ha desarrollado correctamente, el GCC no devuelve ningún mensaje de confirmación. En realidad la opción “-o” para indicar el fichero de salida no es necesaria, y si no se indica se guarda el resultado de la compilación en el fichero “a.out”. Muchos proyectos de software están formados por más de un fichero fuente, por lo que habrá que compilar varios ficheros para generar un único ejecutable. Esto se puede hacer de forma sencilla llamando a GCC con varios ficheros fuente y un ejecutable: gcc menu.c bd.c motor.c –o juego

CURSO DE PROGRAMACIÓN EN C PARA GNU

Embed Size (px)

Citation preview

1

CURSO DE PROGRAMACIN EN C PARA GNU/LINUX(II) 26Oct06

En la pasada entrega; de este curso de programacin en C para GNU/Linux hablamos de procesos, tareas, hilos, planificacin, y dems. En esta ocasin, hablaremos del GCC (antiguamente conocido como GNU C Compiler y actualmente como GNU Compiler Collection), de los Makefiles y de cmo escribir y ejecutar nuestro primer programa en C para GNU/Linux.

El GCC

Las siglas GCC significan actualmente GNU Compiler Collection (Coleccin de compiladores GNU). Antes estas mismas siglas significaban GNU C Compiler (Compilador C de GNU), si bien ahora se utilizan para denominar a toda una coleccin de compiladores de diversos lenguajes como C, C++, Objetive C, Chill, Fortran, y Java. Esta coleccin de compiladores est disponible para prcticamente todos los Sistemas Operativos, si bien es caracterstica de entornos UNIX libres y se incluye en la prctica totalidad de distribuciones de GNU/Linux. En su desarrollo participan voluntarios de todas las partes del mundo y se distribuye bajo la licencia GPL (General Public License) lo que lo hace de libre distribucin: est permitido hacer copias de l y regalarlas o venderlas siempre que se incluya su cdigo fuente y se mantenga la licencia. Nosotros nos referiremos al GCC nicamente como el compilador de C estndar en GNU/Linux.COMPILACIN BSICA

GCC es un compilador de lnea de comandos, aunque existen numerosos IDE o entornos de desarrollo que incluyen a GCC como su motor de compilacin. La manera ms simple de llamar a GCC es esta:

gcc codigo.c o ejecutable

As el GCC compilar el cdigo fuente que haya en codigo.c y generar un fichero ejecutable en ejecutable. Si todo el proceso se ha desarrollado correctamente, el GCC no devuelve ningn mensaje de confirmacin. En realidad la opcin -o para indicar el fichero de salida no es necesaria, y si no se indica se guarda el resultado de la compilacin en el fichero a.out.

Muchos proyectos de software estn formados por ms de un fichero fuente, por lo que habr que compilar varios ficheros para generar un nico ejecutable. Esto se puede hacer de forma sencilla llamando a GCC con varios ficheros fuente y un ejecutable:

gcc menu.c bd.c motor.c o juego

Sin embargo es bastante probable que todos los ficheros fuente de un mismo proyecto no se encuentren en el mismo directorio, y que conforme el proyecto crezca, existan muchos ficheros de cabeceras (los tpicos .h) y se alojen en directorios diferentes. Para evitar problemas a la hora de tratar con proyectos semejantes, podemos hacer uso de la opcin -I e incluir los ficheros que sean necesario. Imaginemos que tenemos un proyecto en el que todos los ficheros fuente estn dentro del directorio src y todos los ficheros de cabeceras estn en el directorio include. Podramos compilar el proyecto de la siguiente manera:

gcc ./src/*.c Iinclude o juego

PASO A PASO

Hasta ahora hemos dado por hecho que es normal que un compilador realice todos los pasos necesarios para obtener un ejecutable partiendo del cdigo fuente, si bien esto no tiene por qu ser as. A la hora de generar un ejecutable hay una serie de procesos implicados:

Edicin del cdigo fuente cdigo fuente.

Preprocesado cdigo fuente preprocesado.

Compilacin cdigo ensamblador.

Ensamblado cdigo objeto.

Enlazado ejecutable.

Mediante el GCC pueden realizarse todos ellos secuencialmente hasta conseguir el ejecutable. Eso es lo que hemos estado haciendo en los ejemplos anteriores, pero en ocasiones es conveniente parar el proceso en un paso intermedio para evaluar los resultados: Con la opcin -E detenemos el proceso en la etapa de preprocesado, obteniendo cdigo fuente preprocesado.

Con la opcin -S se detiene en la etapa de compilacin, pero no ensambla el cdigo.

Con la opcin -c, compila y ensambla el cdigo, pero no lo enlaza, obteniendo cdigo objeto.

Si no indicamos ninguna de estas opciones, se realizarn las cuatro fases de las que se encarga el GCC: preprocesado, compilacin, ensamblado y enlazado.Ahora ya controlamos ms el proceso. Cuando un proyecto involucra muchos ficheros es bastante normal que no todas sus partes tengan las mismas opciones de compilacin. Por ello es muy til generar separadamente los respectivos cdigos objeto, y cuando ya estn todos generados, enlazarlos para obtener el ejecutable:gcc c bd.c o bd.o

gcc c motor.c lgraphics o motor.o

gcc c menu.c lcurses o menu.o

gcc bd.o motor.o menu.o o juego

LIBRERASConforme un proyecto va ganando entidad se hace casi irremediable el uso de libreras (realmente son bibliotecas) de funciones, que permiten reutilizar cdigo de manera cmoda y eficiente.

Para utilizar libreras estndar en el sistema es necesario emplear la opcin -l a la hora de llamar a GCC:gcc c menu.c lcurses o menu.o

La compilacin de este fichero (menu.c) requiere que est instalada la librera curses o ncurses en el sistema, por ejemplo (la librera se llamar casi con seguridad libncurses). Si la librera no es una librera estndar en el sistema, sino que pertenece nicamente a nuestro proyecto, podremos indicar la ruta empleando la opcin -L:gcc c motor.c L./libs/librera-motor o motor.o

OPTIMIZACIONESEl GCC incluye opciones de optimizacin en cuanto al cdigo generado. Existen 3 niveles de optimizacin de cdigo:1. Con -O1 conseguimos optimizaciones en bloques repetitivos, operaciones con coma flotante, reduccin de saltos, optimizacin de manejo de parmetros en pila, etc.

2. Con -O2 conseguimos todas las optimizaciones de -O1 ms mejoras en el abastecimiento de instrucciones al procesador, optimizaciones con respecto al retardo ocasionado al obtener datos del heap o de la memoria, etc.

3. Con -O3 conseguimos todas las optimizaciones de -O2 ms el desenrollado de bucles y otras prestaciones muy vinculadas con el tipo de procesador.

Si queremos tener un control total acerca de las opciones de optimizacin empleadas podremos utilizar la opcin -f:

-ffastmath: genera optimizaciones sobre las operaciones de coma flotante, en ocasiones saltndose restricciones de estndares IEEE o ANSI.

-finline-functions: expande todas las funciones inline durante la compilacin.

-funroll-loops: desenrolla todos los bucles, convirtindolos en una secuencia de instrucciones. Se gana en velocidad a costa de aumentar el tamao del cdigo.

DEBUGGINGLos errores de programacin o bugs son nuestros compaeros de viaje a la hora de programar cualquier cosa. Es muy comn programar cualquier aplicacin sencillsima y que por alguna mgica razn no funcione correctamente, o lo haga slo en determinadas ocasiones (esto desespera an ms). Por ello, muchas veces tenemos que hacer debugging, ir a la caza y captura de nuestros bugs. La manera ms ruin de buscar fallos todos la conocemos (aunque muchas veces nos d vergenza reconocerlo), en lugar de pelearnos con debuggers, llenar el cdigo de llamadas a printf() sacando resultados intermedios es lo ms divertido. En muchas ocasiones hacemos de ello un arte y utilizamos variables de preprocesado para indicar qu parte del cdigo es de debug y cul no. Para indicar una variable de preprocesado en GCC se utiliza la opcin -D:gcc DDEBUG prueba.c o pruebaSi queremos optar por una alternativa ms profesional, quiz convenga utilizar las opciones -g o -ggdb para generar informacin extra de debug en nuestro ejecutable y poder seguir de forma ms cmoda su ejecucin mediante el GDB (GNU Debugger).Si deseamos obtener todas las posibles advertencias en cuanto a generacin del ejecutable partiendo de nuestro cdigo fuente, emplearemos -Wall, para solicitar todos los warnings en los que incurra nuestro cdigo. As mismo, podramos utilizar la opcin -ansi o -pedantic para tratar de acercar nuestros programas al estndar ANSI C.MAKE WORLDHemos visto en el anterior apartado cmo el desarrollo de un programa puede involucrar muchos ficheros diferentes, con opciones de compilacin muy diversas y complejas. Esto podra convertir la programacin de herramientas que involucren varios ficheros en un verdadero infierno. Sin embargo, make permite gestionar la compilacin y creacin de ejecutables, aliviando a los programadores de stas tareas.Con make deberemos definir solamente una vez las opciones de compilacin de cada mdulo o programa. El resto de llamadas sern sencillas gracias a su funcionamiento mediante reglas de compilacin. Adems, make es capaz de llevar un control de los cambios que ha habido en los ficheros fuente y ejecutables y optimiza el proceso de edicin-compilacin-depuracin evitando recompilar los mdulos o programas que no han sido modificados.MAKEFILE, EL GUIN DE MAKELos Makefiles son los ficheros de texto que utiliza make para llevar la gestin de la compilacin de programas. Se podran entender como los guiones de la pelcula que quiere hacer make, o la base de datos que informa sobre las dependencias entre las diferentes partes de un proyecto.Todos los Makefiles estn ordenados en forma de reglas, especificando qu es lo que hay que hacer para obtener un mdulo en concreto. El formato de cada una de esas reglas es el siguiente:

objetivo : dependencias

comandos

En objetivo definimos el mdulo o programa que queremos crear, despus de los dos puntos y en la misma lnea podemos definir qu otros mdulos o programas son necesarios para conseguir el objetivo. Por ltimo, en la lnea siguiente y sucesivas indicamos los comandos necesarios para llevar esto a cabo. Es muy importante que los comandos estn separados por un tabulador de el comienzo de lnea. Algunos editores como el mcedit cambian los tabuladores por 8 espacios en blanco, y esto hace que los Makefiles generados as no funcionen. Un ejemplo de regla podra ser el siguiente:

juego : ventana.o motor.o bd.o

gcc O2 c juego.c o juego.o

gcc O2 juego.o ventana.o motor.o bd.o o juegoPara crear juego es necesario que se hayan creado ventana.o, motor.o y bd.o (tpicamente habr una regla para cada uno de esos ficheros objeto en ese mismo Makefile).

En los siguientes apartados analizaremos un poco ms a fondo la sintaxis de los Makefiles.

Comentarios en Makefiles

Los ficheros Makefile pueden facilitar su comprensin mediante comentarios. Todo lo que est escrito desde el carcter # hasta el final de la lnea ser ignorado por make. Las lneas que comiencen por el carcter # sern tomadas a todos los efectos como lneas en blanco.Es bastante recomendable hacer uso de comentarios para dotar de mayor claridad a nuestros Makefiles. Podemos incluso aadir siempre una cabecera con la fecha, autor y nmero de versin del fichero, para llevar un control de versiones ms eficiente.Variables

Es muy habitual que existan variables en los ficheros Makefile, para facilitar su portabilidad a diferentes plataformas y entornos. La forma de definir una variable es muy sencilla, basta con indicar el nombre de la variable (tpicamente en maysculas) y su valor, de la siguiente forma:CC = gcc O2

Cuando queramos acceder al contenido de esa variable, lo haremos as:

$(CC) juego.c o juego

Es necesario tener en cuenta que la expansin de variables puede dar lugar a problemas de expansiones recursivas infinitas, por lo que a veces se emplea esta sintaxis:

CC := gcc

CC := $(CC) O2

Empleando := en lugar de = evitamos la expansin recursiva y por lo tanto todos los problemas que pudiera acarrear.

Adems de las variables definidas en el propio Makefile, es posible hacer uso de las variables de entorno, accesibles desde el intrprete de comandos. Esto puede dar pie a formulaciones de este estilo:

SRC = $(HOME)/src

juego :

gcc $(SCR)/*.c o juego

Un tipo especial de variables lo constituyen las variables automticas, aquellas que se evalan en cada regla. A m, personalmente, me recuerdan a los parmetros de un script. En la siguiente tabla tenemos una lista de las ms importantes:

VARIABLEDESCRIPCIN

$@Se sustituye por el nombre del objetivo de la presente regla.

$*Se sustituye por la raz de un nombre de fichero.

$