0
votes

Update: GNU Make 3.81, Ubuntu 12.04

I have a set of markdown files that I want to compile to (say) html files, so this is my rule:

%.html: %.md
    pandoc $< -o $@

So make foo.html would convert foo.md into foo.html.

However, there are spaces in the source markdown filenames and I do not have the ability to control these, that is I can't change a setting to remove the spaces.

This means if I make foo\ bar.html, I get

make: *** No rule to make target `foo bar.html'. Stop.

How can I write a generic rule %.html: %.md where the prerequisite filename has spaces?

I can get around it by using:

foo\ bar.html: foo\ bar.md
    pandoc $< -o $@

But then I must manually write out this rule for every such source file that I have, when I'd rather use the % construct. Is my only hope to do some sort of $(foreach f,$(get list of *.md files),$(eval $(call function_to_generate_rule)))?

2
Make really doesn't handle spaces in target names well. I suspect that any solution you find will be an ugly kludge.Beta
In trying to reproduce your issue, putting %.html: %.md markdown $< > $@, I cannot get the make error about not finding the target. Which version of make are you using?binki
You do know that for make to do inference properly, the source file foo bar.md has to either exist or be something that make knows how to build, right?binki
@binki: of course, foo bar.md does exist. GNU make 3.81. I can reproduce this.mathematical.coffee
OK, I see the issue on GNU make 3.81 on Windows but not on GNU make 3.82 on GNU.binki

2 Answers

2
votes

It seems from what @binki says that GNU make 3.82 might not have this issue, but unfortunately I do not have the option to update from v3.81 that is on my Ubuntu 12.04 machine.

I managed to "solve" it like so by using SECONDEXPANSION to substitute spaces with backslash-space in the prerequisite (so a prerequisite of foo bar.md becomes foo\ bar.md).

# define a variable with a single space
space:=
space+=

.SECONDEXPANSION:
%.html: $$(subst $$(space),\$$(space),%).md
   pandoc "$<" -o "$@"

Here is the log. Again, works on Ubuntu 12.04/GNU Make 3.81, perhaps if you have 3.82 you can use @binki's solution which seems more elegant.

1
votes

Edit

Apparently make’s support for whitespace in inference rules depends on what variant of GNU Make you are using. It just magically works fine with Gentoo’s patched sys-devel/make-3.82-r4 (and fails with Gentoo’s make 3.81-r2). I did not notice any explanation in make-3.82’s ChangeLog or NEWS or the Gentoo patches when quickly checking them. So implicit rules working with whitespace could just be a fluke in make-3.82 itself or even from Gentoo’s patchset. Official GNU support for whitespace in targets is tracked in the still-open GNU Make bug #712.

Original misguided answer

You can use any quoting characters that your shell supports. make ignores them when performing macro substitution and passes them directly to the shell. For example,

.SUFFIXES: .md .html
.md.html:
    pandoc "$(<)" > "$(@)"

results in $ make foo\ bar.html passing the shell pandoc "foo bar.md" > "foo bar.html". I decided to use the traditional style of specifying generic make rules instead of the GNU Make extension involving %, but you can do this with GNU Make’s %-style rules too, I assume.

This does not solve the potential problem of the filenames containing quote characters in them. I think that, simply, most people just avoid putting " or ' in filenames because of the likelihood of causing issues with Makefiles or other scripts. Or you could use a GNU Makefile extension to replace the " characdter with \", something that makes sh happy (we’re going to just ignore cmd for now because I don’t even…):

.SUFFIXES: .md .html
.md.html:
    pandoc "$(subst ",\",$(<))" > "$(subst ",\",$(@))"

This was tested with a file called a"b"c.md which succeeded in creating a"b"c.html (disclaimer: I used discount’s markdown command instead of pandoc).