【问题标题】:Makefile: operate on all files in a subdirectory?Makefile:对子目录中的所有文件进行操作?
【发布时间】:2017-12-17 17:21:28
【问题描述】:

我正在使用 Makefile 和 GNU make 基于源 Markdown 文件创建各种文档输出目标。

这包括使用latexpdflatex 创建 DVI 文件。使用 EPS 或 PS 格式以外的图像会导致错误。

我可以在源 Markdown 文件中搜索和替换图像名称,并且已经这样做了。

我想做的是为images/ 子目录中的所有图像文件创建一个makefile 规则,并运行convert 来创建这些文件的eps 版本。

所以:

images/myimage1.png
images/myimage2.jpeg

保留,但创建了其他版本:

images/myimage1.eps
images/myimage2.eps

(是的,我必须保持跟踪,否则其他地方没有名称冲突。)

要运行的命令类似于:

convert -format eps images/myimage1.png images/myimage1.eps

我想在任何非 EPS 图像文件上运行它:gif、jpg、jpeg、png、bmp 等。这些将在 Makefile 中特别列出。


这是第一次迭代

它可以工作(以其他错误为模),虽然它有点长,如果扩展 Imagemagick 支持的全部 193 种图形格式将是... 笨重。

我的目标是构建 DVI,所以我展示了相关的目标

dvi: docfs-Manifesto.dvi
latex: docfs-Manifesto.tex
epsimg.md: docfs-Manifesto.md

docfs-Manifesto.tex: docfs-Manifesto-epsimg.md all-img 
    pandoc -s --from=markdown --to=latex -o docfs-Manifesto.tex docfs-Manifesto-epsimg.md

docfs-Manifesto-epsimg.md: docfs-Manifesto.md
    ./img-ref-to-eps.sed docfs-Manifesto.md > docfs-Manifesto-epsimg.md

docfs-Manifesto.dvi: latex
    pdflatex -output-format dvi -halt-on-error docfs-Manifesto.tex 2>pdflatex.log

MG_DIR=images
EPS_DIR=images-eps

# We can handle any of about 193 formats Imagemagick will read, but
# let's start with some basics

# ... Source formats
SRC_GIF = $(wildcard $(IMG_DIR)/*.gif)
SRC_JPG = $(wildcard $(IMG_DIR)/*.jpg)

# ... Destination formats
EPS_GIF = $(patsubst $(IMG_DIR)/%.gif,$(EPS_DIR)/%.eps,$(SRC_GIF))
EPS_JPG = $(patsubst $(IMG_DIR)/%.jpg,$(EPS_DIR)/%.eps,$(SRC_JPG))


# And the actual conversions.  This ... could be shorter?

all-img: $(EPS_DIR) $(EPS_GIF) $(EPS_JPG) 
    @echo "Done"

$(EPS_DIR) :
    mkdir $(EPS_DIR)

$(EPS_DIR)/%.eps : $(IMG_DIR)/%.gif
    convert -format eps $< $@

$(EPS_DIR)/%.eps : $(IMG_DIR)/%.jpg
    convert -format eps $< $@

(我认为这就是所有相关规则)

它成功了,因为它失败了我的转换脚本 转换失败。

但这不是 Make 的错。


现在通过 foreach 循环处理代码长度

我们做到了! 77 行代码减少到 17 行(包括空格)。

IMG_DIR=images
EPS_DIR=images-eps

# We can handle any of about 193 formats Imagemagick will read, but
# let's start with some basics
# Thanks @kebs: https://stackoverflow.com/a/47857821/9105048

IMG_EXT=bmp dot gif jpg jpeg png raw tiff xcf pnm ppm ps

# ... Source formats

IMG_FILES = $(wildcard $(IMG_DIR)/*)

# Rename files s/./_/ so: img1.gif => img1_gif Then add extension

IMG_FILES2 = $(subst .,_,$(IMG_FILES))

EPS_FILES = $(patsubst $(IMG_DIR)/%,$(EPS_DIR)/%.eps,$(IMG_FILES2))

all-img: $(EPS_DIR) $(EPS_FILES)
@echo "all-img: done"

$(EPS_DIR) :
    mkdir $(EPS_DIR)

$(foreach \
prereq, \
$(IMG_EXT), \
$(eval $(EPS_DIR)/%_$(prereq).eps: $(IMG_SRC)/%.$(prereq); convert -format eps $$< $$@) \
)

当前输出(跟随make clean):

$ make all-img
convert -format eps images/browser-of-a-scientist.jpg images-eps/browser-of-a-scientist_jpg.eps
convert -format eps images/nukewaste.jpg images-eps/nukewaste_jpg.eps
convert -format eps images/standards.png images-eps/standards_png.eps
$ ls images-eps/
browser-of-a-scientist_jpg.eps standards_png.eps
nukewaste_jpg.eps 

【问题讨论】:

  • 好的,所以你需要一些通配符匹配和模式规则。但在继续之前,您能否向我们展示您已经拥有的代码?
  • @kebs:这里没有与问题相关的代码。我有一个 Makefile 可以生成我想要的大部分输出,尽管 DVI 生成器由于使用 JPG 和 PNG 文件而失败,如前所述。目录结构是docs,带有一个降价文件和一个images/ 子目录。如图所示,我现在在 shell 中运行了 Imagemagick 代码。
  • 要检查变量,添加一个没有依赖关系的规则(例如,print:),并以@echo $(SRC_GIF); @echo $(EPS_GIF) 作为配方。

标签: makefile gnu-make


【解决方案1】:

试试这样的:

SRC_DIR=images
SRC_FILES1 = $(wildcard $(SRC_DIR)/*.png)
SRC_FILES2 = $(wildcard $(SRC_DIR)/*.jpeg)

DEST_FILES1 = $(patsubst $(SRC_DIR)/%.png,$(SRC_DIR)/%.eps,$(SRC_FILES1))
DEST_FILES2 = $(patsubst $(SRC_DIR)/%.jpeg,$(SRC_DIR)/%.eps,$(SRC_FILES2))

all: $(DEST_FILES1) $(DEST_FILES2)
     @echo "Done"

$(SRC_DIR)/%.eps : $(SRC_DIR)/%.png
    convert -format eps $< $@

$(SRC_DIR)/%.eps : $(SRC_DIR)/%.jpeg
    convert -format eps $< $@

但是,如果您同时拥有 image1.pngimage1.jpeg,这将失败。

要处理其他图像类型,您需要复制其他图像类型的规则和变量。但是我认为如果您在另一个文件夹中构建 eps 文件,则可以避免这种情况(顺便说一句,它被称为“源代码外”构建,主要思想是您不要混合源文件并在同一个文件夹中构建文件)。如果你这样做,我认为你可以设法只有一个变量和构建规则。


编辑好的,我想我有一个解决方案来简化这一切:

首先,定义一个变量来保存所有需要的文件类型(阅读:扩展名):

EXT=gif png jpg jpeg

然后,构建一个包含所有图像的变量(假设这里只有图像,这是请求的):

SRC_FILES = $(wildcard $(SRC_DIR)/*)

然后我们需要构建相应的目标变量来保存所有输入文件,但扩展名为 .eps。我们不能直接使用patsubst,因为它不能进行多个扩展。所以我们需要一个技巧:将img1.gif 替换为img1_gif,然后添加.eps 扩展名。这分两步完成:

首先,将输入文件中的. 替换为_

DEST1 = $(subst .,_,$(SRC_FILES))

其次,添加.eps扩展名(假设输出文件夹为out):

DEST2 = $(patsubst $(SRC_DIR)/%,out/%.eps,$(DEST1))

好的,现在我们完成了:

all: $(DEST2)
    @echo "Done"

嗯,不完全是。最后的技巧来了:使用foreach 函数从EXT 变量中自动生成所有需要的配方:

$(foreach \
    prereq, \
    $(EXT), \
    $(eval out/%_$(prereq).eps: $(SRC_DIR)/%.$(prereq); convert -format eps $$< $$@) \
)

这将在prereq 中实例化EXT 中的所有值,并调用eval 函数来生成配方。

【讨论】:

  • 那么,一个好的OOS位置可能是什么?一个子目录,“图像/eps”?还是一个并行目录,比如 images/ 和 eps/?
  • 名称冲突问题的替代方法是重命名文件包括源扩展名,因此:myimage1.png => myimage1.png.eps。尴尬但更安全。
  • 我正在解决这个问题,并进行了一些扩展。事实证明,大约有 193 种可能的图像文件转换,因此合理化这些可能是有意义的(基于 identify -list format)。目前我有 12 种格式(bmp、dot、gif、jpg、jpeg、png、raw、tiff、xcf、pnm、ppm、ps),这已经足够了。另外,如果我要使用我拥有的 makefile 更新我的问题,围绕这些部分的标准做法是什么?
  • what might a good OOS location be? 绝对是第二选择,将输出文件夹设为源的子文件夹是一种不好的方法。
  • 非常感谢。这确实是有效解决方案的基础。
猜你喜欢
  • 2015-02-01
  • 2015-01-16
  • 2013-02-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多