C Makefile:为什么使用%的Makefile不起作用?

C Makefile:为什么使用%的Makefile不起作用?,c,linux,makefile,C,Linux,Makefile,%在我的makefile中没有工作 我已经在ubuntu 16.04 x64上测试了makefile 我的makefile代码是: 版本1 CC=gcc OBJ=main.o TARGET:=main .PHONY: clean all : main # ${OBJ}:%.o:%.c %.i : %.c $(info Preprocess: build main.i) ${CC} -E -o $@ $< %.s : %.i $(info

%在我的makefile中没有工作

我已经在ubuntu 16.04 x64上测试了makefile

我的makefile代码是: 版本1

CC=gcc
OBJ=main.o
TARGET:=main
.PHONY: clean
all : main
# ${OBJ}:%.o:%.c

%.i : %.c
        $(info Preprocess: build main.i)
        ${CC} -E -o $@ $<

%.s : %.i
        $(info Compile: build main.s)
        ${CC} -S -o $@ $<

%.o : %.s
        $(info Assemble: build main.o)
        ${CC} -c -o $@ $<

main : main.o
        $(info Link: build main.o)
        ${CC} -o $@ $^

clean:
        rm -f *.o *.out *.s *.i *.asm *.map ${OBJ} main
所以只有最后一个rulemain:main.o run。 第一步是自动派生代码gcc-c-omain.omain.c。 为什么其他规则没有运行

然后我修改第三条规则,添加静态模式: 版本2

...
%.i : %.c
        $(info Preprocess: build main.i)
        ${CC} -E -o $@ $<

%.s : %.i
        $(info Compile: build main.s)
        ${CC} -S -o $@ $<

main.o : %.o : %.s
        $(info Assemble: build main.o)
        ${CC} -c -o $@ $<

%: %.o
        $(info Link: build main.o)
        ${CC} -o $@ $^
为什么要运行rm main,我

我再次修改makefile: 版本3

%.o:%.c
        $(info build main.o)
        ${CC} -c -o $@ $<
main : main.o
        $(info Link: build main.o)
        ${CC} -o $@ $^
那么,为什么版本1不能正常工作呢?

它不能工作,因为make知道如何从.c源代码构建一个对象文件

您可以禁用隐式规则,如果您使用make-r运行版本1,它应该按预期运行

.i文件被删除是因为它是一个中间文件,默认情况下,您可以使用.PRECIOUS:some文件名来避免删除所有中间文件

%makefiles中的规则称为stem,模式规则而不是通配符,这是另一回事

对于详细日志或更详细的日志,可以使用-debug或-debug=all参数运行make

编辑

您还有两个选项可以禁用内置规则并使版本1正常工作:

用空规则覆盖特定的内置规则,只需添加%.o:%.c即可 禁用所有内置规则添加空后缀列表。后缀: 如果修改后缀列表,唯一有效的预定义后缀规则将是由指定列表中的一个或两个后缀命名的规则

编辑

禁用我过去使用的内置规则的附加选项:

MAKEFLAGS += --no-builtin-rules
它不起作用,因为make知道如何从.c源代码构建一个对象文件.o,它是一个

您可以禁用隐式规则,如果您使用make-r运行版本1,它应该按预期运行

.i文件被删除是因为它是一个中间文件,默认情况下,您可以使用.PRECIOUS:some文件名来避免删除所有中间文件

%makefiles中的规则称为stem,模式规则而不是通配符,这是另一回事

对于详细日志或更详细的日志,可以使用-debug或-debug=all参数运行make

编辑

您还有两个选项可以禁用内置规则并使版本1正常工作:

用空规则覆盖特定的内置规则,只需添加%.o:%.c即可 禁用所有内置规则添加空后缀列表。后缀: 如果修改后缀列表,唯一有效的预定义后缀规则将是由指定列表中的一个或两个后缀命名的规则

编辑

禁用我过去使用的内置规则的附加选项:

MAKEFLAGS += --no-builtin-rules

为了避免隐式规则生效,需要使用显式对象的静态模式。所以我用静态模式重写makefile。它可以正常工作并且不运行rm main.i

CC:=gcc
SRCS:=          $(wildcard *.c)
OBJ:=           $(patsubst %.c, %.o, ${SRCS})
PREFILE:=       $(patsubst %.o, %.i, ${OBJ})
ASMFILE:=       $(patsubst %.o, %.s, ${OBJ})
TARGET:=main
all: ${TARGET}
.PHONY: clean distclean

$(PREFILE):%.i:%.c
        $(info Preprocess: build main.i)
        $(CC) -E -o $@ $<

$(ASMFILE):%.s:%.i
        $(info Compile: build main.s)
        $(CC) -S -o $@ $<

$(OBJ):%.o:%.s
        $(info Assemble: build main.o)
        $(CC) -c -o $@ $<
        @objdump -DrwC -Mintel $@ > $(patsubst %.o,%.o.asm,$@)

$(TARGET):$(OBJ)
        $(info Link: build main)
        $(CC) -o $@ $^ -Wl,-Map=gcc.map
        @objdump -D $@ > $(patsubst %,%.asm,$@)

clean:
        rm -f *.o *.out *.s *.i *.asm *.map ${OBJ} ${TARGET}

distclean : clean
        rm -f *.d

为了避免隐式规则生效,需要使用显式对象的静态模式。所以我用静态模式重写makefile。它可以正常工作并且不运行rm main.i

CC:=gcc
SRCS:=          $(wildcard *.c)
OBJ:=           $(patsubst %.c, %.o, ${SRCS})
PREFILE:=       $(patsubst %.o, %.i, ${OBJ})
ASMFILE:=       $(patsubst %.o, %.s, ${OBJ})
TARGET:=main
all: ${TARGET}
.PHONY: clean distclean

$(PREFILE):%.i:%.c
        $(info Preprocess: build main.i)
        $(CC) -E -o $@ $<

$(ASMFILE):%.s:%.i
        $(info Compile: build main.s)
        $(CC) -S -o $@ $<

$(OBJ):%.o:%.s
        $(info Assemble: build main.o)
        $(CC) -c -o $@ $<
        @objdump -DrwC -Mintel $@ > $(patsubst %.o,%.o.asm,$@)

$(TARGET):$(OBJ)
        $(info Link: build main)
        $(CC) -o $@ $^ -Wl,-Map=gcc.map
        @objdump -D $@ > $(patsubst %,%.asm,$@)

clean:
        rm -f *.o *.out *.s *.i *.asm *.map ${OBJ} ${TARGET}

distclean : clean
        rm -f *.d

回答得好。OP还应该注意,模式规则是特定于GNU make的。当然,如果他们不关心与其他实现的兼容性,那也没关系,但人们应该始终保持对何时依赖于标准工具扩展的意识。谢谢,所以隐式规则的优先级高于模式规则(没有显式对象),我认为应该使用带有显式对象的静态模式,以避免隐式规则生效。所以我用静态模式重写makefile。@Edward我不知道这是否是一个优先级,但肯定可以选择make think,如果你有一个.s文件,可能会使用规则%.o:%.s,我没有检查好答案。OP还应该注意,模式规则是特定于GNU make的。当然,如果他们不关心与其他实现的兼容性,那也没关系,但人们应该始终保持对何时依赖于标准工具扩展的意识。谢谢,所以隐式规则的优先级高于模式规则(没有显式对象),我认为应该使用带有显式对象的静态模式,以避免隐式规则生效。所以我用静态模式重写makefile。@Edward我不知道这是否是一个优先级,但肯定是一个选项,如果你有一个.s文件存在,可能是规则%.o:%.s会被使用我没有检查看起来很好,我在一个旧项目中经常使用stem模式,我不记得有过这个选项,但可能当时我错过了它,如果您需要追溯兼容性,您可能需要检查此功能何时可用。好的,我在一个旧项目中经常使用stem模式,我不记得有过此选项,但可能当时我错过了它。如果您需要追溯兼容性,您可能需要检查此功能何时可用
CC:=gcc
SRCS:=          $(wildcard *.c)
OBJ:=           $(patsubst %.c, %.o, ${SRCS})
PREFILE:=       $(patsubst %.o, %.i, ${OBJ})
ASMFILE:=       $(patsubst %.o, %.s, ${OBJ})
TARGET:=main
all: ${TARGET}
.PHONY: clean distclean

$(PREFILE):%.i:%.c
        $(info Preprocess: build main.i)
        $(CC) -E -o $@ $<

$(ASMFILE):%.s:%.i
        $(info Compile: build main.s)
        $(CC) -S -o $@ $<

$(OBJ):%.o:%.s
        $(info Assemble: build main.o)
        $(CC) -c -o $@ $<
        @objdump -DrwC -Mintel $@ > $(patsubst %.o,%.o.asm,$@)

$(TARGET):$(OBJ)
        $(info Link: build main)
        $(CC) -o $@ $^ -Wl,-Map=gcc.map
        @objdump -D $@ > $(patsubst %,%.asm,$@)

clean:
        rm -f *.o *.out *.s *.i *.asm *.map ${OBJ} ${TARGET}

distclean : clean
        rm -f *.d