在makefile规则中提取匹配的一部分

时间:2014-09-22 10:53:05

标签: makefile

我有一个makefile,可以在不同的地方生成一堆图像版本:

website/img/logo_256.png
website/img/logo_152.png
/tmp/logo_64.png

等等(/ tmp / generation因此我以后可以使用这些文件来生成多分辨率.ico,其详细信息并不重要。)

我想要一个表格规则

logo_%.png: ${SRC}
        convert $^ -thumbnail $*x$* $@

但是,$*也会引入匹配的目录,所以我得到了一个表单命令:

convert logo_1024.png -thumbnail /tmp/64x/tmp/64 /tmp/logo_64.png

这是不正确的(我需要48x48,而不是/tmp/48x/tmp/48)。

或者我可以写

/tmp/logo_%.png: ${SRC}
        convert $^ -thumbnail $*x$* $@
website/img/logo_%.png: ${SRC}
        convert $^ -thumbnail $*x$* $@

看起来很难看。

我确信有一些方法可以分解和模式匹配$@以获得我想要的东西,但我不是一个makefile大师,所以这需要一些研究。

最简单的方法是什么?

2 个答案:

答案 0 :(得分:2)

请参阅GNU Make Manual中的Automatic Variables的后半部分:

Of the variables listed above, four have values that are single file names, and three have values that are lists of file names. These seven have variants that get just the file's directory name or just the file name within the directory. The variant variables' names are formed by appending ‘D’ or ‘F’, respectively. These variants are semi-obsolete in GNU make since the functions dir and notdir can be used to get a similar effect (see Functions for File Names). Note, however, that the ‘D’ variants all omit the trailing slash which always appears in the output of the dir function. Here is a table of the variants:

‘$(@D)’
    The directory part of the file name of the target, with the trailing slash removed. If the value of ‘$@’ is dir/foo.o then ‘$(@D)’ is dir. This value is . if ‘$@’ does not contain a slash.


‘$(@F)’
    The file-within-directory part of the file name of the target. If the value of ‘$@’ is dir/foo.o then ‘$(@F)’ is foo.o. ‘$(@F)’ is equivalent to ‘$(notdir $@)’.


‘$(*D)’
‘$(*F)’
    The directory part and the file-within-directory part of the stem; dir and foo in this example.


‘$(%D)’
‘$(%F)’
    The directory part and the file-within-directory part of the target archive member name. This makes sense only for archive member targets of the form archive(member) and is useful only when member may contain a directory name. (See Archive Members as Targets.)


‘$(<D)’
‘$(<F)’
    The directory part and the file-within-directory part of the first prerequisite.


‘$(^D)’
‘$(^F)’
    Lists of the directory parts and the file-within-directory parts of all prerequisites.


‘$(+D)’
‘$(+F)’
    Lists of the directory parts and the file-within-directory parts of all prerequisites, including multiple instances of duplicated prerequisites.


‘$(?D)’
‘$(?F)’
    Lists of the directory parts and the file-within-directory parts of all prerequisites that are newer than the target.

编辑:

根据@ Ian的评论提示,我再次看了一眼,发现这不是一个完整的解决方案。随后是一个完整的解决方案。

以上F修饰符(以及$(notdir)函数)将从目标文件名中删除路径。这是必要的一部分。

需要额外的操作才能从目标中提取数字组件,如/some/path/logo_64.png

$(basename)功能会以更具体的方式删除后缀($(patsubst %.png,%,$@)$(@:%.png=))。

将我们从/some/path/logo_64.png获得的内容与logo_64相结合。在这一点上处理事情在很大程度上取决于数据的样子以及可以做出的关于它的断言。如果logo_是一个静态前缀,那么一个简单的$(patsubst logo_%,%,...)将起作用(匹配的替换引用就像之前一样)。

如果无法保证,但可以保证维度是最后一个下划线分离的组件,则可以使用$(lastword $(subst _, ,...))

答案 1 :(得分:1)

所需规则是:

logo_%.png: ${SRC}
    convert $^ -thumbnail $(*F)x$(*F) $@

$(*F)Make manual中非常简短地记录,正如Etan的回答所引用的那样。

  

'$(*F)'词干的文件目录内部分;在此示例中为foo

&#39>干&#39; ($*)在模式中没有任何明确的含义。这包括通配符和任何隐式目录。因此,在问题中,它具有来自隐式目录的值/tmp/48/tmp/,以及来自模式中的通配符的48。对于这个组合词干,我需要只选择文件名部分$(*F)


或者,注意手册说明:

  

这些变体在GNU make中已经过时了,因为函数dirnotdir可用于获得类似的效果

我们可以改为:

logo_%.png: ${SRC}
    convert $^ -thumbnail $(notdir $*)x$(notdir $*) $@

在评论中,Etan还链接到手册的How Patterns Match部分,以帮助理解如何构建词干。我觉得这很有用,想把它搞定一个答案。