make instalar entre ejecutar diferencia como comando archivos makefile

instalar - Cómo generar un archivo Makefile con fuente en subdirectorios utilizando solo un archivo MAKE



makefile linux c (7)

Tengo una fuente en un grupo de subdirectorios como:

src/widgets/apple.cpp src/widgets/knob.cpp src/tests/blend.cpp src/ui/flash.cpp

En la raíz del proyecto quiero generar un solo archivo Makefile usando una regla como:

%.o: %.cpp $(CC) -c $< build/test.exe: build/widgets/apple.o build/widgets/knob.o build/tests/blend.o src/ui/flash.o $(LD) build/widgets/apple.o .... build/ui/flash.o -o build/test.exe

Cuando intento esto, no encuentra una regla para build / widgets / apple.o. ¿Puedo cambiar algo para que se use% .o:% .cpp cuando se necesita crear build / widgets / apple.o?


Aquí está mi solución, inspirada en la respuesta de Beta. Es más simple que las otras soluciones propuestas

Tengo un proyecto con varios archivos C, almacenados en muchos subdirectorios. Por ejemplo:

src/lib.c src/aa/a1.c src/aa/a2.c src/bb/b1.c src/cc/c1.c

Aquí está mi Makefile (en el directorio src/ ):

# make -> compile the shared library "libfoo.so" # make clean -> remove the library file and all object files (.o) # make all -> clean and compile SONAME = libfoo.so SRC = lib.c / aa/a1.c / aa/a2.c / bb/b1.c / cc/c1.c # compilation options CFLAGS = -O2 -g -W -Wall -Wno-unused-parameter -Wbad-function-cast -fPIC # linking options LDFLAGS = -shared -Wl,-soname,$(SONAME) # how to compile individual object files OBJS = $(SRC:.c=.o) .c.o: $(CC) $(CFLAGS) -c $< -o $@ .PHONY: all clean # library compilation $(SONAME): $(OBJS) $(SRC) $(CC) $(OBJS) $(LDFLAGS) -o $(SONAME) # cleaning rule clean: rm -f $(OBJS) $(SONAME) *~ # additional rule all: clean lib

Este ejemplo funciona bien para una biblioteca compartida, y debería ser muy fácil de adaptar para cualquier proceso de compilación.


Este es otro truco.

En el ''Makefile'' principal, defina SRCDIR para cada directorio de origen e incluya ''makef.mk'' para cada valor de SRCDIR. En cada directorio de origen, coloque el archivo ''files.mk'' con una lista de archivos de origen y opciones de compilación para algunos de ellos. En el principal ''Makefile'' uno puede definir opciones de compilación y excluir archivos para cada valor de SRCDIR.

Makefile:

PRG := prog-name OPTIMIZE := -O2 -fomit-frame-pointer CFLAGS += -finline-functions-called-once LDFLAGS += -Wl,--gc-section,--reduce-memory-overheads,--relax .DEFAULT_GOAL := hex OBJDIR := obj MK_DIRS := $(OBJDIR) SRCDIR := . include makef.mk SRCDIR := crc CFLAGS_crc := -DCRC8_BY_TABLE -DMODBUS_CRC_BY_TABLE ASFLAGS_crc := -DCRC8_BY_TABLE -DMODBUS_CRC_BY_TABLE include makef.mk ################################################################ CC := avr-gcc -mmcu=$(MCU_TARGET) -I. OBJCOPY := avr-objcopy OBJDUMP := avr-objdump C_FLAGS := $(CFLAGS) $(REGS) $(OPTIMIZE) CPP_FLAGS := $(CPPFLAGS) $(REGS) $(OPTIMIZE) AS_FLAGS := $(ASFLAGS) LD_FLAGS := $(LDFLAGS) -Wl,-Map,$(OBJDIR)/$(PRG).map C_OBJS := $(C_SRC:%.c=$(OBJDIR)/%.o) CPP_OBJS := $(CPP_SRC:%.cpp=$(OBJDIR)/%.o) AS_OBJS := $(AS_SRC:%.S=$(OBJDIR)/%.o) C_DEPS := $(C_OBJS:%=%.d) CPP_DEPS := $(CPP_OBJS:%=%.d) AS_DEPS := $(AS_OBJS:%=%.d) OBJS := $(C_OBJS) $(CPP_OBJS) $(AS_OBJS) DEPS := $(C_DEPS) $(CPP_DEPS) $(AS_DEPS) hex: $(PRG).hex lst: $(PRG).lst $(OBJDIR)/$(PRG).elf : $(OBJS) $(CC) $(C_FLAGS) $(LD_FLAGS) $^ -o $@ %.lst: $(OBJDIR)/%.elf -@rm $@ 2> /dev/nul $(OBJDUMP) -h -s -S $< > $@ %.hex: $(OBJDIR)/%.elf -@rm $@ 2> /dev/nul $(OBJCOPY) -j .text -j .data -O ihex $< $@ $(C_OBJS) : $(OBJDIR)/%.o : %.c Makefile $(CC) -MMD -MF [email protected] -c $(C_FLAGS) $(C_FLAGS_$(call clear_name,$<)) $< -o $@ @sed -e ''s,.*:,SRC_FILES += ,g'' < [email protected] > [email protected] @sed -e "/$$s/$$/ $(subst /,//,$(dir $<))files.mk/n/" < [email protected] >> [email protected] @sed -e ''s,^[^:]*: *,,'' -e ''s,^[ /t]*,,'' -e ''s, //$$,,'' -e ''s,$$, :,'' < [email protected] >> [email protected] -@rm -f [email protected] $(CPP_OBJS) : $(OBJDIR)/%.o : %.cpp Makefile $(CC) -MMD -MF [email protected] -c $(CPP_FLAGS) $(CPP_FLAGS_$(call clear_name,$<)) $< -o $@ @sed -e ''s,.*:,SRC_FILES += ,g'' < [email protected] > [email protected] @sed -e "/$$s/$$/ $(subst /,//,$(dir $<))files.mk/n/" < [email protected] >> [email protected] @sed -e ''s,^[^:]*: *,,'' -e ''s,^[ /t]*,,'' -e ''s, //$$,,'' -e ''s,$$, :,'' < [email protected] >> [email protected] -@rm -f [email protected] $(AS_OBJS) : $(OBJDIR)/%.o : %.S Makefile $(CC) -MMD -MF [email protected] -c $(AS_FLAGS) $(AS_FLAGS_$(call clear_name,$<)) $< -o $@ @sed -e ''s,.*:,SRC_FILES += ,g'' < [email protected] > [email protected] @sed -e "/$$s/$$/ $(subst /,//,$(dir $<))files.mk/n/" < [email protected] >> [email protected] @sed -e ''s,^[^:]*: *,,'' -e ''s,^[ /t]*,,'' -e ''s, //$$,,'' -e ''s,$$, :,'' < [email protected] >> [email protected] -@rm -f [email protected] clean: -@rm -rf $(OBJDIR)/$(PRG).elf -@rm -rf $(PRG).lst $(OBJDIR)/$(PRG).map -@rm -rf $(PRG).hex $(PRG).bin $(PRG).srec -@rm -rf $(PRG)_eeprom.hex $(PRG)_eeprom.bin $(PRG)_eeprom.srec -@rm -rf $(MK_DIRS:%=%/*.o) $(MK_DIRS:%=%/*.o.d) -@rm -f tags cscope.out # -rm -rf $(OBJDIR)/* # -rm -rf $(OBJDIR) # -rm $(PRG) tag: tags tags: $(SRC_FILES) if [ -e tags ] ; then ctags -u $? ; else ctags $^ ; fi cscope -U -b $^ # include dep. files ifneq "$(MAKECMDGOALS)" "clean" -include $(DEPS) endif # Create directory $(shell mkdir $(MK_DIRS) 2>/dev/null)

makef.mk

SAVE_C_SRC := $(C_SRC) SAVE_CPP_SRC := $(CPP_SRC) SAVE_AS_SRC := $(AS_SRC) C_SRC := CPP_SRC := AS_SRC := include $(SRCDIR)/files.mk MK_DIRS += $(OBJDIR)/$(SRCDIR) clear_name = $(subst /,_,$(1)) define rename_var $(2)_$(call clear_name,$(SRCDIR))_$(call clear_name,$(1)) := / $($(subst _,,$(2))_$(call clear_name,$(SRCDIR))) $($(call clear_name,$(1))) $(call clear_name,$(1)) := endef define proc_lang ORIGIN_SRC_FILES := $($(1)_SRC) ifneq ($(strip $($(1)_ONLY_FILES)),) $(1)_SRC := $(filter $($(1)_ONLY_FILES),$($(1)_SRC)) else ifneq ($(strip $(ONLY_FILES)),) $(1)_SRC := $(filter $(ONLY_FILES),$($(1)_SRC)) else $(1)_SRC := $(filter-out $(EXCLUDE_FILES),$($(1)_SRC)) endif endif $(1)_ONLY_FILES := $(foreach name,$($(1)_SRC),$(eval $(call rename_var,$(name),$(1)_FLAGS))) $(foreach name,$(ORIGIN_SRC_FILES),$(eval $(call clear_name,$(name)) :=)) endef $(foreach lang,C CPP AS, $(eval $(call proc_lang,$(lang)))) EXCLUDE_FILES := ONLY_FILES := SAVE_C_SRC += $(C_SRC:%=$(SRCDIR)/%) SAVE_CPP_SRC += $(CPP_SRC:%=$(SRCDIR)/%) SAVE_AS_SRC += $(AS_SRC:%=$(SRCDIR)/%) C_SRC := $(SAVE_C_SRC) CPP_SRC := $(SAVE_CPP_SRC) AS_SRC := $(SAVE_AS_SRC)

./files.mk

C_SRC := main.c CPP_SRC := AS_SRC := timer.S main.c += -DDEBUG

./crc/files.mk

C_SRC := byte-modbus-crc.c byte-crc8.c AS_SRC := modbus-crc.S crc8.S modbus-crc-table.S crc8-table.S byte-modbus-crc.c += --std=gnu99 byte-crc8.c += --std=gnu99


Esto hace el truco:

CC := g++ LD := g++ MODULES := widgets test ui SRC_DIR := $(addprefix src/,$(MODULES)) BUILD_DIR := $(addprefix build/,$(MODULES)) SRC := $(foreach sdir,$(SRC_DIR),$(wildcard $(sdir)/*.cpp)) OBJ := $(patsubst src/%.cpp,build/%.o,$(SRC)) INCLUDES := $(addprefix -I,$(SRC_DIR)) vpath %.cpp $(SRC_DIR) define make-goal $1/%.o: %.cpp $(CC) $(INCLUDES) -c $$< -o $$@ endef .PHONY: all checkdirs clean all: checkdirs build/test.exe build/test.exe: $(OBJ) $(LD) $^ -o $@ checkdirs: $(BUILD_DIR) $(BUILD_DIR): @mkdir -p $@ clean: @rm -rf $(BUILD_DIR) $(foreach bdir,$(BUILD_DIR),$(eval $(call make-goal,$(bdir))))

Este Makefile supone que tiene sus archivos de inclusión en los directorios de origen. También comprueba si existen los directorios de compilación y los crea si no existen.

La última línea es la más importante. Crea las reglas implícitas para cada construcción con la función make-goal , y no es necesario escribirlas una a una

También puede agregar generación automática de dependencias, usando la forma de Tromey


Esto lo hará sin manipulación dolorosa o secuencias de comandos múltiples:

build/%.o: src/%.cpp src/%.o: src/%.cpp %.o: $(CC) -c $&lt -o $@ build/test.exe: build/widgets/apple.o build/widgets/knob.o build/tests/blend.o src/ui/flash.o $(LD) $^ -o $@

JasperE ha explicado por qué "% .o:% .cpp" no funcionará; esta versión tiene una regla de patrón (% .o :) con comandos y sin prerrequisitos, y dos reglas de patrones (build /%. o: y src /%. o :) con prereqs y sin comandos. (Tenga en cuenta que puse la regla src /% .o para tratar con src / ui / flash.o, suponiendo que no era un error tipográfico para build / ui / flash.o, así que si no lo necesita puede déjalo afuera.)

build / test.exe necesita build / widgets / apple.o,
build / widgets / apple.o se ve como build /%. o, por lo que necesita src /%. cpp (en este caso src / widgets / apple.cpp),
build / widgets / apple.o también se ve como% .o, por lo que ejecuta el comando CC y usa los prereqs que acaba de encontrar (a saber, src / widgets / apple.cpp) para construir el destino (build / widgets / apple.o)


La cosa es $@ incluirá la ruta completa (relativa) al archivo fuente que a su vez se usa para construir el nombre del objeto (y por lo tanto su ruta relativa)

Usamos:

##################### # rules to build the object files $(OBJDIR_1)/%.o: %.c @$(ECHO) "$< -> $@" @test -d $(OBJDIR_1) || mkdir -pm 775 $(OBJDIR_1) @test -d $(@D) || mkdir -pm 775 $(@D) @-$(RM) $@ $(CC) $(CFLAGS) $(CFLAGS_1) $(ALL_FLAGS) $(ALL_DEFINES) $(ALL_INCLUDEDIRS:%=-I%) -c $< -o $@

Esto crea un directorio de objetos con el nombre especificado en $(OBJDIR_1) y subdirectorios de acuerdo con los subdirectorios en la fuente.

Por ejemplo (suponga objs como el directorio de objetos de nivel superior), en Makefile:

widget/apple.cpp tests/blend.cpp

resultados en el siguiente directorio de objetos:

objs/widget/apple.o objs/tests/blend.o


La razón es que tu regla

%.o: %.cpp ...

espera que el archivo .cpp resida en el mismo directorio que su edificio. Como test.exe en su caso depende de build / widgets / apple.o (etc), make espera que apple.cpp sea build / widgets / apple.cpp.

Puede usar VPATH para resolver esto:

VPATH = src/widgets BUILDDIR = build/widgets $(BUILDDIR)/%.o: %.cpp ...

Al intentar construir "build / widgets / apple.o", make buscará apple.cpp en VPATH . Tenga en cuenta que la regla de compilación debe usar variables especiales para acceder al nombre de archivo real make finds:

$(BUILDDIR)/%.o: %.cpp $(CC) $< -o $@

Donde "$ <" se expande a la ruta donde se ubica la primera dependencia.

También tenga en cuenta que esto construirá todos los archivos .o en compilación / widgets. Si quieres construir los binarios en diferentes directorios, puedes hacer algo como

build/widgets/%.o: %.cpp .... build/ui/%.o: %.cpp .... build/tests/%.o: %.cpp ....

Yo recomendaría que use " secuencias de comandos enlatados " para evitar repetir la regla de compilación del compilador real:

define cc-command $(CC) $(CFLAGS) $< -o $@ endef

A continuación, puede tener varias reglas como esta:

build1/foo.o build1/bar.o: %.o: %.cpp $(cc-command) build2/frotz.o build2/fie.o: %.o: %.cpp $(cc-command)


Usualmente, usted crea un Makefile en cada subdirectorio y escribe en el Makefile de nivel superior para hacer make en los subdirectorios.

Esta página puede ayudar: http://www.gnu.org/software/make/