如何使目标依赖于特定的文件名?

How can I make target depend on specific filename?

我正在尝试使用 Makefile 来管理我的项目中的一些任务(例如打包以供分发)。但是我找不到一种方法来依赖特定的文件名而不是一些自动魔术。参见示例:

+   $ cat Makefile
dist: ctl
        echo "package it here"

+   $ tree
.
├── ctl
└── Makefile

0 directories, 2 files

+   $ make
echo "package it here"
package it here

如您所见,这工作正常。但是当我创建文件 ctl.hctl.c:

时它停止工作
+   $ touch ctl.{h,c}

+   $ make
cc     ctl.c   -o ctl
/usr/bin/ld: /usr/lib/gcc/x86_64-pc-linux-gnu/8.2.1/../../../../lib/Scrt1.o: in function `_start':
(.text+0x24): undefined reference to `main'
collect2: error: ld returned 1 exit status
make: *** [<builtin>: ctl] Error 1

+   $ tree
.
├── ctl.c
├── ctl.h
└── Makefile

0 directories, 3 files

我的假设是 make 试图变得聪明,并认为 ctl 是从 ctl.c 编译而来的程序。事实并非如此。我怎样才能抑制这种行为?

ctl.c 创建 ctl 的 "implicit rule" 仅在没有明确规定的规则创建 ctl 时使用。例如,如果 ctl 应该从源文件 ctlcmd.ccommon.c 编译,那么写:

ctl: ctlcmd.o common.o
        $(CC) $(CFLAGS) -o $@ $^

.o 文件将使用另一个隐式规则从 .c 文件创建。)

如果ctl根本不需要重新创建(比如是手写脚本),那么你可以为它写一个虚拟规则,像这样:

# `ctl` is a hand-written file, don't try to recreate it from anything
ctl:
        touch ctl

你还应该写一些规则来告诉 Make 应该ctl.c做什么。

Make 带有一堆模式规则,它非常努力地使用它们。 其中之一说如何从 foo.c 中创建可执行文件 foo。这就是发生在你身上的事情。

我个人非常不喜欢这些规则,通常使用 -R 参数禁用它们。

$ ls
ctl  ctl.c  Makefile

$ make -R
echo "package it here"
package it here

$ make
cc     ctl.c   -o ctl
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crt1.o: In function `_start':
(.text+0x20): undefined reference to `main'
collect2: error: ld returned 1 exit status
make: *** [ctl] Error 1

现在,要求您的用户必须使用某个参数并不好。 一种前进的方式是简单地取消所有隐含规则。 您可以销毁 make 认为应用模式规则的候选文件扩展名列表。 一个简单的 SUFFIXES: 就可以了。

$ ls
ctl  ctl.c  Makefile

$ cat Makefile
.SUFFIXES:
dist: ctl
       echo "package it here"

$ make
echo "package it here"
package it here

通常make 假定所有目标都将创建同名文件。如果在您的示例中没有为 ctl 指定依赖项,make 会尝试猜测依赖项,例如,如果您有一个文件 ctl.c,它假定它可以从 ctl 构建ctl.c 使用标准规则。

假设您的目标 distctl 永远不应构建为文件,您可以通过添加一行

将它们声明为虚假目标
.PHONY: dist ctl

https://www.gnu.org/software/make/manual/html_node/Phony-Targets.html