如何在 make 目标中手动调用另一个目标?

48

我想要一个像这样的makefile:

cudaLib :
    # Create shared library with nvcc

ocelotLib :
    # Create shared library for gpuocelot

build-cuda : cudaLib
    make build

build-ocelot : ocelotLib
    make build

build :
    # build and link with the shared library

也就是说,*Lib 任务创建的库可以直接在设备上或者在 gpuocelot 上运行 cuda.

对于这两个构建任务,我需要运行相同的构建步骤,只是创建库不同。

是否有替代方法可以避免直接运行 make?

make build

这是一种后置要求吗?

3个回答

85

注意:本答案重点介绍在给定的makefile中对不同目标进行强大的递归调用。

为了补充Jack Kelly有益的回答,这里提供一个GNU makefile片段,演示如何使用$(MAKE)稳健地调用同一makefile中的不同目标(确保调用相同的make二进制文件,并且针对相同的makefile):

# Determine this makefile's path.
# Be sure to place this BEFORE `include` directives, if any.
THIS_FILE := $(lastword $(MAKEFILE_LIST))

target:
    @echo $@  # print target name
    @$(MAKE) -f $(THIS_FILE) other-target # invoke other target

other-target:
    @echo $@ # print target name

输出:

$ make target

target
other-target

使用 $(lastword $(MAKEFILE_LIST))-f ... 确保 $(MAKE) 命令使用同一个makefile,即使在调用 make 时通过显式路径 (-f ...) 传递了该 makefile。


注意:虽然GNU make具有递归调用的功能——例如,变量$(MAKE)专门用于启用它们——但它们的重点是调用下级makefile,而不是调用同一makefile中的不同目标。

话虽如此,尽管上面的解决方法有些繁琐和晦涩,但它确实使用了常规特性,应该是稳健的

这是手册部分链接,介绍了递归调用 ("sub-makes"):


1
只是对代码风格的一点评论。在任何可能的情况下,请避免从_make_中调用_make_。当然,有时候这样做很有帮助,但是如果你有选择,请不要这样做。这样做会让你的生活更美好。http://www.real-linux.org.uk/recursivemake.pdf - bobbogo

39

大多数 make 版本都设置了一个变量 $(MAKE),你可以用它来进行递归调用。


14

根据你目前的写法,build目标需要根据最近是否进行了ocelot或cuda构建来执行不同的操作。这就是说你必须以某种方式对build进行参数化。我建议使用单独的构建目标(就像你已经有的一样),带有相关的变量。例如:

build-cuda: cudaLib
build-ocelot: ocelotLib

build-cuda build-ocelot:
    shell commands
    which invoke ${opts-$@}
在命令行上,你要输入 make build-cuda(以此类推)。首先,Make会构建 cudaLib,然后执行 build-cuda 的步骤。在调用 shell 之前,它会扩展宏。在这种情况下,$@build-cuda,因此 ${opts-$@} 首先被扩展为 ${opts-build-cuda}。现在,Make将继续扩展 ${opts-build-cuda}。在 makefile 中的其他位置中,你需要定义 opts-build-cuda (当然还有它的姊妹文件 opts-build-ocelot)。请注意,由于 build-cuda 等不是实际的文件,所以你最好告诉 make 这一点(.PHONY: build-cuda)。

我该如何调用opts-build-cuda?在这种情况下,是使用“make opts-build-cuda”还是“make ${opts-$@}”? - Simon A. Eugster
2
你需要调用_build_cuda_ (make build_cuda)。Make会首先执行cudaLib的shell命令,然后执行build-cuda的shell命令。在生成最终的命令集时,Make必须扩展变量opts-build-cuda。(可能还有其他变量,比如deptool-build-cudabuild-cuda-output-dir等等。)这使得你可以在Makefile中编写一块命令,当它们传递给shell时看起来非常不同。附注:始终使用--warn-undefined-variable调用make,这将为你节省很多烦恼。 - bobbogo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接