Makefile:为什么带有%的makefile不起作用?

时间:2019-05-16 08:40:56

标签: 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 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

运行make,终端显示消息:

gcc    -c -o main.o main.c
Link: build main.o
gcc -o main main.o

因此只有最后一条规则(main:main.o)运行。 第一个步骤是自动派生的代码(gcc -c -o main.o main.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 $@ $^

然后所有规则生效,显示消息:

Preprocess: build main.i
gcc -E -o main.i main.c
Compile: build main.s
gcc -S -o main.s main.i
Assemble: build main.o
gcc -c -o main.o main.s
Link: build main.o
gcc -o main main.o
rm main.i

(为什么运行“ rm main.i”?)

我再次修改了makefile: 版本3

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

它可以正确运行。打印消息:

build main.o
gcc -c -o main.o main.c
Link: build main.o
gcc -o main main.o

那么,为什么版本1无法正常工作?

2 个答案:

答案 0 :(得分:6)

这是行不通的,因为make知道如何从.o源构建目标文件(.c),是built-in implicit rule

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

.i文件被删除,因为它是一个中间文件,默认情况下,make删除所有中间文件,您可以通过使用.PRECIOUS: some-file-name

来避免这种情况。 生成文件中的

%规则称为 stem 模式规则(不是通配符,这是另一回事)

您可以使用参数make--debug运行--debug=all来获取详细日志或更详细的日志

修改

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

  • 使用空规则覆盖特定的内置规则,只需添加%.o: %.c
  • 禁用所有内置规则,添加空后缀列表.SUFFIXES:
  

如果您修改后缀列表,则唯一有效的预定义后缀规则将是由您指定的列表中的一个或两个后缀命名的规则。

答案 1 :(得分:1)

应该使用带有显式对象的静态模式,以避免隐式规则生效。所以我用静态模式重写了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