问题
I am using a Makefile and GNU make to create various document output targets based on a source Markdown file.
This includes using latex or pdflatex to create a DVI file. Use of images in other than EPS or PS formats causes errors.
I can search-and-replace image names within the source markdown file, and have done so.
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.
So:
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.)
The command to be run would be something like:
convert -format eps images/myimage1.png images/myimage1.eps
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.
And here's the first iteration
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.
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.
But that's not Make's fault.
Now tackling the code length via a foreach loop
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 $$< $$@) \
)
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
回答1:
Try something like this:
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 $< $@
However, this will fail if you have both image1.png and image1.jpeg.
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)/*)
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))
Second, add the .eps extension (assuming the output folder is out):
DEST2 = $(patsubst $(SRC_DIR)/%,out/%.eps,$(DEST1))
Ok, now we are done:
all: $(DEST2)
@echo "Done"
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 $$< $$@) \
)
This will instanciate in prereq all the values in EXT and call the eval function to generate the recipe.
来源:https://stackoverflow.com/questions/47857614/makefile-operate-on-all-files-in-a-subdirectory