utilizar para makeopts make fichero existe entre directorio diferencia create crear con compilar como makefile object directory

para - makefile 112 makeopts no existe el fichero o el directorio



Crear directorios usando make file (8)

Acabo de presentar una solución bastante razonable que te permite definir los archivos para construir y hacer que los directorios se creen automáticamente. Primero, defina una variable ALL_TARGET_FILES que contenga el nombre de archivo de cada archivo que se generará en su archivo MAKE. Luego usa el siguiente código:

define depend_on_dir $(1): | $(dir $(1)) ifndef $(dir $(1))_DIRECTORY_RULE_IS_DEFINED $(dir $(1)): mkdir -p $$@ $(dir $(1))_DIRECTORY_RULE_IS_DEFINED := 1 endif endef $(foreach file,$(ALL_TARGET_FILES),$(eval $(call depend_on_dir,$(file))))

Así es como funciona. depend_on_dir una función depend_on_dir que toma un nombre de archivo y genera una regla que hace que el archivo dependa del directorio que lo contiene y luego define una regla para crear ese directorio si es necesario. Luego uso foreach para call esta función en cada nombre de archivo y eval el resultado.

Tenga en cuenta que necesitará una versión de GNU make que admita eval , que creo que es la versión 3.81 y superior.

Soy muy nuevo en makefiles y quiero crear directorios usando makefile. Mi directorio de proyectos es así

+--Project +--output +--source +Testfile.cpp +Makefile

Quiero poner todos los objetos y la salida en la carpeta de salida respectiva. Quiero crear una estructura de carpetas que sería así después de compilar.

+--Project +--output +--debug (or release) +--objs +Testfile.o +Testfile (my executable file) +--source +Testfile.cpp +Makefile

Intenté con varias opciones, pero no pude tener éxito. Por favor, ayúdame a hacer directorios usando make file. Estoy publicando mi Makefile para su consideración.

#--------------------------------------------------------------------- # Input dirs, names, files #--------------------------------------------------------------------- OUTPUT_ROOT := output/ TITLE_NAME := TestProj ifdef DEBUG TITLE_NAME += _DEBUG else ifdef RELEASE TITLE_NAME += _RELEASE endif endif # Include all the source files here with the directory tree SOURCES := / source/TestFile.cpp / #--------------------------------------------------------------------- # configs #--------------------------------------------------------------------- ifdef DEBUG OUT_DIR := $(OUTPUT_ROOT)debug CC_FLAGS := -c -Wall else ifdef RELEASE OUT_DIR := $(OUTPUT_ROOT)release CC_FLAGS := -c -Wall else $(error no build type defined) endif endif # Put objects in the output directory. OUT_O_DIR := $(OUT_DIR)/objs #--------------------------------------------------------------------- # settings #--------------------------------------------------------------------- OBJS = $(SOURCES:.cpp=.o) DIRS = $(subst /,/,$(sort $(dir $(OBJS)))) DIR_TARGET = $(OUT_DIR) OUTPUT_TARGET = $(OUT_DIR)/$(TITLE_NAME) CC_FLAGS += LCF_FLAGS := LD_FLAGS := #--------------------------------------------------------------------- # executables #--------------------------------------------------------------------- MD := mkdir RM := rm CC := g++ #--------------------------------------------------------------------- # rules #--------------------------------------------------------------------- .PHONY: all clean title all: title clean: $(RM) -rf $(OUT_DIR) $(DIR_TARGET): $(MD) -p $(DIRS) .cpp.o: @$(CC) -c $< -o $@ $(OBJS): $(OUT_O_DIR)/%.o: %.cpp @$(CC) -c $< -o $@ title: $(DIR_TARGET) $(OBJS)

Gracias por adelantado. Por favor guíame si cometí algún error también.


En mi opinión, los directorios no deben considerarse objetivos de su archivo MAKE, ya sea en términos técnicos o de diseño. Debe crear archivos y si la creación de un archivo necesita un nuevo directorio, cree silenciosamente el directorio dentro de la regla para el archivo relevante.

Si tiene como objetivo un archivo normal o "modelado", simplemente use la variable interna de make $(@D) , que significa "el directorio donde reside el objetivo actual" (cmp. Con $@ para el destino). Por ejemplo,

$(OUT_O_DIR)/%.o: %.cpp @mkdir -p $(@D) @$(CC) -c $< -o $@ title: $(OBJS)

Entonces, efectivamente haces lo mismo: creas directorios para todos $(OBJS) , pero lo harás de una manera menos complicada.

La misma política (los archivos son objetivos, los directorios nunca lo son) se usa en diversas aplicaciones. Por ejemplo, el sistema de control de revisiones git no almacena directorios.

Nota: Si va a usarlo, puede ser útil introducir una variable de conveniencia y utilizar las reglas de expansión de make .

dir_guard=@mkdir -p $(@D) $(OUT_O_DIR)/%.o: %.cpp $(dir_guard) @$(CC) -c $< -o $@ $(OUT_O_DIR_DEBUG)/%.o: %.cpp $(dir_guard) @$(CC) -g -c $< -o $@ title: $(OBJS)


Esto lo haría, suponiendo un entorno tipo Unix.

MKDIR_P = mkdir -p .PHONY: directories all: directories program directories: ${OUT_DIR} ${OUT_DIR}: ${MKDIR_P} ${OUT_DIR}

Esto debería ejecutarse en el directorio de nivel superior, o la definición de $ {OUT_DIR} debería ser correcta en relación con el lugar donde se ejecuta. Por supuesto, si sigue los edictos del documento " Recursive Make Considered Harmful " de Peter Miller, entonces ejecutará make en el directorio de nivel superior de todos modos.

Estoy jugando con esto (RMCH) en este momento. Necesitaba un poco de adaptación al paquete de software que estoy usando como campo de pruebas. La suite tiene una docena de programas separados construidos con fuente distribuida en 15 directorios, algunos de ellos compartidos. Pero con un poco de cuidado, se puede hacer. OTOH, podría no ser apropiado para un novato.

Como se señaló en los comentarios, enumerar el comando ''mkdir'' como acción para ''directorios'' es incorrecto. Como también se señaló en los comentarios, existen otras maneras de corregir el error ''no sé cómo hacer la salida / depurar''. Una es eliminar la dependencia en la línea de ''directorios''. Esto funciona porque ''mkdir -p'' no genera errores si ya existen todos los directorios que se le pide que cree. El otro es el mecanismo que se muestra, que solo intentará crear el directorio si no existe. La versión ''enmendada'' es lo que tenía en mente anoche, pero ambas técnicas funcionan (y ambas tienen problemas si existe salida / eliminación de fallas, pero es un archivo en lugar de un directorio).


La independencia del sistema operativo es crítica para mí, por lo que mkdir -p no es una opción. Creé esta serie de funciones que usan eval para crear destinos de directorio con el requisito previo en el directorio padre. Esto tiene el beneficio que make -j 2 que make -j 2 funcione sin problemas ya que las dependencias se determinan correctamente.

# convenience function for getting parent directory, will eventually return ./ # $(call get_parent_dir,somewhere/on/earth/) -> somewhere/on/ get_parent_dir=$(dir $(patsubst %/,%,$1)) # function to create directory targets. # All directories have order-only-prerequisites on their parent directories # https://www.gnu.org/software/make/manual/html_node/Prerequisite-Types.html#Prerequisite-Types TARGET_DIRS:= define make_dirs_recursively TARGET_DIRS+=$1 $1: | $(if $(subst ./,,$(call get_parent_dir,$1)),$(call get_parent_dir,$1)) mkdir $1 endef # function to recursively get all directories # $(call get_all_dirs,things/and/places/) -> things/ things/and/ things/and/places/ # $(call get_all_dirs,things/and/places) -> things/ things/and/ get_all_dirs=$(if $(subst ./,,$(dir $1)),$(call get_all_dirs,$(call get_parent_dir,$1)) $1) # function to turn all targets into directories # $(call get_all_target_dirs,obj/a.o obj/three/b.o) -> obj/ obj/three/ get_all_target_dirs=$(sort $(foreach target,$1,$(call get_all_dirs,$(dir $(target))))) # create target dirs create_dirs=$(foreach dirname,$(call get_all_target_dirs,$1),$(eval $(call make_dirs_recursively,$(dirname)))) TARGETS := w/h/a/t/e/v/e/r/things.dat w/h/a/t/things.dat all: $(TARGETS) # this must be placed after your .DEFAULT_GOAL, or you can manually state what it is # https://www.gnu.org/software/make/manual/html_node/Special-Variables.html $(call create_dirs,$(TARGETS)) # $(TARGET_DIRS) needs to be an order-only-prerequisite w/h/a/t/e/v/e/r/things.dat: w/h/a/t/things.dat | $(TARGET_DIRS) echo whatever happens > $@ w/h/a/t/things.dat: | $(TARGET_DIRS) echo whatever happens > $@

Por ejemplo, ejecutar lo anterior creará:

$ make mkdir w/ mkdir w/h/ mkdir w/h/a/ mkdir w/h/a/t/ mkdir w/h/a/t/e/ mkdir w/h/a/t/e/v/ mkdir w/h/a/t/e/v/e/ mkdir w/h/a/t/e/v/e/r/ echo whatever happens > w/h/a/t/things.dat echo whatever happens > w/h/a/t/e/v/e/r/things.dat


O, KISS.

DIRS=build build/bins ... $(shell mkdir -p $(DIRS))

Esto creará todos los directorios después de que se haya analizado Makefile.


Todas las soluciones, incluida la aceptada, tienen algunos problemas como se indica en sus respectivos comentarios. La respuesta aceptada por @ jonathan-leffler ya es bastante buena, pero no tiene en cuenta que los requisitos previos no deben construirse necesariamente en orden (durante make -j por ejemplo). Sin embargo, simplemente mover el requisito previo de all los directories para program provoca reconstrucciones en cada ejecución AFAICT. La siguiente solución no tiene ese problema y AFAICS funciona según lo previsto.

MKDIR_P := mkdir -p OUT_DIR := build .PHONY: directories all clean all: $(OUT_DIR)/program directories: $(OUT_DIR) $(OUT_DIR): ${MKDIR_P} $(OUT_DIR) $(OUT_DIR)/program: | directories touch $(OUT_DIR)/program clean: rm -rf $(OUT_DIR)


dado que eres un novato, yo diría que no trates de hacer esto todavía. definitivamente es posible, pero complicará innecesariamente tu Makefile. mantén las formas simples hasta que te sientas más cómodo con make.

dicho esto, una forma de compilar en un directorio diferente al directorio de origen es VPATH ; prefiero reglas de patrones


make in, y off itself, maneja los destinos del directorio de la misma manera que los objetivos del archivo. Por lo tanto, es fácil escribir reglas como esta:

outDir/someTarget: Makefile outDir touch outDir/someTarget outDir: mkdir -p outDir

El único problema con eso es que la marca de tiempo de los directorios depende de lo que se hace a los archivos dentro. Para las reglas anteriores, esto lleva al siguiente resultado:

$ make mkdir -p outDir touch outDir/someTarget $ make touch outDir/someTarget $ make touch outDir/someTarget $ make touch outDir/someTarget

Esto definitivamente no es lo que quieres. Cada vez que toca el archivo, también toca el directorio. Y dado que el archivo depende del directorio, el archivo, en consecuencia, parece estar desactualizado, lo que obliga a reconstruirlo.

Sin embargo, puede romper fácilmente este ciclo diciendo a make que ignore la marca de tiempo del directorio . Esto se hace declarando el directorio como un prerrequisito de solo orden:

# The pipe symbol tells make that the following prerequisites are order-only # | # v outDir/someTarget: Makefile | outDir touch outDir/someTarget outDir: mkdir -p outDir

Esto cede correctamente:

$ make mkdir -p outDir touch outDir/someTarget $ make make: ''outDir/someTarget'' is up to date.

TL; DR:

Escribe una regla para crear el directorio:

$(OUT_DIR): mkdir -p $(OUT_DIR)

Y los objetivos para el contenido interno dependen de la orden de directorio solo:

$(OUT_DIR)/someTarget: ... | $(OUT_DIR)