2011-03-03 20 views
40

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 utilizar la información en esta página: http://www.gnu.org/software/hello/manual/make/Prerequisite-Types.html#Prerequisite-TypesCómo colocar archivos de objetos en un subdirectorio separado

me sale el siguiente salida de make: make: *** No hay ninguna regla para hacer diana 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, omito las partes OBJDIR), funciona bien. ¿Por qué hacer pensar que ku.h es un objetivo?

mi makefile es la siguiente: (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: solicité el cambio de utilizar 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). Esta es ahora la 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 hacen no está aplicando la regla implícita para un archivo objeto aunque el manual dice "Las reglas implícitas contadas por la gente cómo utilizar las técnicas habituales de modo que usted no tiene que especificar en detalle cuando desee usarlos. Por ejemplo, hay 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. make aplica la regla implícita para la compilación C cuando ve esta combinación de terminaciones de nombre 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 (ver Uso de reglas implícitas)".

Aquí de nuevo "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 dicho archivo en el directorio actual, los directorios apropiados se buscan. 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. "

Me agradecería cualquier ayuda para conseguir que las reglas implícitas funcionen para mi archivo MAKE.

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í es 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 [email protected] 

.PHONY : clean 
clean : 
    rm $(objects) 
+14

Estilo nota: '$ (CPPFLAGS)' se utiliza tradicionalmente para las banderas C preprocesador, mientras que '$ (CFLAGS)' se utiliza para banderas para el compilador. –

Respuesta

51

Dado que está utilizando gnumake, utiliza una regla patrón para la compilación de archivos de objetos:

$(OBJDIR)/%.o: %.c 
    $(CC) $(CFLAGS) $(CPPFLAGS) -c -o [email protected] $< 
+4

Esto no funciona para mí: busca $ (OBJDIR) /% .c y no% .c. ¿Alguna idea de cómo puedo conseguir que use archivos C en el directorio actual como dependencia mientras usa $ (OBJDIR) como destino? – Lelanthran

+0

@Lelanthran, la solución anterior para obtener archivos C se encuentra en el directorio actual. Si usa "$ (OBJDIR) /% .c" en lugar de "% .c", su código C debe ponerlo en "$ (OBJDIR)". – Neal

22

El VPATH líneas están equivocados, deben ser

vpath %.c src 
vpath %.h src 

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

4

En general, ya sea que tiene que especificar $(OBJDIR) en el lado izquierdo de todas las reglas que colocar archivos en $(OBJDIR) , o puede ejecutar make desde $(OBJDIR). VPATH es para fuentes, no para objetos.

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

+1

En realidad, esta es la mejor respuesta. Es curioso cómo tenía cero upvotes (antes que el mío), mientras que todos los intentos desesperados, incompletos, rotos, etc. lo tienen todo ...;) ¡Gracias, Theo B., me salvó algunas horas! –

2

La siguiente solución no es agradable en mi opinión, ya que me encanta las reglas incorporadas. Sin embargo, GNU make no es compatible con algo como vpath para los directorios de salida. Y las reglas incorporadas no pueden igualar, como el % en %.o coincidiría 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, a mi mejor saber la mejor solución disponible.

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

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

Además, si $(OBJDIR) sería solamente nunca contener archivos de auto-gererated, se podría crear en -the-volar con un requisito fin de sólo, por lo que la regla limpia un poco más sencillo:

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

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

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

Esto requiere que la función orden de sólo está disponible, 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 construidos con solo orden activado, y ahora me deja perplejo por qué Kubuntu 14.04 viene con una versión anterior de GNU make que OpenSUSE 13.1. De todas formas, va a hacer descarga 4.1 ahora :)

32

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

Se permite poner los archivos de origen, los encabezados y archivos en línea en subcarpetas y subcarpetas de subcarpetas y so- adelante, y generará automáticamente un archivo de dependencia para cada objeto Esto significa que la modificación de los encabezados y archivos en línea desencadenará la recompilación de los archivos que son dependientes.

Los archivos de origen se detectan a través del comando shell find, por lo que no hay necesidad de especificarlo explícitamente, solo siga codificando a su gusto.

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 es debido, la función de auto-dependencias se basa en gran medida fuera de la página de Scott McPeak que se pueden 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 [email protected]) 
    $(CC) $(CFLAGS) $(INC) -c -o [email protected] $< 
    @$(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 
+0

'mp' significa MacPorts. g ++ - mp-4.7 es compilador C++ de GCC para MacPorts –

1

Para todos los que trabajan con reglas implícitas (y hacer GNU). Aquí es un makefile simple que es compatible con diferentes directorios:

#Start of the makefile 

VPATH = ./src:./header:./objects 

OUTPUT_OPTION = -o objects/[email protected] 

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) 

Vamos a echar un vistazo más de cerca (me referiré al directorio actual con CurDir):

Esta línea se utiliza 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" 

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

OUTPUT_OPTION = -o objects/[email protected] 
#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 no es sin duda margen de mejora.

Para información adicional, consulte: Make documetation. See chapter 10.2

O: Oracle: Programming Utilities Guide

Cuestiones relacionadas