忽略隐式规则依赖

时间:2017-06-09 18:49:29

标签: c makefile gnu-make

在这个部分Makefile中,当我执行make而没有参数且.PHONY被禁用时,它返回:

  

make:'debug'没什么可做的。

启用.PHONY(或make -r)它会转到'build'而不创建任何目标文件,因此GCC不能打开任何目标文件,因为目标中没有目标文件目录呢。

  

arm-none-eabi-gcc:错误:   obj / debug / ThirdParty / STM32F1xx_HAL_Driver / Src / stm32f1xx_hal_adc.o:No   这样的文件或目录

此makefile将objs分隔为文件夹obj / debug或obj / release。

文件结构:

bin
inc
Src
ThirdParty  // thirdparty source files
obj // mkdir -p should create this directories tree
    debug
        Src
        ThirdParty
    release
        ...

生成文件

.PHONY: build debug release clean $(COBJ) $(SOBJ)

# Main target
debug:  CC_FLAGS += $(DEBUG)  
debug:  ELF = debug.elf 
debug:  OBJPATH = obj/debug
debug:  COBJ = $(patsubst ./%,$(OBJPATH)/%,$(C:.c=.o))  # C contains c code
debug:  SOBJ = $(patsubst ./%,$(OBJPATH)/%,$(S:.s=.o))  # S contains asm code
debug:  build

release: CC_FLAGS += $(RELEASE)
release: OBJPATH = obj/release
release: COBJ = $(patsubst ./%,$(OBJPATH)/%,$(C:.c=.o))
release: SOBJ = $(patsubst ./%,$(OBJPATH)/%,$(S:.s=.o))
release: ELF = release.elf 
release: build


build: $(COBJ) $(SOBJ)      
    $(CC) $(COBJ) $(SOBJ) $(LIBS) $(LD_FLAGS)  -o bin/$(ELF)


%.o: %.c
    echo $@
    @mkdir -p $(OBJPATH)/$(dir $@)  
    $(CC) $(CC_FLAGS) -c   $< -o $(OBJPATH)/$@

%.o: %.s
    @mkdi -p $(OBJPATH)/$(dir $@)
    $(CC) $(CC_FLAGS) -c   $< -o $(OBJPATH)/$@

$(COBJ)的一个示例:

  

OBJ /调试/第三方/ FreeRTOS的/ queue.o

Linux x86-64

GNU Make 4.2.1

Arm-none-eabi-gcc - 我认为这没关系

2 个答案:

答案 0 :(得分:2)

您遗漏了the GNU make manual关于特定目标变量的重要提示:

  

与自动变量一样,这些值仅在目标配方的上下文中可用(以及在其他特定于目标的分配中)。

所以,在你的makefile中:

debug:  COBJ = $(patsubst ./%,$(OBJPATH)/%,$(C:.c=.o))  # C contains c code
debug:  SOBJ = $(patsubst ./%,$(OBJPATH)/%,$(S:.s=.o))  # S contains asm code

build: $(COBJ) $(SOBJ)
        ...

此时$(COBJ)$(SOBJ)引用COBJSOBJ变量的全局设置值(因为如上所述,特定于目标的值仅在配方中可用,而不在先决条件列表中。这些变量没有全局值,因此它们扩展为空字符串,而makefile基本上只有:

build:
        ...

没有任何先决条件,这就是为什么你会看到你的行为。

有多种方法可以解决这个问题。一种是使用递归make:删除release: builddebug: build行并添加:

debug release:
        @$(MAKE) COBJ='$(COBJ)' SOBJ='$(SOBJ)' build

另一种方法是使用secondary expansion(你不能按照我最初建议的方式去做,但你可以使用构造的变量名来做到这一点:

OBJPREFIX := obj
COBJ = $(patsubst ./%,$(OBJPREFIX)/$@/%,$(C:.c=.o))
SOBJ = $(patsubst ./%,$(OBJPREFIX)/$@/%,$(S:.s=.o))

# Main target
debug:  CC_FLAGS += $(DEBUG)
debug:  ELF = debug.elf

release: CC_FLAGS += $(RELEASE)
release: ELF = release.elf 

.SECONDEXPANSION:
release debug: $$(COBJ) $$(SOBJ)      
        $(CC) $(COBJ) $(SOBJ) $(LIBS) $(LD_FLAGS)  -o bin/$(ELF)

这使用输出对象名称中的目标名称。

另一种方法是使用生成的makefile。

您可以考虑阅读以下系列帖子:http://make.mad-scientist.net/category/metaprogramming/(从最早的帖子开始)。

答案 1 :(得分:0)

正如 MadScientist 所提到的,特定于目标的变量的范围有限,我将makefile作为一个选择器并使用TARGET ='target'参数运行make,如下所示:

make TARGET = debug
make TARGET = release

没有优雅但功能齐全!

Makefile:

O  = $(C:%.c=%.o)
O += $(S:%.s=%.o)

ifeq ($(TARGET), release)
    ELF = bin/release.elf
    CC_FLAGS += -O3
    OBJPATH = obj/release
else
    ELF = bin/debug.elf
    CC_FLAGS += -g3
    OBJPATH = obj/debug
endif

OBJ = $(addprefix $(OBJPATH)/, $(O))


all: makepath build

build: $(OBJ) 
    @echo ---- LINKING ----
    $(CC) $(OBJ) $(LIBS) $(LD_FLAGS)  -o $(ELF) 

makepath: 
    @mkdir -p $(dir $(OBJ)) 


$(OBJPATH)/%.o:%.c
    @echo ---- C ----
    $(CC) $(CC_FLAGS) -c $<  -o $@

$(OBJPATH)/%.o:%.s
    @echo ---- S ----
    $(CC) $(CC_FLAGS) -c $<  -o $@

clean:
    find -name *.o -delete
    find -name *.elf -delete