模式仅在每次调用时匹配一次,并且make正在删除中间文件

时间:2017-03-12 11:15:12

标签: makefile gnu-make

我在Makefile中有以下规则来分三个阶段构建可执行文件:

all: build/myexe

build/myexe: output/main_dats.o output/foo_dats.o | build/
    gcc $^ -o $@
output/%.o: output/%.c
    patscc -c $< -o $@
output/%_dats.c: src/%.dats | output/
    patsopt -cc -o $@ -d $<
build/:
    mkdir -p build/
output/:
    mkdir -p output/

src/%.dats源文件用于生成output/%_dats.c源文件,该文件被编译为output/%.o目标文件,最后它们被链接到可执行文件build/myexe。< / p>

第一次运行make只会成功构建两个.o文件的第一个

$ make
mkdir -p output/
patsopt -cc -o output/main_dats.c -d src/main.dats
patscc -c output/main_dats.c -o output/main_dats.o
make: *** No rule to make target `output/foo_dats.o', needed by `build/myexe'.  Stop.
rm output/main_dats.c

但是再次运行将构建第二个.o文件并成功链接可执行文件:

$ make
patsopt -cc -o output/foo_dats.c -d src/foo.dats
patscc -c output/foo_dats.c -o output/foo_dats.o
mkdir -p build/
gcc output/main_dats.o output/foo_dats.o -o build/myexe
rm output/foo_dats.c

并注意在每次调用结束时,命令rm output/..._dats.c正在删除生成的.c源文件。

这是一个没有模式匹配的Makefile:

all: build/myexe

build/myexe: output/main_dats.o output/foo_dats.o | build/
    gcc $^ -o $@
output/foo_dats.o: output/foo_dats.c
    patscc -c $< -o $@
output/main_dats.o: output/main_dats.c
    patscc -c $< -o $@
output/foo_dats.c: src/foo.dats | output/
    patsopt -cc -o $@ -d $<
output/main_dats.c: src/main.dats | output/
    patsopt -cc -o $@ -d $<
build/:
    mkdir -p build/
output/:
    mkdir -p output/

更可预测的是:

$ make
mkdir -p output/
patsopt -cc -o output/main_dats.c -d src/main.dats
patscc -c output/main_dats.c -o output/main_dats.o
patsopt -cc -o output/foo_dats.c -d src/foo.dats
patscc -c output/foo_dats.c -o output/foo_dats.o
mkdir -p build/
gcc output/main_dats.o output/foo_dats.o -o build/myexe

并注意,生成的.c文件不再被删除。

显然我在滥用模式匹配机制。我知道有一些通配符功能,但我相信它适用于文件通配。

2 个答案:

答案 0 :(得分:2)

为避免删除中间文件,您只需将它们列为某处的实际目标。例如,您可以编写单独的规则:

.jumbotron.tight {
    margin-bottom: 0;
}

您不必将此目标make_srcs: output/main_dats.c output/foo_dats.c 列为先决条件,也不必提供配方等。只需将make_srcs文件列为makefile中的实际目标或先决条件即可它们被删除了。

至于你的“只构建一些输出”的行为,我不知道:它对我来说很好用:

_dats.c

因此,您的设置中有一些内容尚未在您的问题中明确说明。正如评论所示,您需要运行$ make --version | head -n1 GNU Make 4.2.1 $ cat Makefile all: build/myexe build/myexe: output/main_dats.o output/foo_dats.o | build/ touch $@ output/%.o: output/%.c touch $@ output/%_dats.c: src/%.dats | output/ touch $@ build/: mkdir -p build/ output/: mkdir -p output/ make_srcs: output/main_dats.c output/foo_dats.c $ rm -rf output build && make mkdir -p output/ touch output/main_dats.c touch output/main_dats.o touch output/foo_dats.c touch output/foo_dats.o mkdir -p build/ touch build/myexe (我会忽略make -d选项,我不知道您为什么要添加它)并弄清楚为什么会抛出错误。

答案 1 :(得分:0)

理想情况下,不应该弃用模式规则。他们容易过度匹配(因为,模式),他们可能很难开始工作,他们带来了整个&#34;中间目标&#34;问题(删除您正在观察的output/*.c个文件),他们需要另一个可疑功能(&#34;二次扩展&#34;)以使其可用于一些更多涉及的场景等。

简而言之:不建议使用模式规则,并且使用多级模式规则肯定不建议。比它的价值更麻烦。无论如何,恕我直言。

(结束咆哮)

所以我建议你写一个简单的宏,所以你的makefile最终看起来像这样:

all: build/myexe

# $(call dats,basename)
define dats
output/$1_dats.o: output/$1_dats.c
    patscc -c $$< -o $$@
output/$1_dats.c: src/$1.c | output
    patcc -cc -o $$@ -d $$<
endif

build/myexe: output/main_dats.o output/foo_dats.o | build
    gcc $^ -o $@
$(eval $(call dats,foo))
$(eval $(call dats,main))

build:
    mkdir -p build
output:
    mkdir -p output