在此Makefile中:
ifeq ($(shell uname),Darwin)
LDFLAGS := -Wl,-dead_strip
else
LDFLAGS := -Wl,--gc-sections -lpthread -ldl
endif
all: target/double
target/double
target:
mkdir -p $@
target/double: target/main.o target/debug/libdouble_input.a
$(CC) -o $@ $^ $(LDFLAGS)
target/debug/libdouble_input.a: src/lib.rs Cargo.toml
cargo build
target/main.o: src/main.c | target
$(CC) -o $@ -c $<
clean:
rm -rf target
当我执行make all
时,得到以下输出:
hello_c_use_rust [master] ⚡ make all
mkdir -p target
cc -o target/main.o -c src/main.c
cargo build
Compiling hello_c_use_rust v0.1.0 (/Users/jelly/code/own/hello_rust/hello_c_use_rust)
Finished dev [unoptimized + debuginfo] target(s) in 0.20s
cc -o target/double target/main.o target/debug/libdouble_input.a -Wl,-dead_strip
target/double
4 * 2 = 8
请告诉我为什么这是执行顺序? txs ^ _ ^。让我感到困惑的是,为什么第一步是mkdir -p target
;
您的目标是all
。 all
取决于target/double
,因此必须首先完成。反过来,target/double
取决于target/main.o
和target/debug/libdouble_input.a
。因此,必须先完成target/main.o
和target/debug/libdouble_input.a
。在这里,您很幸运(我们稍后将说明原因):首先尝试构建target/main.o
。由于target/main.o
具有target
作为仅订购的先决条件(|
符号开始列出仅订购的先决条件),因此必须首先完成target
。 Qed。
为什么会这样?因为如果target/main.o
目录尚不存在,则无法构建target
。构建将完全失败。因此,仅订购的先决条件告诉make必须首先存在目录。因为它是仅订购的先决条件,而不是常规先决条件,所以make只注意其存在。它会忽略其上次修改时间,这很好,因为目录的上次修改时间通常与构建过程无关。
你为什么幸运?因为如果make首先尝试构建target/debug/libdouble_input.a
,并且cargo build
没有创建目标目录,则它将失败。即使您知道首先构建了target/main.o
,也不应依靠它。有一天或另一天,有人可能会尝试使用并行make(make -j
),但可能会出错。
确实target/debug/libdouble_input.a
并没有target/debug
作为仅订购的先决条件。因此,make将执行其配方(cargo build
)而无需创建第一个target/debug
。并且,如果cargo build
不处理此操作,则它将失败。即使您知道cargo build
负责创建目标目录,也最好将其添加到Makefile中。以防万一某天或另一天发生变化。并向Makefile的读者显示您知道自己在做什么:
target target/debug:
mkdir -p $@
target/debug/libdouble_input.a: src/lib.rs Cargo.toml | target/debug
cargo build
这没什么大不了,可以为您节省一些错误。