Makefile: operate on all files in a subdirectory?

一曲冷凌霜 提交于 2019-12-12 17:30:47

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!