Skip to content

Dependencias en los makefiles

6 agosto 2010

Saludos veraniegos. Con la calor, es difícil acordarse de todas las dependencias de cada fichero, y a menudo se nos escapan algunas al escribir nuestro Makefile. Mi compañero David me comentó la existencia de makedepend, una herramienta para la gestión automática de dependencias que había visto de refilón en algún makefile ajeno pero que apenas conocía.

Leyendo su entrada en Wikipedia y algunos comentarios en StackOverflow, vi que actualmente se desaconseja su uso, prefiriéndose las alternativas que la mayoría de compiladores ofrecen de forma nativa. Así fue como conocí la opción -MM de gcc, cuyo cometido es el mismo que el de makedepend: generar, en formato makefile, una lista de dependencias para cada fichero, basándose en las cabeceras incluidas. El funcionamiento es sencillo:

gcc -MM $(CXXFLAGS) ficherosFuente

Es importante pasarle las flags de compilación, ya que suelen incluir directivas como -I, que indican las carpetas en las que buscar ficheros de cabecera.

Problema 1: utilización de las dependencias generadas

La utilidad makedepend automáticamente actualizaba el makefile que la ejecutaba, añadiendo al final del fichero las dependencias generadas. Sin embargo, gcc -MM muestra su resultado en la salida estándar (o en un fichero que indiquemos), en lugar de añadirlo al Makefile actual, por lo que había que buscar una forma de incluir el resultado en nuestro Makefile. Con utilizar

-include dependencias.dep

Podremos incluir cualquier fichero en nuestro Makefile como parte del mismo.

Problema 2: rutas en el fichero generado

En mi caso, tengo tres carpetas que cuelgan de la raíz del proyecto: src, obj e include, en las que se guardan los cpp, los ficheros objeto y las cabeceras respectivamente. El problema de gcc -MM es que, al generar las dependencias, quita la ruta de la cabecera de las reglas, esto es, si tenemos un fichero objeto obj/main.o que depende de main.cpp, en el fichero generado aparecería así:

main.o: src/main.cpp

Por ahora, la única solución que he encontrado es utilizar sed para añadir al inicio la ruta correspondiente, aunque me habría gustado que gcc incluyera una opción al respecto.

gcc -MM $(CXXFLAGS) $(shell ls -t $(SRCDIR)/*.cpp) | sed 's/^\([a-zA-Z]\+.o:\)/$(OBJDIR)\/\1/g' > $(DEPFILE)

La explicación de la expresión regular es muy sencilla: Simplemente, cada vez que encuentre al inicio de la línea el nombre de un fichero objeto, que añada el nombre del directorio de los objetos (OBJDIR) y luego el nombre del fichero. Se utilizan grupos, primero agrupando el nombre con paréntesis y luego haciendo referencia al grupo con \1.

Por último, comentar que he puesto como dependencia del binario final al archivo de dependencias, y como dependencia del archivo de dependencias (valga la redundancia) todos los ficheros de código. El objetivo es que, si modifico algún fichero de código, puede que los includes cambien, así que hay que regenerar las dependencias. Tal vez acabe quitando esta dependencia cruzada, ya que estar regenerando las dependencias constantemente es un rollo. Otra opción que tal vez baraje es la de tener un archivo de dependencias por cada fichero objeto, así la regeneración no será tan pesada.

Opciones hay muchas.

2 comentarios leave one →
  1. 6 agosto 2010 18:01

    Como ya te comenté, genial consejo te acabas de pegar. Yo me he hecho un objetivo más del cual depende el proyecto. Lo que ocurre es que no le he pasado las CXXFLAGS porque me metía en las dependencias decenas de ficheros (aunque fueran #include). Al final he metido sólo el que me interesa y me queda:

    gen_deps:
            @echo ''
            @echo -e '$(COLOR_AVISO)Generando dependencias$(COLOR_FIN)...'
            @gcc -MM -I$(HDRDIR) $(shell ls -t $(SRCDIR)/*.cpp) | sed 's/^\([a-zA-Z]\+.o:\)/$(OBJDIR)\/\1/g' > $(DEPFILE)
            @echo ''
    
  2. 6 agosto 2010 18:06

    El único problema es que sed no está en Windows…

    … o al menos no viene de serie, se puede encontrar aquí: http://gnuwin32.sourceforge.net/packages/sed.htm

    Perdón por la doble-respuesta😀

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: