linux - comando - Makefiles con archivos fuente en diferentes directorios
comando makefile linux (9)
Creo que es mejor señalar que el uso de Make (recursivo o no) es algo que generalmente querrás evitar, porque comparado con las herramientas de hoy en día, es difícil de aprender, mantener y escalar.
Es una herramienta maravillosa, pero su uso directo debe considerarse obsoleto en 2010+.
A menos que, por supuesto, trabaje en un entorno especial, es decir, con un proyecto heredado, etc.
Use un IDE, CMake o, si tiene núcleo duro, las Autotools .
(editado debido a los votos a la baja, ty Honza por señalar)
Tengo un proyecto donde la estructura del directorio es así:
$projectroot
|
+---------------+----------------+
| | |
part1/ part2/ part3/
| | |
+------+-----+ +---+----+ +---+-----+
| | | | | | |
data/ src/ inc/ src/ inc/ src/ inc/
¿Cómo debería escribir un archivo MAKE que sería en parte / src (o donde realmente) que podría comple / link en los archivos fuente c / c ++ en parte? / Src?
¿Puedo hacer algo como -I $ projectroot / part1 / src -I $ projectroot / part1 / inc -I $ projectroot / part2 / src ...
Si eso funcionara, ¿hay alguna manera más fácil de hacerlo? ¿He visto proyectos en los que hay un archivo MAKE en cada una de las partes correspondientes? carpetas. [en este post utilicé el signo de interrogación como en la sintaxis de bash]
La forma tradicional es tener un Makefile
en cada uno de los subdirectorios ( part1
, part2
, etc.) que le permite construirlos de forma independiente. Además, tenga un Makefile
en el directorio raíz del proyecto que crea todo. El Makefile
"raíz" se parecería a lo siguiente:
all:
+$(MAKE) -C part1
+$(MAKE) -C part2
+$(MAKE) -C part3
Dado que cada línea en un objetivo de fabricación se ejecuta en su propio shell, no hay necesidad de preocuparse por atravesar una copia de seguridad del árbol de directorios o de otros directorios.
Sugiero echar un vistazo a la sección 5.7 del manual de creación de GNU ; es de mucha ayuda.
La opción de VPATH puede ser útil, lo que le indica a qué directorios buscar el código fuente. Sin embargo, todavía necesitarías una opción -I para cada ruta de inclusión. Un ejemplo:
CXXFLAGS=-Ipart1/inc -Ipart2/inc -Ipart3/inc
VPATH=part1/src:part2/src:part3/src
OutputExecutable: part1api.o part2api.o part3api.o
Esto buscará automáticamente los archivos partXapi.cpp coincidentes en cualquiera de los directorios especificados de VPATH y los compilará. Sin embargo, esto es más útil cuando su directorio src está dividido en subdirectorios. Por lo que describes, como han dicho otros, probablemente estés mejor con un archivo MAKE para cada parte, especialmente si cada parte puede ser independiente.
La publicación de RC fue SUPER útil. Nunca pensé en usar la función $ (dir $ @), pero hizo exactamente lo que necesitaba.
En parentDir, tenga un grupo de directorios con archivos fuente en ellos: dirA, dirB, dirC. Varios archivos dependen de los archivos objeto en otros directorios, así que quería poder hacer un archivo desde un directorio y hacer que esa dependencia llame al archivo MAKE asociado con esa dependencia.
Esencialmente, hice un Makefile en parentDir que tenía (entre muchas otras cosas) una regla genérica similar a la de RC:
%.o : %.cpp @mkdir -p $(dir $@) @echo "=============" @echo "Compiling $<" @$(CC) $(CFLAGS) -c $< -o $@
Cada subdirectorio incluía este archivo MAKE de nivel superior para heredar esta regla genérica. En el Makefile de cada subdirectorio, escribí una regla personalizada para cada archivo para poder realizar un seguimiento de todo lo que dependía de cada archivo individual.
Cuando necesité hacer un archivo, utilicé (esencialmente) esta regla para hacer recursivamente cualquier / todas las dependencias. ¡Perfecto!
NOTA: hay una utilidad llamada "makepp" que parece hacer esta misma tarea aún más intuitivamente, pero por el bien de la portabilidad y no dependiendo de otra herramienta, elegí hacerlo de esta manera.
¡Espero que esto ayude!
Puede agregar reglas a su raíz Makefile para compilar los archivos cpp necesarios en otros directorios. El siguiente ejemplo de Makefile debería ser un buen comienzo para llevarte a donde quieres estar.
CC=g++ TARGET=cppTest OTHERDIR=../../someotherpath/in/project/src SOURCE = cppTest.cpp SOURCE = $(OTHERDIR)/file.cpp ## End sources definition INCLUDE = -I./ $(AN_INCLUDE_DIR) INCLUDE = -I.$(OTHERDIR)/../inc ## end more includes VPATH=$(OTHERDIR) OBJ=$(join $(addsuffix ../obj/, $(dir $(SOURCE))), $(notdir $(SOURCE:.cpp=.o))) ## Fix dependency destination to be ../.dep relative to the src dir DEPENDS=$(join $(addsuffix ../.dep/, $(dir $(SOURCE))), $(notdir $(SOURCE:.cpp=.d))) ## Default rule executed all: $(TARGET) @true ## Clean Rule clean: @-rm -f $(TARGET) $(OBJ) $(DEPENDS) ## Rule for making the actual target $(TARGET): $(OBJ) @echo "=============" @echo "Linking the target $@" @echo "=============" @$(CC) $(CFLAGS) -o $@ $^ $(LIBS) @echo -- Link finished -- ## Generic compilation rule %.o : %.cpp @mkdir -p $(dir $@) @echo "=============" @echo "Compiling $<" @$(CC) $(CFLAGS) -c $< -o $@ ## Rules for object files from cpp files ## Object file for each file is put in obj directory ## one level up from the actual source directory. ../obj/%.o : %.cpp @mkdir -p $(dir $@) @echo "=============" @echo "Compiling $<" @$(CC) $(CFLAGS) -c $< -o $@ # Rule for "other directory" You will need one per "other" dir $(OTHERDIR)/../obj/%.o : %.cpp @mkdir -p $(dir $@) @echo "=============" @echo "Compiling $<" @$(CC) $(CFLAGS) -c $< -o $@ ## Make dependancy rules ../.dep/%.d: %.cpp @mkdir -p $(dir $@) @echo "=============" @echo Building dependencies file for $*.o @$(SHELL) -ec ''$(CC) -M $(CFLAGS) $< | sed "s^$*.o^../obj/$*.o^" > $@'' ## Dependency rule for "other" directory $(OTHERDIR)/../.dep/%.d: %.cpp @mkdir -p $(dir $@) @echo "=============" @echo Building dependencies file for $*.o @$(SHELL) -ec ''$(CC) -M $(CFLAGS) $< | sed "s^$*.o^$(OTHERDIR)/../obj/$*.o^" > $@'' ## Include the dependency files -include $(DEPENDS)
Si las fuentes están distribuidas en muchas carpetas, y tiene sentido tener Makefiles individuales, como se sugirió antes, recursive make es un buen enfoque, pero para proyectos más pequeños me resulta más fácil enumerar todos los archivos fuente en el Makefile con su ruta relativa al Makefile así:
# common sources
COMMON_SRC := ./main.cpp /
../src1/somefile.cpp /
../src1/somefile2.cpp /
../src2/somefile3.cpp /
Entonces puedo configurar VPATH
esta manera:
VPATH := ../src1:../src2
Luego construyo los objetos:
COMMON_OBJS := $(patsubst %.cpp, $(ObjDir)/%$(ARCH)$(DEBUG).o, $(notdir $(COMMON_SRC)))
Ahora la regla es simple:
# the "common" object files
$(ObjDir)/%$(ARCH)$(DEBUG).o : %.cpp Makefile
@echo creating $@ ...
$(CXX) $(CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<
Y construir la salida es aún más fácil:
# This will make the cbsdk shared library
$(BinDir)/$(OUTPUTBIN): $(COMMON_OBJS)
@echo building output ...
$(CXX) -o $(BinDir)/$(OUTPUTBIN) $(COMMON_OBJS) $(LFLAGS)
Incluso se puede automatizar la generación de VPATH
la VPATH
:
VPATH := $(dir $(COMMON_SRC))
O usando el hecho de que sort
elimina los duplicados (aunque no debería importar):
VPATH := $(sort $(dir $(COMMON_SRC)))
Si tiene un código en un subdirectorio que depende del código en otro subdirectorio, probablemente esté mejor con un solo archivo MAKE en el nivel superior.
Vea Recursive Make Harmedful para la explicación completa, pero básicamente desea que tenga la información completa que necesita para decidir si un archivo necesita ser reconstruido o no, y no tendrá eso si solo le dice que es un tercio de tu proyecto.
El enlace de arriba parece no ser alcanzable. El mismo documento es accesible aquí:
Sugiero usar autotools
:
//##
Coloque los archivos de objetos generados (.o) en el mismo directorio que sus archivos fuente, para evitar colisiones cuando se usa make no recursivo.
AUTOMAKE_OPTIONS = subdir-objects
simplemente incluyéndolo en Makefile.am
con las otras cosas bastante simples.
Aquí está el tutorial .
all:
+$(MAKE) -C part1
+$(MAKE) -C part2
+$(MAKE) -C part3
Esto permite dividir en trabajos y usar múltiples núcleos