【问题标题】:How can I make target depend on specific filename?如何使目标取决于特定的文件名?
【发布时间】:2019-02-04 17:36:59
【问题描述】:

我正在尝试使用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定义一个显式规则,这样它就不会使用内置规则。
  • dist 依赖于ctl 的原因是什么?如果您只想在文件ctl 被修改的情况下运行dist 的命令,则目标dist 必须创建一个文件dist。如果dist 是一个虚假目标,那么除了应该在dist 之前执行的其他虚假目标之外,拥有依赖项是没有意义的,例如dist: all 如果你想在运行dist 命令之前自动make all
  • 只是为了保证ctldist开始运行之前存在
  • 这和automake标签有什么关系?

标签: c++ c makefile gnu-make automake


【解决方案1】:

ctl.c 创建ctl 的“隐式规则”仅在没有明确规定的创建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 做什么。

【讨论】:

  • ctl 在我的情况下是手写脚本,但我得到了+ $ make make: 'ctl' is up to date. ..
  • 是的,因为ctl是手写的,没有依赖关系,所以它总是最新的。打印出来是不是有问题?
  • 不,不是;我刚刚将它作为第一条规则放在 makefile 中,并想知道为什么 make 除了该消息之外不再做任何事情。当调用make dist 时,它可以正常工作,谢谢:)
  • 一般makefile中的第一条规则应该命名为all,它应该没有自己的命令,但它应该取决于你想要正常构建的所有东西。这样,只需输入 make 就可以了。
【解决方案2】:

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

【讨论】:

    【解决方案3】:

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

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

    .PHONY: dist ctl
    

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-31
      • 2011-01-17
      • 2012-01-02
      • 1970-01-01
      相关资源
      最近更新 更多