tutorial make create makefile gnu-make

makefile - make - Cómo colocar los archivos de objetos en subdirectorio separado



makefile linux c (6)

Como está utilizando GNUmake, use una regla de patrón para compilar archivos de objeto:

$(OBJDIR)/%.o: %.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<

Tengo problemas para tratar de usar make para colocar archivos de objetos en un subdirectorio separado, probablemente una técnica muy básica. He tratado de usar la información en esta página: http://www.gnu.org/software/hello/manual/make/Prerequisite-Types.html#Prerequisite-Types

Obtengo el siguiente resultado de make: make: *** No hay regla para hacer objetivo ku.h'', needed by obj / kumain.o''. Detener.

Sin embargo, ku.h es una dependencia, no un objetivo (aunque es obviamente #incluido dentro de los c archivos de origen). Cuando no trato de usar un subdirectorio para archivos de objeto (es decir, me pierdo las partes OBJDIR), funciona bien. ¿Por qué hacer pensar que ku.h es un objetivo?

mi archivo MAKE es este: (el estilo es después de leer varias fuentes de información)

.SUFFIXES: .SUFFIXES: .c .o CC=gcc CPPFLAGS=-Wall LDLIBS=-lhpdf VPATH=%.c src VPATH=%.h src VPATH=%.o obj OBJDIR=obj objects= $(addprefix $(OBJDIR)/, kumain.o kudlx.o kusolvesk.o kugetpuz.o kuutils.o / kurand.o kuASCboard.o kuPDFs.o kupuzstrings.o kugensud.o / kushapes.o ) ku : $(objects) $(CC) $(CPPFLAGS) -o ku $(objects) $(LDLIBS) $(objects) : ku.h kudefines.h kuglobals.h kufns.h | $(OBJDIR) $(OBJDIR): mkdir $(OBJDIR) .PHONY: clean clean : rm $(objects)

Editar: apliqué el cambio para usar la directiva vpath. Mi versión era una mala mezcla de VPATH = xxx y vpath% .c xxx. Sin embargo ahora tengo otro problema (que era el problema original antes de agregar el vpath incorrecto). Este es ahora el resultado:

gcc -o ku -lhpdf obj/kumain.o obj/kudlx.o obj/kusolvesk.o ..etc gcc: obj/kumain.o: No such file or directory gcc: obj/kudlx.o: No such file or directory gcc: obj/kusolvesk.o: No such file or directory gcc: obj/kugetpuz.o: No such file or directory gcc: obj/kuutils.o: No such file or directory gcc: obj/kurand.o: No such file or directory gcc: obj/kuASCboard.o: No such file or directory gcc: obj/kuPDFs.o: No such file or directory gcc: obj/kupuzstrings.o: No such file or directory gcc: obj/kugensud.o: No such file or directory gcc: obj/kushapes.o: No such file or directory make: *** [ku] Error 1

Parece que make no está aplicando la regla implícita para un archivo de objeto aunque el manual dice "Las reglas implícitas indican cómo usar las técnicas habituales para que no tenga que especificarlas en detalle cuando desee usarlas. Por ejemplo, es una regla implícita para la compilación C. Los nombres de archivo determinan qué reglas implícitas se ejecutan. Por ejemplo, la compilación C normalmente toma un archivo .c y crea un archivo .o. Así que make aplica la regla implícita para la compilación C cuando ve esta combinación de nombre de archivo finales. " y también "La búsqueda a través de los directorios especificados en VPATH o con vpath también ocurre durante la consideración de reglas implícitas (ver Uso de reglas implícitas)".

De nuevo aquí "Por ejemplo, cuando un archivo foo.o no tiene una regla explícita, make considera reglas implícitas, como la regla incorporada para compilar foo.c si ese archivo existe. Si falta ese archivo en el directorio actual, haga se buscan los directorios apropiados. Si foo.c existe (o se menciona en el archivo MAKE) en cualquiera de los directorios, se aplica la regla implícita para la compilación C. "

Cualquier ayuda para lograr que las reglas implícitas funcionen para mi archivo MAKE sería muy apreciada.

Edit no 2: Gracias a Jack Kelly he hecho una regla explícita para compilar los archivos .c ya que no pude llegar a ninguna parte tratando de usar reglas implícitas. También gracias a al_miro por la información vpath.

Aquí está el makfile de trabajo:

.SUFFIXES: .SUFFIXES: .c .o CC=gcc CPPFLAGS=-Wall LDLIBS=-lhpdf OBJDIR=obj vpath %.c src vpath %.h src objects = $(addprefix $(OBJDIR)/, kumain.o kudlx.o kusolvesk.o kugetpuz.o kuutils.o / kurand.o kuASCboard.o kuPDFs.o kupuzstrings.o kugensud.o / kushapes.o ) ku : $(objects) $(CC) $(CPPFLAGS) -o ku $(objects) $(LDLIBS) $(OBJDIR) obj/%.o : %.c ku.h kudefines.h kuglobals.h kufns.h $(CC) -c $(CPPFLAGS) $< -o $@ .PHONY : clean clean : rm $(objects)



Este es el archivo MAKE que uso para la mayoría de mis proyectos,

Permite colocar archivos de origen, encabezados y archivos en línea en subcarpetas y subcarpetas de subcarpetas y demás, y generará automáticamente un archivo de dependencia para cada objeto. Esto significa que la modificación de encabezados y archivos en línea desencadenará la recompilación de archivos que son dependientes.

Los archivos de origen se detectan a través del comando shell find, por lo que no es necesario especificarlo explícitamente, solo debe seguir codificando según el contenido de su corazón.

También copiará todos los archivos de una carpeta de ''recursos'', en la carpeta bin cuando se compile el proyecto, que me resulta útil la mayor parte del tiempo.

Para proporcionar crédito donde corresponde, la función de autodependencias se basó principalmente en la página de Scott McPeak que se puede encontrar HERE , con algunas modificaciones / ajustes adicionales para mis necesidades.

Ejemplo Makefile

#Compiler and Linker CC := g++-mp-4.7 #The Target Binary Program TARGET := program #The Directories, Source, Includes, Objects, Binary and Resources SRCDIR := src INCDIR := inc BUILDDIR := obj TARGETDIR := bin RESDIR := res SRCEXT := cpp DEPEXT := d OBJEXT := o #Flags, Libraries and Includes CFLAGS := -fopenmp -Wall -O3 -g LIB := -fopenmp -lm -larmadillo INC := -I$(INCDIR) -I/usr/local/include INCDEP := -I$(INCDIR) #--------------------------------------------------------------------------------- #DO NOT EDIT BELOW THIS LINE #--------------------------------------------------------------------------------- SOURCES := $(shell find $(SRCDIR) -type f -name *.$(SRCEXT)) OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:.$(SRCEXT)=.$(OBJEXT))) #Defauilt Make all: resources $(TARGET) #Remake remake: cleaner all #Copy Resources from Resources Directory to Target Directory resources: directories @cp $(RESDIR)/* $(TARGETDIR)/ #Make the Directories directories: @mkdir -p $(TARGETDIR) @mkdir -p $(BUILDDIR) #Clean only Objecst clean: @$(RM) -rf $(BUILDDIR) #Full Clean, Objects and Binaries cleaner: clean @$(RM) -rf $(TARGETDIR) #Pull in dependency info for *existing* .o files -include $(OBJECTS:.$(OBJEXT)=.$(DEPEXT)) #Link $(TARGET): $(OBJECTS) $(CC) -o $(TARGETDIR)/$(TARGET) $^ $(LIB) #Compile $(BUILDDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(SRCEXT) @mkdir -p $(dir $@) $(CC) $(CFLAGS) $(INC) -c -o $@ $< @$(CC) $(CFLAGS) $(INCDEP) -MM $(SRCDIR)/$*.$(SRCEXT) > $(BUILDDIR)/$*.$(DEPEXT) @cp -f $(BUILDDIR)/$*.$(DEPEXT) $(BUILDDIR)/$*.$(DEPEXT).tmp @sed -e ''s|.*:|$(BUILDDIR)/$*.$(OBJEXT):|'' < $(BUILDDIR)/$*.$(DEPEXT).tmp > $(BUILDDIR)/$*.$(DEPEXT) @sed -e ''s/.*://'' -e ''s///$$//'' < $(BUILDDIR)/$*.$(DEPEXT).tmp | fmt -1 | sed -e ''s/^ *//'' -e ''s/$$/:/'' >> $(BUILDDIR)/$*.$(DEPEXT) @rm -f $(BUILDDIR)/$*.$(DEPEXT).tmp #Non-File Targets .PHONY: all remake clean cleaner resources


La siguiente solución no es agradable en mi opinión, ya que realmente amo las reglas integradas. Sin embargo, GNU make no es compatible con algo como vpath para los directorios de salida. Y las reglas incorporadas no pueden coincidir, ya que el % en %.o coincidiría con obj/foo de obj/foo.o , dejando make con una búsqueda en vpath %.c src/ para cosas como src/obj/foo.c , pero no src/foo.c

Pero esto es lo más cercano a las reglas integradas que puede obtener, y por lo tanto, para mi mejor conocimiento, es la mejor solución disponible.

$(OBJDIR)/%.o: %.c $(COMPILE.c) $(OUTPUT_OPTION) $<

Explicación: $(COMPILE.c) $(OUTPUT_OPTION) $< realidad es cómo se implementa .co , vea http://git.savannah.gnu.org/cgit/make.git/tree/default.c (y es incluso mencionado en el manual)

Además, si $(OBJDIR) solo contendría archivos autogererated, podría crearlo sobre la marcha con un requisito previo solo de pedido, simplificando la regla de limpieza:

$(OBJDIR): mkdir -p $(OBJDIR) $(OBJDIR)/%.o: %.c | $(OBJDIR) $(COMPILE.c) $(OUTPUT_OPTION) $< .PHONY: clean clean: $(RM) -r $(OBJDIR)

Esto requiere que solo esté disponible la función de orden , que puede verificar usando $(filter order-only, $(.FETAURES)) . Revisé Kubuntu 14.04 GNU make 3.81 y OpenSUSE 13.1 GNU make 3.82. Ambos fueron creados con solo el pedido habilitado, y ahora me deja perplejo por qué Kubuntu 14.04 viene con una versión anterior de GNU make que OpenSUSE 13.1. De todos modos, voy a descargar hacer 4.1 ahora :)


Las líneas de VPATH son incorrectas, deberían ser

vpath %.c src vpath %.h src

es decir, no capital y sin el =. Tal como está ahora, no encuentra el archivo .h y piensa que es un objetivo que se debe crear.


Para todos aquellos que trabajan con reglas implícitas (y GNU MAKE). Aquí hay un archivo make simple que admite diferentes directorios:

#Start of the makefile VPATH = ./src:./header:./objects OUTPUT_OPTION = -o objects/$@ CXXFLAGS += -Wall -g -I./header Target = $(notdir $(CURDIR)).exe Objects := $(notdir $(patsubst %.cpp,%.o,$(wildcard src/*.cpp))) all: $(Target) $(Target): $(Objects) $(CXX) $(CXXFLAGS) -o $(Target) $(addprefix objects/,$(Objects)) #Beware of -f. It skips any confirmation/errors (e.g. file does not exist) .PHONY: clean clean: rm -f $(addprefix objects/,$(Objects)) $(Target)

Veamos más de cerca (me referiré al Directorio actual con curdir):

Esta línea se usa para obtener una lista de los archivos .o utilizados que están en curdir / src.

Objects := $(notdir $(patsubst %.cpp,%.o,$(wildcard src/*.cpp))) #expands to "foo.o myfoo.o otherfoo.o"

A través de la variable, la salida se establece en un directorio diferente (curdir / objects).

OUTPUT_OPTION = -o objects/$@ #OUTPUT_OPTION will insert the -o flag into the implicit rules

Para asegurarse de que el compilador encuentra los objetos en la nueva carpeta de objetos, la ruta se agrega al nombre del archivo.

$(Target): $(Objects) $(CXX) $(CXXFLAGS) -o $(Target) $(addprefix objects/,$(Objects)) # ^^^^^^^^^^^^^^^^^^^^

Esto se entiende como un ejemplo y definitivamente hay margen de mejora.

Para información adicional consultar: Hacer documentación. Ver el capítulo 10.2

O: Oracle: Guía de utilidades de programación