Makefile |

Makefile |

前言

在学习skynet项目中的Makefile时,遇到以下这个语句时不是很明白:

3rd/jemalloc/Makefile : | 3rd/jemalloc/autogen.sh
	cd 3rd/jemalloc && ./autogen.sh --with-jemalloc-prefix=je_ --enable-prof

百度时也搜不到相关的消息,现在大概了解了相关的意思,写个博文记录下。

正文

谷歌中发现了官方的文档:https://www.gnu.org/software/make/manual/make.html

随后根据 |进行搜索,得到了一段话,放在参考文献中。对这段话我的理解大致如下:

先决条件有两种:一种称为 normal-prerequisites 另一个称为 order-only-prerequisites。两者可以共存,也可以同时存在。例如下面的这些写法都是允许的:

a : b c 
a : | d e
a : b c | d e
a : b | b

通常,如果更新了目标的先决条件,那么也应该更新目标。order-only-prerequisites则让我们实现更新了目标的先决条件,不更新目标。下面通过一个简单的例子来解释一下:

这个Makefile执行了几件事情,创建objdir目录,然后再该目录下创建a.o, b.o两个文件。在目录下创建删除文件都会改变目录的时间戳,这里是 normal-prerequisites,所以看到在make执行后会执行两次touch命令。

wyw@DESKTOP-GJ20UDC:~/code/test_make$ cat Makefile
objdir = objdir
objs := $(addprefix $(objdir)/, a.o b.o)

$(objdir)/%.o:
        touch $@


all: $(objs)

$(objs): objdir

$(objdir):
        mkdir $(objdir)
wyw@DESKTOP-GJ20UDC:~/code/test_make$ make
mkdir objdir
touch objdir/a.o
touch objdir/b.o
wyw@DESKTOP-GJ20UDC:~/code/test_make$ ls --full-time
total 0
-rw-r--r-- 1 wyw wyw  145 2021-07-22 20:54:11.194231600 +0800 Makefile
drwxr-xr-x 1 wyw wyw 4096 2021-07-22 20:56:37.093678100 +0800 objdir
wyw@DESKTOP-GJ20UDC:~/code/test_make$ touch objdir/c.o
wyw@DESKTOP-GJ20UDC:~/code/test_make$ ls --full-time
total 0
-rw-r--r-- 1 wyw wyw  145 2021-07-22 20:54:11.194231600 +0800 Makefile
drwxr-xr-x 1 wyw wyw 4096 2021-07-22 20:57:16.898140600 +0800 objdir
wyw@DESKTOP-GJ20UDC:~/code/test_make$ make
touch objdir/a.o
touch objdir/b.o

在这个版本中我们修改先决条件,加上管道符|

wyw@DESKTOP-GJ20UDC:~/code/test_make$ cat Makefile
objdir = objdir
objs := $(addprefix $(objdir)/, a.o b.o)

$(objdir)/%.o:
        touch $@


all: $(objs)

$(objs): |objdir

$(objdir):
        mkdir $(objdir)
wyw@DESKTOP-GJ20UDC:~/code/test_make$ make
mkdir objdir
touch objdir/a.o
touch objdir/b.o
wyw@DESKTOP-GJ20UDC:~/code/test_make$ touch objdir/c.o
wyw@DESKTOP-GJ20UDC:~/code/test_make$ make
make: Nothing to be done for 'all'.

在这次,最后make的提示是目标无须更新~

参考文献

4.3 Types of Prerequisites

There are actually two different types of prerequisites understood by GNU make: normal prerequisites such as described in the previous section, and order-only prerequisites. A normal prerequisite makes two statements: first, it imposes an order in which recipes will be invoked: the recipes for all prerequisites of a target will be completed before the recipe for the target is run. Second, it imposes a dependency relationship: if any prerequisite is newer than the target, then the target is considered out-of-date and must be rebuilt.

Normally, this is exactly what you want: if a target’s prerequisite is updated, then the target should also be updated.

扫描二维码关注公众号,回复: 15708216 查看本文章

Occasionally, however, you have a situation where you want to impose a specific ordering on the rules to be invoked without forcing the target to be updated if one of those rules is executed. In that case, you want to define order-only prerequisites. Order-only prerequisites can be specified by placing a pipe symbol (|) in the prerequisites list: any prerequisites to the left of the pipe symbol are normal; any prerequisites to the right are order-only:

targets : normal-prerequisites | order-only-prerequisites

The normal prerequisites section may of course be empty. Also, you may still declare multiple lines of prerequisites for the same target: they are appended appropriately (normal prerequisites are appended to the list of normal prerequisites; order-only prerequisites are appended to the list of order-only prerequisites). Note that if you declare the same file to be both a normal and an order-only prerequisite, the normal prerequisite takes precedence (since they have a strict superset of the behavior of an order-only prerequisite).

Consider an example where your targets are to be placed in a separate directory, and that directory might not exist before make is run. In this situation, you want the directory to be created before any targets are placed into it but, because the timestamps on directories change whenever a file is added, removed, or renamed, we certainly don’t want to rebuild all the targets whenever the directory’s timestamp changes. One way to manage this is with order-only prerequisites: make the directory an order-only prerequisite on all the targets:

OBJDIR := objdir
OBJS := $(addprefix $(OBJDIR)/,foo.o bar.o baz.o)

$(OBJDIR)/%.o : %.c
       $(COMPILE.c) $(OUTPUT_OPTION) $<

all: $(OBJS)

$(OBJS): | $(OBJDIR)

$(OBJDIR):
       mkdir $(OBJDIR)

Now the rule to create the objdir directory will be run, if needed, before any ‘.o’ is built, but no ‘.o’ will be built because the objdir directory timestamp changed.

猜你喜欢

转载自blog.csdn.net/sayWhat_sayHello/article/details/119010996