有没有办法定义自定义隐式 GNU Make 规则?

Is there a way to define custom implicit GNU Make rules?

我经常从 dot(graphviz 格式)文件中创建 png 文件。这样做的命令如下:

$ dot my_graph.dot -o my_graph.png -Tpng

但是,我希望能够使用更短的命令格式,例如 $ make my_graph.dot 来自动生成我的 png 文件。

目前,我使用的是 Makefile,我在其中定义了以下规则,但配方仅在包含 Makefile 的目录中可用

%.eps: %.dot
    dot $<  -o $@ -Teps

是否可以定义自定义隐式 GNU Make 配方?这将允许上述配方在系统范围内可用

如果没有,您使用什么解决方案来解决这类问题?

设置:

您可以在 shell 的启动文件中定义 shell 函数,例如

dotpng()
{
    echo dot ${1%.dot}.dot -o ${1%.dot}.png -Tpng;
}

这个函数可以这样调用

dotpng my_graph.dot

dotpng my_graph

代码 ${1%.dot}.dot 从文件名中删除 .dot(如果存在)并(再次)附加它以允许 my_graph.dotmy_graph 作为函数参数。

Is it possible to define custom implicit GNU Make recipes ?

不修改 GNU Make 的源代码就不行。

If not, what solution do you use to solve those kind of problem ?

我不喜欢在全球范围内修改系统,但您可以这样做:

  • 使用内容

    创建一个文件/usr/local/lib/make/myimplicitrules.make
      %.eps: %.dot
          dot $<  -o $@ -Teps
    
  • 在 Makefile 中使用 include /usr/local/lib/make/myimplicitrules.make

我宁愿使用 git 子模块或类似模块在项目之间共享通用配置,而不是依赖于全局配置。依赖全局环境会使您的程序难以测试并且 non-portable.

我宁愿使用 shell 函数,还有一些东西:

mymake() {
   make -f <(cat <<'EOF'
%.eps: %.dot
    dot $<  -o $@ -Teps
EOF
   ) "$@"
}
mymake my_graph.dot

GNU Make 允许您使用 MAKEFILES 指定要读取的额外 makefile 环境变量。引用自 info '(make)MAKEFILES Variable':

the default goal is never taken from one of these makefiles (or any makefile included by them) and it is not an error if the files listed in 'MAKEFILES' are not found
if you are running 'make' without a specific makefile, a makefile in 'MAKEFILES' can do useful things to help the built-in implicit rules work better

举个例子,当前目录下没有makefile, 在 make 的包含路径中跟随 .mk 个文件(例如通过 MAKEFLAGS=--include-dir="$HOME"/.local/lib/make/) 你可以创建 subdir gen/ 并通过以下方式转换 my_graph.dotdot/my_graph.dot 运行:

MAKEFILES=dot.mk make gen/my_graph.png

为了进一步节省一些输入,很想添加 MAKEFILES=dot.mk 到会话环境,但在启动文件中定义 MAKEFILES 可以使事情完全不透明。出于这个原因,我更喜欢 在命令行上看到 MAKEFILES=…

文件:dot.mk

include common.mk

genDir ?= gen/
dotDir ?= dot/
dotFlags ?= $(if $(DEBUG),-v)
Tvariant ?= :cairo:cairo

vpath %.dot $(dotDir)

$(genDir)%.png $(genDir)%.svg $(genDir)%.eps : %.dot | $(genDir).
    dot $(dotFlags) $< -o $@ -T'$(patsubst .%,%,$(suffix $@))$(Tvariant)'

包含的 common.mk 是您将一般定义存储到的地方 管理目录创建、诊断等,例如

.PRECIOUS: %/. ## preempt 'unlink: ...: Is a directory'
%/. : ; $(if $(wildcard $@),,mkdir -p -- $(@D))

参考文献:

  • ?= = := ... - info '(make)Reading Makefiles'
  • vpath - info '(make)Selective Search'
  • order-only 先决条件(例如 | $(genDir).)- info '(make)Prerequisite Types'
  • .PRECIOUS - info '(make)Chained Rules'