Makefile:对子目录中的所有文件进行操作?

问题描述 投票:2回答:1

我正在使用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图形格式将是... unweildy。

我的目标是建立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 
makefile gnu-make
1个回答
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文件可以避免这种情况(推荐使用BTW,它被称为“out of source”版本,主要的想法是你不要在同一个文件夹中混合源文件和构建文件)。如果你这样做,我认为你可以设法只有一个变量和构建规则。


编辑好吧,我想我有一个解决方案来简化所有这些:

首先,定义一个包含所有所需文件类型的变量(读取:扩展):

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函数来生成配方。


推荐问答