Cundo iniciamos un proyecto de programacion es comun que nos baste con un simple g++ *.cpp para compilar nuestro codigo de forma rapida, pero conforme el numero de fuentes crece es necesario usar algo que nos permita recompilar solo el codigo que se ve afectado con los cambios a los fuentes realizados y no todos los fuentes, esto se logra usando make y el archivo makefile. Por lo general al ejecutar make solo hace uso de un core en las compilaciones, si se cuenta con un equipo con varios cores se pueden usar todos ellos para hacer mas rapida la compilacion, usar $ make -j n donde el valor optimo de n se puede encontrar variando N; para medir el tiempo de compilacion usar el comando: $ time make -j 2 Este nos permite tener las interdependencias de nuestro codigo especificadas para que solo recompile aquello que sea requerido, su estructura basica es: ==================================================================== # Inicio del makefile # Indicar el compilador CC=g++ # Indicar las opciones del compilador CFLAGS=-c -Wall all: test # indicar que se liga y el nombre del ejecutable test: ejem.o A.o B.o $(CC) ejem.o A.o B.o -o test # opciones de compilacion por cada fuente ejem.o: ejem.cpp $(CC) $(CFLAGS) ejem.cpp A.o: A.cpp $(CC) $(CFLAGS) A.cpp B.o: B.cpp $(CC) $(CFLAGS) B.cpp # Permite borrar los archivos generados clean: rm -rf *o test # fin de makefile ==================================================================== Uso basico de Make: Para compilar $ make Para borrar los archivos generados por la compilacion $ make clean Nota: Para que funcione el makefile despues de una regla debe de usarse tabulador para indicar la accion, no funciona si solo se usan espacios. Pero que pasa si nuestro proyecto crece y crece el numero de archivos fuente, entonces usar este esquema puede ser engorroso de mantener, una opcion es usar un makefile generico, y que sea este mismo makefile el encargado de llevar la cuenta de los fuentes y las dependencias entre los mismos. Para ello podemos usar: ==================================================================== # Inicio de makefile # Defining the sources SOURCES = $(wildcard *.cpp) # Parameters of executable PARAMETERS = file test # Defining the neme of th executable EXECUTABLE = ressim # Defining the debug Flags DEBUG = -g -pg -Wall # Debuger # Defining the compiler Flags CFLAGS = -MD -c $(DEBUG) # Defining the linker Flags LDFLAGS = -lm $(DEBUG) # Defining the compiler: CC = g++ # Defining the object files: OBJECTS = $(SOURCES:.cpp=.o) # Load the automatic dependency DEPS = $(patsubst %.o,%.d,$(OBJECTS)) # target: all - The default rule - compiling our main program: all: $(SOURCES) $(EXECUTABLE) echo all: make complete $(EXECUTABLE): $(OBJECTS) $(CC) $(LDFLAGS) $(OBJECTS) -o $@ # Tell make how to build .o files from .cpp files: $(OBJECTS): $(CC) $(CFLAGS) $(@:.o=.cpp) -o $@ #Now make sure that make rebuilds files if included headers change: -include $(DEPS) # target: deps - Automatic dependency calculation deps: $(SOURCES) $(CC) -MD -E $(SOURCES) > /dev/null # The .PHONY rule keeps make from doing something with a file named clean .PHONY: clean # target: clean - Removing the executable and the object files clean: rm $(EXECUTABLE) $(OBJECTS) $(DEPS) gmon.out echo clean: make complete # target: run - Run the application run: ./$(EXECUTABLE) $(PARAMETERS) # Fin de makefile ==================================================================== Uso basico de Make: Para generar dependencias de los fuentes $ make deps Para compilar $ make Para ejecutar $ make run Para borrar los archivos generados por la compilacion $ make clean Este makefile soporta una amplia configuracion y es reusable en proyectos de C y C++, ademas se puede extender para soportar varias actividades rutinarias en el manejo de nuestro proyecto, como son compactar en distintos formatos (como tar, tar.gz, tar.bz2, zip), usar subversion o depurar con ddd y valgrind, etc. Angunas opciones son: # target: gz - Store in tar.gz gz: tar -zcvpf $(EXECUTABLE)-`date "+%F"`.tar.gz makefile *.?pp # target: bz2 - Store in tar.bz2 bz2: tar -jcvpf $(EXECUTABLE)-`date "+%F"`.tar.bz2 makefile *.?pp # target: tar - Store in tar tar: tar -cvpf $(EXECUTABLE)-`date "+%F"`.tar makefile *.?pp # target: zip - Store in zip zip: zip $(EXECUTABLE)-`date "+%F"`.zip makefile *.?pp # target: ddd - Debuger with ddd, required DEBUG = -g ddd: ddd $(EXECUTABLE) # target: val - Debuger with valgrind, required DEBUG = -g val: valgrind --tool=memcheck --leak-check=yes --show-reachable=yes \ ./$(EXECUTABLE) $(PARAMETERS) # target: gpro - Analysis of speedup, required DEBUG = -g -pg gpro: ./$(EXECUTABLE) $(PARAMETERS) gprof -c -z $(EXECUTABLE) # target: svnup - svn update svnup: svn update # target: svnst - svn status svnst: svn status --verbose # target: svnci - svn commit svnci: svn ci -m "Update" De esta forma es posible tener un makefile flexible y poderoso para usarse en multiples proyectos de desarrollo de software con un minimo de cambios Nota: Una version de makefile para programacion secuencial y otro paralela se pone en este directorio, pero recuerde que para el funcionamiento de make, es necesario respetar los caracteres tabulador en las acciones del makefile. ------------------------------------------------------------------------------------------------------- Algo de linux: http://www.mmc.geofisica.unam.mx/acl/linux/ Antonio Carrillo Ledesma http://www.mmc.geofisica.unam.mx/acl/