2009-09-02 6 views
9

Tengo un proyecto pequeño de C++ usando GNU Make. Me gustaría ser capaz de convertir los siguientes archivos de origen:Salida de estructura de directorio de archivos de objeto plano con GNU Make

src/ 
    a.cpp 
    b/ 
    b.cpp 
    c/ 
    c.cpp 

en la siguiente estructura de salida (no estoy preocupado por duplicados en este punto):

build/ 
    a.o 
    b.o 
    c.o 

Hasta ahora tengo los siguientes, que por desgracia pone el .oy .d uno al lado del .cpp:

OBJS   :=  $(foreach file,$(SRCS),$(file).o) 
DEPS   :=  $(patsubst %.o,%.d,$(OBJS)) 
sinclude $(DEPS) 

$(OBJS) : %.o : %.cpp 
     @echo Compiling $< 
     $(CC) $(CC_FLAGS) $(INCS) -MMD -o [email protected] $< 

soy consciente de la (notdir ...) la función $, pero en este momento mis esfuerzos para usarlo para filtrar los objetos ha fallado. ¿Alguien puede arrojar algo de luz sobre esto? Parece algo bastante razonable de hacer.

Respuesta

8

Existen al menos dos formas de hacerlo. Primero (y lo que recomendaría) es que puede agregar el directorio de compilación a los nombres de destino (incluso cuando se usa una regla de patrón). Por ejemplo:

$(OBJS) : build/%.o : %.cpp 

En segundo lugar, puede utilizar la variable VPATH para decirle hacer para buscar un directorio diferente para requisitos previos. Este es probablemente el enfoque más común (sobre) usado. Tiene al menos un inconveniente serio, y es que si lo haces y luego te encuentras con problemas con "duplicados", no hay forma de resolver el problema. Con el primer enfoque, siempre puede reflejar la estructura del directorio fuente debajo del directorio de compilación para evitar duplicados.

Editar: Mi respuesta anterior fue un poco escasa de detalles, por lo que voy a ampliarla para mostrar que esto realmente funciona como se anuncia. Aquí hay un ejemplo de trabajo completo Makefile que usa la primera técnica descrita arriba para resolver el problema. Simplemente pegue esto en un Makefile y ejecute make - hará el resto y mostrará que esto de hecho funciona.

Editar: No puedo encontrar la manera de obtener SO para permitir caracteres de tabulación en mi texto de respuesta (los reemplazó por espacios). Después de copiar y pegar este ejemplo, deberá convertir los espacios iniciales en las secuencias de comando en pestañas.

BUILD_DIR := build 

SRCS := \ 
    a.c \ 
    b.c \ 
    c.c \ 
    a/a.c \ 
    b/b.c \ 
    c/c.c 

OBJS := ${SRCS:%.c=${BUILD_DIR}/%.o} 

foo: ${OBJS} 
    @echo Linking [email protected] using $? 
    @touch [email protected] 

${BUILD_DIR}/%.o: %.c 
    @mkdir -p $(dir [email protected]) 
    @echo Compiling $< ... 
    @touch [email protected] 

${SRCS}: 
    @echo Creating [email protected] 
    @mkdir -p $(dir [email protected]) 
    @touch [email protected] 

.PHONY: clean 
clean: 
    rm -f foo 
    rm -f ${OBJS} 

En particular, tenga en cuenta que existen archivos de origen con nombres duplicados (A.C. y/A.C., b.c y B/b.c, etc) y que esto no causa ningún problema. También tenga en cuenta que no hay uso de VPATH, que recomiendo evitar utilizar debido a sus limitaciones inherentes.

+0

Ok, usando este enfoque probablemente necesitaría una regla adicional para crear subcarpetas dentro de la carpeta de salida? – Justicle

+0

Terminé yendo por esta ruta, ya que necesitaba crear carpetas de compilación específicas de destino y configuración de todos modos, era fácil agregar otro par de carpetas al paso "compilar carpetas". ¡Gracias! – Justicle

+0

Una regla separada para las carpetas de compilación debería funcionar bien. Lo que normalmente hago, solo es agregar una línea "@mkdir -p $ (dir $ @)" al script de comandos para crear el directorio de salida (si no existe) como parte de hacer el archivo de objeto (s). –

2
vpath %.cpp src src/b src/c 

A continuación, consulte los archivos de origen sin su nombre de directorio; Haga buscará en el vpath.

1

Creando la estructura de directorio plana como se solicitó inicialmente.

Utiliza vpath para rastrear los archivos de origen, pero todas las tareas se realizan automágicamente desde la lista SRC.

SRC = a/a.c a/aa.c b/b.c 
TARGET = done 

FILES = $(notdir $(SRC)) 
#make list of source paths, sort also removes duplicates 
PATHS = $(sort $(dir $(SRC))) 

BUILD_DIR = build 
OBJ = $(addprefix $(BUILD_DIR)/, $(FILES:.c=.o)) 
DEP = $(OBJ:.o=.d) 

# default target before includes 
all: $(TARGET) 

include $(DEP) 

vpath %.c $(PATHS) 

# create dummy dependency files to bootstrap the process 
%.d: 
    echo a=1 >[email protected] 

$(BUILD_DIR)/%.o:%.c 
    echo [email protected]: $< > $(patsubst %.o,%.d,[email protected]) 
    echo $< >[email protected] 

$(TARGET): $(OBJ) 
    echo $^ > [email protected] 

.PHONY: clean 
clean: 
    del $(BUILD_DIR)/*.o 
    del $(BUILD_DIR)/*.d 

Lo siento por los feos echo 's, pero yo sólo tenía mi caja victoria para probarlo en.

0

Es posible que no particularmente como este enfoque, pero:

AUTOMAKE_OPTIONS = 

hace el truco bastante bien en un Makefile.am. Solo digo que no necesitas escribir todo a mano.

1

Esto es para Win32 mingw32-make. funciona. La parte más importante es

-mkdir $(patsubst %/,%,$(dir [email protected]))

para Win32. Necesitamos quitar el trailing/for win32.

GENERATED_DIRS = a b 

# Dependency generator function 
mkdir_deps =$(foreach dir,$(GENERATED_DIRS),$(dir)/.mkdir.done) 

# Target rule to create the generated dependency. 
# And create the .mkdir.done file for stop continuous recreate the dir 
%/.mkdir.done: # target rule 
    -mkdir $(patsubst %/,%,$(dir [email protected])) 
    echo $(patsubst %/,%,$(dir [email protected])) >[email protected] 

all: $(mkdir_deps) 
    @echo Begin 

clean: 
    @echo Cleaning 
Cuestiones relacionadas