Makefile:对子目录中的所有文件进行操作吗? [英] Makefile: operate on all files in a subdirectory?
问题描述
我正在使用Makefile和GNU make基于源Markdown文件创建各种文档输出目标.
I am using a Makefile and GNU make to create various document output targets based on a source Markdown file.
这包括使用latex
或pdflatex
创建DVI文件.使用非EPS或PS格式的图像会导致错误.
This includes using latex
or pdflatex
to create a DVI file. Use of images in other than EPS or PS formats causes errors.
我可以在源Markdown文件中搜索并替换图像名称,并且已经做到了.
I can search-and-replace image names within the source markdown file, and have done so.
我想做的是为images/
子目录中的所有图像文件创建一个makefile规则,然后运行convert
创建这些文件的eps版本.
What I'd like to do is create a makefile rule for all image files in the images/
subdirectory, and to run convert
to create eps versions of those files.
所以:
images/myimage1.png
images/myimage2.jpeg
已保留,但已创建其他版本:
Are retained, but have additional versions created:
images/myimage1.eps
images/myimage2.eps
(是的,我必须保持跟踪,否则在其他地方不会发生名称冲突.)
(And yes, I've got to keep track otherwise that there aren't name collisions elsewhere.)
要运行的命令类似于:
convert -format eps images/myimage1.png images/myimage1.eps
我想在所有非EPS图像文件上运行此文件:gif,jpg,jpeg,png,bmp等.这些文件将在Makefile中专门列出.
I'd want to run this on any non-EPS image files: gif, jpg, jpeg, png, bmp, etc. These will be specifically listed in the Makefile.
虽然有点长,但如果扩展了,它仍然可以工作(对其他错误取模) 到Imagemagick支持的全部193种图形格式将是... 不耐烦.
It works (modulo other errors), though it's a bit long, and if extended to the full 193 graphics formats supported by Imagemagick would be ... unweildy.
我的目标是构建DVI,因此我展示了相关目标
My goal here is to build the DVI, so I'm showing the related targets
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 $< $@
(我认为这是所有相关规则)
(I think that's all the relevant rules)
它成功了,因为它在我的转换脚本中出现了图像失败 转换失败.
And it succceeds, in that it fails with an image my conversion script had failed to convert.
但这不是Make的错.
But that's not Make's fault.
我们知道了! 77行代码减少到17行(包括空格).
And we've got it! 77 lines of code reduced to 17 (inclusive of whitespace).
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
之后):
Current output (following 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
推荐答案
尝试如下操作:
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.png
和image1.jpeg
,则此操作将失败.
However, this will fail if you have both image1.png
and image1.jpeg
.
要处理其他图像类型,您将需要复制其他图像类型的规则和变量.但是我认为,如果您在另一个文件夹中构建eps文件,可以避免这种情况(建议BTW,这被称为源外"构建,主要思想是您不要混合源文件并在同一文件夹中构建文件).如果这样做,我认为您只能设法拥有一个变量和构建规则.
To process other image types, you will need to replicate the rules and variables for the other image types. But I think this could be avoided if you build the eps files in another folder (which is BTW recommended, it's called an "out of source" build, the main idea is you don't mix source files and build files in the same folder). If you do so, I think you can manage to have only one variable and build rule.
编辑,好的,我想我有一个简化所有步骤的解决方案:
EDIT ok, I think I have a solution to simplify all that:
首先,定义一个变量,其中包含所有需要的文件类型(读取:扩展名):
First, define a variable holding all the needed file types (read: extensions):
EXT=gif png jpg jpeg
然后,构建一个包含所有图像的变量(假设这里仅图像,这是必需的):
Then, build a variable holding ALL your images (assuming there are only images here, this is requested):
SRC_FILES = $(wildcard $(SRC_DIR)/*)
然后,我们需要构建包含所有输入文件但扩展名为.eps的相应目标变量.我们不能直接使用patsubst
,因为它不能继续使用倍数扩展名.因此,我们需要一个技巧:用img1_gif
替换img1.gif
,然后添加.eps扩展名.这分两个步骤完成:
Then we need to build the corresponding target variables holding all the input files, but with .eps extension. We can't use patsubst
directly because it cannot proceed with multiples extensions. So we need a trick: replace img1.gif
by img1_gif
and then add the .eps extension. This is done in two steps:
首先,在输入文件中将.
替换为_
:
First, replace .
by _
in the input files:
DEST1 = $(subst .,_,$(SRC_FILES))
第二,添加.eps扩展名(假设输出文件夹为out
):
Second, add the .eps extension (assuming the output folder is out
):
DEST2 = $(patsubst $(SRC_DIR)/%,out/%.eps,$(DEST1))
好的,我们完成了:
all: $(DEST2)
@echo "Done"
嗯,不完全是.这是最后一个技巧:使用foreach
函数从EXT
变量自动生成所有需要的配方:
Well, not quite. Here comes the final trick: use the foreach
function to generate automatically all the needed recipes from the EXT
variable:
$(foreach \
prereq, \
$(EXT), \
$(eval out/%_$(prereq).eps: $(SRC_DIR)/%.$(prereq); convert -format eps $$< $$@) \
)
这将在prereq
中实例化EXT
中的所有值,并调用eval
函数来生成配方.
This will instanciate in prereq
all the values in EXT
and call the eval
function to generate the recipe.
这篇关于Makefile:对子目录中的所有文件进行操作吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!