Cómo colocar archivos objeto en un subdirectorio separado


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

Obtengo la siguiente salida de make: make: * * * No hay regla para hacer target ku.h', needed byobj/kumain.o'. Dejar.

Sin embargo ku.h es una dependencia no un objetivo (aunque obviamente #está incluido dentro de la c archivos fuente). Cuando no intento usar un subdirectorio para los archivos objeto (es decir, pierdo las partes de OBJDIR) funciona bien. ¿Por qué hace pensar ku.h es un objetivo?

Mi makefile 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: He aplicado 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 salida:

    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 objeto, aunque el manual dice "Las reglas implícitas le dicen a make cómo usar las técnicas habituales para que no tengas que especificarlas en detalle cuando quieras usarlas. Por ejemplo, hay una regla implícita para la compilación en C. Los nombres de archivo determinan qué reglas implícitas se ejecutan. Por ejemplo, la compilación C normalmente toma a .c archivo y hace a .o archivo. Así que make aplica la regla implícita para la compilación en C cuando ve esta combinación de terminaciones de nombres de archivo."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 (véase Usar reglas implícitas)."

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

Cualquier ayuda para conseguir que las reglas implícitas funcionen para mi makefile sería muy apreciada.

Editar no 2: Gracias a Jack Kelly he hecho una regla explícita para compilar el .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 de 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)
Author: jww, 2011-03-03

6 answers

Ya que está usando GNUmake, use una regla de patrón para compilar archivos objeto:

$(OBJDIR)/%.o: %.c
    $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
 58
Author: Jack Kelly,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-04 00:56:53

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

Permite poner archivos fuente, encabezados y archivos en línea en subcarpetas, y subcarpetas de subcarpetas y así sucesivamente, y generará automáticamente un archivo de dependencia para cada objeto Esto significa que la modificación de encabezados y archivos en línea activará la recompilación de archivos que son dependientes.

Los archivos fuente se detectan a través del comando shell find, por lo que no es necesario especificar explícitamente, solo mantener codificando al contenido de sus corazones.

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

Para proporcionar crédito donde se debe, la función de auto-dependencias se basó en gran medida 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
 39
Author: Nicholas Hamilton,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-09-18 17:33:30

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

vpath %.c  src
vpath %.h  src

Es decir, no capital y sin el = . Como es ahora, no encuentra el .h archivo y piensa que es un objetivo a ser hecho.

 22
Author: al_miro,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-03 08:24:25

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 fuentes, no para objetos.

Echa un vistazo a estos dos enlaces para obtener más explicaciones y una solución "inteligente".

 4
Author: Theo Belaire,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-05-22 15:11:29

La siguiente solución no es agradable en mi opinión, ya que realmente me encantan las reglas integradas. Sin embargo, GNU make no soporta 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 incorporadas que puede obtener, y por lo tanto, a mi mejor conocimiento, la mejor solución que es disponible.

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

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

Además, si $(OBJDIR) solo contendría archivos gererados automáticamente, podría crearlos sobre la marcha con un requisito previo de solo orden, haciendo que la regla limpia sea un poco más simple: {[16]]}

$(OBJDIR):
        mkdir -p $(OBJDIR)

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

.PHONY: clean
clean:
        $(RM) -r $(OBJDIR)

Esto requiere que la función solo para pedidos esté disponible, que puede verificar usando $(filter order-only, $(.FETAURES)). He comprobado Kubuntu 14.04 GNU make 3.81 y openSUSE 13.1 GNU make 3.82. Ambos fueron construidos con habilitado solo para pedidos, y ahora me queda 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 make 4.1 ahora:)

 2
Author: Christian Hujer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-10-06 12:19:05

Para todos aquellos que trabajan con reglas implícitas (y GNU MAKE). Aquí hay un makefile simple que soporta 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)

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

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

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

Mediante 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 carpeta objetos nuevos, el se añade la ruta 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: Haga la documentación. Véase el capítulo 10.2

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

 1
Author: A. Frank,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-21 11:06:51