을 생성하는 방법 Makefile 소스 하위 디렉토리에서만 사용하여 한 makefile

StackOverflow https://stackoverflow.com/questions/231229

  •  04-07-2019
  •  | 
  •  

문제

나는 소리의 하위 디렉터리와 같은:

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

의 루트에서 프로젝트를 생성하려는 단일 Makefile 을 사용하여 규칙은 다음과 같:

%.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

하려고 할 때 이것을 찾지 못한 규칙을 작성/위젯/애플입니다.o.을 바꿀 수 있도록%.o:%.cpp 사용이 필요할 때 확인을 구축/위젯/애플입니다.o?

도움이 되었습니까?

해결책

그 이유는 당신의 규칙입니다

%.o: %.cpp
       ...

.CPP 파일이 건물 .O와 동일한 디렉토리에 상주 할 것으로 기대합니다. 귀하의 경우 Test.exe는 Build/Widgets/Apple.o (etc)에 의존하기 때문에 Apple.cpp는 빌드/위젯/Apple.cpp가 될 것으로 기대합니다.

vpath를 사용하여 다음을 해결할 수 있습니다.

VPATH = src/widgets

BUILDDIR = build/widgets

$(BUILDDIR)/%.o: %.cpp
      ...

"빌드/위젯/apple.o"를 빌드하려고 할 때 Apple.cpp를 검색합니다. vpath에서. 빌드 규칙은 실제 파일 이름을 찾기 위해 특수 변수를 사용해야합니다.

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

여기서 "$ <"는 첫 번째 종속성을 위치시키는 경로로 확장됩니다.

또한 빌드/위젯에서 모든 .o 파일을 빌드합니다. 다른 디렉토리로 바이너리를 만들고 싶다면

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

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

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

나는 당신이 사용하는 것이 좋습니다 "통조림 명령 시퀀스"실제 컴파일러 빌드 규칙을 반복하지 않기 위해 :

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

그런 다음 다음과 같은 여러 규칙을 가질 수 있습니다.

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

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

다른 팁

이지 않:

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))))

이 Makefile 서 당신은 당신의 파일을 포함에서 원본 디렉토리입니다.또한 그것을 검사하는 경우를 구축 디렉토리는 존재하고,만들면 그들은 존재하지 않습니다.

마지막 줄은 가장 중요합니다.를 만듭니다 암시적 규칙 위해 각 빌드 기능을 사용하여 make-goal, 며,그것은 필요하지 않습 쓰는 하나씩

을 추가할 수도 있습니다 자동적인 의존성,세대 사용 Tromey 방법

일입니다 $@ 소스 파일에 대한 전체 (상대적) 경로가 포함되어 있으며, 그 결과 객체 이름을 구성하는 데 사용됩니다 (따라서 상대 경로).

우리는 사용:

#####################
# 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 $@

이름이 지정된 객체 디렉토리를 만듭니다 $(OBJDIR_1)및 소스의 하위 디렉터에 따른 하위 디렉토리.

예를 들어 MakeFile에서 (OBJ를 대상 객체 디렉토리로 가정) :

widget/apple.cpp
tests/blend.cpp

다음 객체 디렉토리의 결과 :

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

이것은 고통스러운 조작 또는 여러 명령 시퀀스없이 수행합니다.

build/%.o: src/%.cpp
src/%.o: src/%.cpp
%.o:
    $(CC) -c $< -o $@

build/test.exe: build/widgets/apple.o build/widgets/knob.o build/tests/blend.o src/ui/flash.o
    $(LD) $^ -o $@

Jaspere는 왜 " %.o : %.cpp"가 작동하지 않는지 설명했습니다. 이 버전에는 명령과 전제 조건이없는 하나의 패턴 규칙 (%.o :)와 두 가지 패턴 규칙 (빌드/%. o : 및 src/%. o :)가 있습니다. (Build/UI/Flash.O의 오타가 아니라고 가정 할 때 SRC/%. O 규칙을 SRC/%를 처리하기 위해 SRC/%. 그것을 꺼내십시오.)

Build/Test.exe는 빌드/위젯/Apple.o가 필요합니다.
Build/Widgets/Apple.o는 Build/%. O처럼 보이므로 SRC/%가 필요합니다. CPP (이 경우 SRC/Widgets/Apple.CPP),
Build/Widgets/Apple.o도 %.O처럼 보이므로 CC 명령을 실행하고 방금 찾은 전제 Q (즉, SRC/Widgets/Apple.CPP)를 사용하여 대상 (빌드/위젯/Apple.O)을 구축합니다.

이것은 또 다른 트릭입니다.

메인 'makefile'에서 각 소스에 대해 srcdir를 정의하고 srcdir의 각 값에 대해 'makef.mk'를 포함합니다. 각 소스에서 소스 파일 목록과 일부에 대한 일부 옵션을 컴파일하는 파일 'files.mk'를 넣습니다. 메인 'makefile'에서는 컴파일 옵션을 정의하고 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 $@.p.d -c $(C_FLAGS) $(C_FLAGS_$(call clear_name,$<)) $< -o $@
    @sed -e 's,.*:,SRC_FILES += ,g' < $@.p.d > $@.d
    @sed -e "\$$s/$$/ $(subst /,\/,$(dir $<))files.mk\n/" < $@.p.d >> $@.d
    @sed -e 's,^[^:]*: *,,' -e 's,^[ \t]*,,' -e 's, \\$$,,' -e 's,$$, :,' < $@.p.d >> $@.d
    -@rm -f $@.p.d

$(CPP_OBJS) : $(OBJDIR)/%.o : %.cpp Makefile
    $(CC) -MMD -MF $@.p.d -c $(CPP_FLAGS) $(CPP_FLAGS_$(call clear_name,$<)) $< -o $@
    @sed -e 's,.*:,SRC_FILES += ,g' < $@.p.d > $@.d
    @sed -e "\$$s/$$/ $(subst /,\/,$(dir $<))files.mk\n/" < $@.p.d >> $@.d
    @sed -e 's,^[^:]*: *,,' -e 's,^[ \t]*,,' -e 's, \\$$,,' -e 's,$$, :,' < $@.p.d >> $@.d
    -@rm -f $@.p.d

$(AS_OBJS) : $(OBJDIR)/%.o : %.S Makefile
    $(CC) -MMD -MF $@.p.d -c $(AS_FLAGS) $(AS_FLAGS_$(call clear_name,$<)) $< -o $@
    @sed -e 's,.*:,SRC_FILES += ,g' < $@.p.d > $@.d
    @sed -e "\$$s/$$/ $(subst /,\/,$(dir $<))files.mk\n/" < $@.p.d >> $@.d
    @sed -e 's,^[^:]*: *,,' -e 's,^[ \t]*,,' -e 's, \\$$,,' -e 's,$$, :,' < $@.p.d >> $@.d
    -@rm -f $@.p.d


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

여기 베타의 답변에서 영감을 얻은 내 솔루션이 있습니다. 다른 제안 된 솔루션보다 간단합니다

여러 하위 디렉토리에 저장된 여러 C 파일이있는 프로젝트가 있습니다. 예를 들어:

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

여기 내 makefile이 있습니다 ( 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

이 예제는 공유 라이브러리에 적합하며 편집 프로세스에 적응하기가 매우 쉽습니다.

일반적으로 각 하위 디렉토리에서 Makefile을 생성하고 최상위 MakeFile로 작성하여 하위 디렉토리에서 Make를 호출합니다.

이 페이지는 도움이 될 수 있습니다. http://www.gnu.org/software/make/

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top