¡Descarga Guía para la creación de un proyecto Makefile en C++ y más Ejercicios en PDF de Ingeniería Infórmatica solo en Docsity! Primera Sesión de Prácticas Metodología de la Programación Doble Grado en Ingeniería Informática y Matemáticas David Pelta – Manuel Gómez Olmedo Curso 2013 - 2014 Indice • Explicación introductoria (sólo atender): – Pasos previos: preparación estructura directorios – Programa simple: “Hola Mundo” – Modularización – Compilación separada – Conceptos básicos de la utilidad Make • Ejercicio personal (usando el guión adicional) Primer paso Cada paso que veamos se hará sobre un directorio diferente. Al final, en el directorio ~/mp/sesion1 debemos tener: - holaMundo - demo1 - demo2 - demo3 - demo4 - demo5 Dentro de cada uno de ellos veremos la estructura de directorios indicada: bin, doc, include, lib, obj y src Programa simple • Con tu editor favorito (tipo texto plano (kwriter, gedit, …)), escribe un programa del tipo “Hola Mundo” y guárdalo en la carpeta src. ¡LO HARÉIS DESPUÉS! #include <iostream> using namespace std; int main(){ cout << "\n Hola Mundo \n"; } Programa simple • Guía de estilo: no usar nunca espacios en blanco en los nombres de los archivos • Nombres de variables: consecuentes con el estilo (o subrayados separando palabras o bien palabras juntas y mayúscula a principio de palabra: util_vector, utilVector, …). Pero siempre la misma nomenclatura. Programa simple #include <iostream> using namespace std; int main(){ // Sangrado adecuado cout << "\n Hola Mundo \n"; // Sangrado incorrecto int x=3; if ( x > 2){ // La sentencia interna deberia // indentarse a la derecha x=5; } } Está bien 3 espacios por nivel de indentación • Comando general para compilar desde línea de comando para un ejecutable a partir de un único archivo de código • Opción –o: cómo se llama el ejecutable Compilación g++ -o nombre-ejecutable nombre-fuente Compilación • Compilar y ejecutar nuestro ejemplo (dos comandos; asumimos estamos en ~/mp/sesion1/holaMundo): • Introduce errores en HolaMundo.cpp y observa la salida del compilador (después, al trabajar con el guión) > g++ -o bin/HolaMundo src/HolaMundo.cpp > ./bin/HolaMundo Modularización Objetivo: organizar mejor el código en módulos (archivos) separados. Así el código es más fácil de mantener, organizar, etc Problema: se hace más laboriosa la generación del ejecutable a partir de módulos separados. Modularización Primer paso: organizar el código de un único archivo de forma que las funciones puedan usarse en cualquier lugar, incluso antes de su declaración. El ejemplo siguiente muestra cómo se consigue. Modularización (primer paso) src/demo1.cpp #include <iostream> int suma (int a, int b) { return a + b; } int resta (int a, int b) { return a - b; } int multiplica (int a, int b) { return a * b; } int divide (int a, int b) { return a / b; } using namespace std; int main (){ int a, b; cout << "Introduce el primer valor: "; cin >> a; cout << "Introduce el segundo valor: "; cin >> b; cout << "suma = " << suma(a,b) << endl; cout << "resta = " << resta(a,b) << endl; cout << "multiplica = " << multiplica(a,b) << endl; cout << "divide = " << divide(a,b) << endl; return 0; } src/demo1.cpp #include <iostream> int suma (int a, int b); int resta (int a, int b); int multiplica (int a, int b); int divide (int a, int b); using namespace std; int main (){ int a, b; cout << "Introduce el primer valor: "; cin >> a; cout << "Introduce el segundo valor: "; cin >> b; cout << "suma = " << suma(a,b) << endl; cout << "resta = " << resta(a,b) << endl; cout << "multiplica = " << multiplica(a,b) << endl; cout << "divide = " << divide(a,b) << endl; return 0; } int suma (int a, int b) { return a + b; } int resta (int a, int b) { return a - b; } int multiplica (int a, int b) { return a * b; } int divide (int a, int b) { return a / b; } ¿ Como quitar esto de aquí ? Concepto de Módulo Por módulo podemos entender: • Una función. • Un fichero (que contiene varias funciones y datos). • Un TDA (Tipo de Dato Abstracto). • Una biblioteca (conjunto de ficheros y/o funciones y/o datos). • Un namespace (agrupamiento lógico de funciones y datos). Módulo Cuando se construyen programas grandes, las funciones y estructuras de datos se dividen y agrupan, según su uso, en múltiples ficheros y bibliotecas. Cada módulo suele tener: –Interfaz de acceso al módulo (parte pública) –Implementación del módulo (parte privada). Tener varios ficheros permite: –La compilación separada –Facilita la construcción y el mantenimiento de los programas –Facilita el trabajo en equipo Módulo Interfaz (parte pública) • Debe ser conocida por cualquiera que desee usar el módulo. • Se escribe en los ficheros de cabecera (.h) • Contenido: #define públicos, Prototipos de funciones, Definición de tipos públicos (struct, class, typedef, enum, …) Implementación (parte privada) • Sólo conocida por el programador o diseñador del módulo. • Se escribe en los ficheros de implementación (.cpp) • Contenido: la implementación de lo que se ha declarado en la parte pública e implementaciones privadas. La parte privada se transformará en un fichero objeto, o bien una biblioteca. Compilación • Se necesita el codigo objeto de cada fichero fuente. • Opción –c del compilador: sólo compila • Hacer g++ -c –o obj/demo2.o src/demo2.cpp • Observard el error por no encontrar el archivo de cabecera • Hacer g++ -c –o obj/demo2.o src/demo2.cpp –I./include g++ -c –o obj/oper2.o src/oper2.cpp –I./include g++ -o bin/demo2 obj/demo2.o obj/oper2.o demo2.cpp demo2.o oper2.cpp oper2.o oper2.h demo2 g++ -c -o g++ -c -o g++ -o (ld) Construcción de una biblioteca • Una biblioteca es un fichero que agrupa un conjunto de ficheros objeto (.o) • En el ejemplo anterior el módulo se transformaba en código objeto que luego se enlazaba con el programa principal. • Veamos como incluir el módulo en una biblioteca. • El esquema necesario es ahora: Construccion de una biblioteca • La extensión por defecto de los ficheros de biblioteca es .a, y suelen comenzar con la palabra lib. • Nuestra biblioteca – se llamará liboper2.a – la guardaremos en el directorio lib. – contendrá un solo fichero objeto oper2.o • Las bibliotecas se crean con el programa ar ar rvs lib/liboper2.a obj/oper2.o Parámetros del programa Primer Cambio
Modificación de trigo.cpp
o ejemplo
trigo.h include
math.h
mates.h Hñnclude rt
compila Puan ejemplo.cpp
mates.cpp A gompiar
ompilar m
DN ejemplo.o
mates.o
enlazar
Agruparen
biblioteca
Segundo Cambio
Modificación de trigo.h
Agrupar en
biblioteca
Tercer Cambio
Modificación de ejemplo.cpp —-o ejemplo.o
.0 -=o ejemplo
Hinclud trigo.h include
math.h
trigo.cpp j
mates. h *tinclude
compila: ftinclude
mates.cpp
Ngonptar
trigo.o mates.o Za? libm.a
Agruparen
biblioteca
Ejecución • El fichero makefile lo guardamos en la carpeta base de la práctica. • Luego ejecutamos make y automaticamente intentará construir el destino all. • También podemos indicar make all • No es necesario que el fichero se llame makefile • • Si utilizamos otro nombre, por ej. misReglas entonces haremos make –f misReglas Versión con Libreria #fichero miMake all : bin/demo2 bin/demo2 : obj/demo2.o lib/liboper2.a g++ -o bin/demo2 obj/demo2.o -L./lib -loper2 obj/demo2.o : src/demo2.cpp include/oper2.h g++ -c -I./include -o obj/demo2.o src/demo2.cpp obj/oper2.o : src/oper2.cpp include/oper2.h g++ -c -I./include -o obj/oper2.o src/oper2.cpp lib/liboper2.a: obj/oper2.o @echo construyendo libreria ar rvs lib/liboper2.a obj/oper2.o clean: rm obj/*.o make –f miMake make –f miMake clean Más posibilidades #fichero miMake2 INCLUDE = ./include LIB = ./lib OBJ = ./obj SRC = ./src all : $(BIN)/demo2 $(BIN)/demo2 : $(OBJ)/demo2.o $(LIB)/liboper2.a g++ -o $(BIN)/demo2 $(OBJ)/demo2.o -L$(LIB) -loper2 $(OBJ)/demo2.o : src/demo2.cpp include/oper2.h g++ -c -I$(INCLUDE) -o $(OBJ)/demo2.o $(SRC)/demo2.cpp $(OBJ)/oper2.o : src/oper2.cpp include/oper2.h g++ -c -I$(INCLUDE) -o $(OBJ)/oper2.o $(SRC)/oper2.cpp $(LIB)/liboper2.a: $(OBJ)/oper2.o @echo construyendo libreria ar rvs $(LIB)/liboper2.a $(OBJ)/oper2.o clean : rm $(OBJ)/*.o Macros para los nombres de directorios