Cómo colocar los archivos de objetos en subdirectorio separado

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#Rerequisite-Types

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

Sin embargo, ku.h es una dependencia, no un objective (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 objective?

mi archivo MAKE es este: (el estilo es después de leer varias fonts 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 comstackción C. Los nombres de archivo determinan qué reglas implícitas se ejecutan. Por ejemplo, la comstackción C normalmente toma un archivo .c y crea un archivo .o. Así que make aplica la regla implícita para la comstackció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 comstackr 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 comstackció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 comstackr 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) 

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

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

Este es el archivo MAKE que utilizo 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 recomstackció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 AQUÍ , 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 

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 objective que se debe crear.

En general, debe especificar $(OBJDIR) en el lado izquierdo de todas las reglas que colocan archivos en $(OBJDIR) , o puede ejecutar make desde $(OBJDIR) . VPATH es para fonts, no para objetos.

Eche un vistazo a estos dos enlaces para obtener más explicaciones y una solución “inteligente”.

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 🙂

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 (eg 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 comstackdor 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 progtwigción