1

Goal I write my slides in a markdown file and compile it to reveal afterwards, uploading it to my webserver and do other things. I wanted to organise the steps after the markdown is written in a makefile:

PROJNAME = `pwd | grep -oP '(\w|-)+' | tail -n 2 | head -n 1 | tr '[:upper:]' '[:lower:]'`

presentation: slides.pandoc
    pandoc --self-contained --data-dir=$(HOME)/.pandoc --template=slides/revealjs_niels_tmpl.html -V revealjs-url:$(HOME)/.pandoc/revealjs -V theme:solarized slides.pandoc -f markdown -t revealjs -o $(PROJNAME).html

onlinepresent: $(PROJNAME).html
    cp $(PROJNAME).html $(HOME)/Share/index.html

Explanation PROJNAME looks for the project folder name and converts it to lowercase. In the example folder where I am using it and which generates the message shown in the Title, this results in ws-anno-ii. The presentation rule compiles the slides as html by using pandoc. The PROJNAME Macro is used to define the name of the output file. onlinepresent where make is stopping should copy a file which holds the project name (ws-anno-ii.html) if this file exists to a mounted external filesystem (Share). If it does not exist, of course the presentation rule should apply first. But when I put the make command nothing happens, and I get the message

The make process stops with Makefile:6: *** multiple target patterns. Stop. referring to the line onlinepresent: $(PROJNAME).html

Can anyone explain to me why this is happening?

1

The value of the make variable PROJNAME is

`pwd | grep -oP '(\w|-)+' | tail -n 2 | head -n 1 | tr '[:upper:]' '[:lower:]'`

The backquote character is not special in make. If you use the variable in a shell command, the shell sees the backquotes and parses them as a command substitution. But if you use the variable in a place where it's interpreted by make, the backquotes don't do anything special. The line onlinepresent: $(PROJNAME).html becomes, after variable expansion,

onlinepresent: `pwd | grep -oP '(\w|-)+' | tail -n 2 | head -n 1 | tr '[:upper:]' '[:lower:]'`.html

which make parses as onlinepresent, colon, `pwd, \, grep, -oP, '(\w|-)+', |, tail, -n, 2, |, head, -n, 1, |, tr, '[, colon, upper, colon, ]', '[, colon, lower, colon, ]'`.html. There are multiple words to the left of the rightmost colon, hence “multiple target patterns”.

If you want to use the output of a shell command in a place where make will read it, you need to invoke the shell function. This is a GNU make feature, it won't work in other make implementations.

PROJNAME = $(shell pwd | grep -oP '(\w|-)+' | tail -n 2 | head -n 1 | tr '[:upper:]' '[:lower:]'`)

This sets the PROJNAME variable to the next-to-last component of working directory transformed to lowercase.

Note that using the current directory is fragile: it means your makefile won't work if invoked from a different directory as the target. It would be more robust to compute PROJNAME from the path to the target. If it wasn't for the lowercase part, you could do it entirely (if cumbersomely) with make functions (I assume that the intent of your splitting code is really to extract pathname components):

$(notdir $(patsubst %/,%,$(dir $(patsubst %/,%,$(dir $(abspath $@))))))

but GNU make doesn't have a case conversion facility. If you're going to invoke a shell anyway, you can make it simpler.

PROJNAME = $(shell set -x; echo '$(abspath $@)' | awk -F/ '{$$0=tolower($$0); print $$(NF-2)}')
onlinepresent: $(PROJNAME).html
        cp $< $$HOME/Share/index.html

Note the use of $$ in the makefile which becomes $ in the shell commands. This works because the PROJNAME variable is calculated on each use, not at the time of definition (variable definitions in make are expanded on each use if they use =, and when the assignment is read if they use :=).

0

When you run make onlinepresent, make goes to the target onlinepresent and sees that it requires $(PROJNAME).html, which is kind of wrong ... from the point of view of make, because there is no target providing directly $(PROJNAME).html.

I am also assuming that your assignment of PROJNAME has only one possible result.

Try with

presentation: slides.pandoc
#your pandoc rule
onlinepresent: presentation
#your mv command

This tells make that in order to make the target onlinepresent, the target presentation is required. Then the target presentation tells make that slides.pandoc is required, so it will run the rule if slides.pandoc is new or has been modified.

OR

You can also try renaming the target presentation to $(PROJNAME).html instead, so that it looks like

$(PROJNAME).html: slides.pandoc
#your pandoc rule
onlinepresent: $(PROJNAME).html
#your mv command
  • The first solution does always use both rules, even if there were no changes made since the last make process. / The second solutions complains with: Makefile:3: *** target pattern contains no `%'. Stop. – Cutú Chiqueño Oct 9 '15 at 10:35
  • from the most voted answer in stackoverflow.com/questions/15113138/…: This is a badly written error message from Make. It means "one of your filenames had a character that could be part of a regular expression" ... so check your variable contents to be sure that Make is not getting something wrong. The fact that the "presentation" target is always executed even if no change was done to the file confuses me... are your sure that pandoc does not alter in anyway (not even touch the file?) – dave_alcarin Oct 9 '15 at 11:25
  • Thank you! I had already a look at the stackoverflow question you mention. The Str which is generated in the example for PROJNAME is 'ws-anno-ii'. I already tried to add | tr '-' '\-' to the line where PROJNAME is defined following the advice from the stackoverflow question but this does not change anything, still the same error. / In the presentation solution the dependent file for the presentation rule is slides.pandoc. It was modified yesterday evening for the last time following ls. B the way make is GNU Make 4.1 – Cutú Chiqueño Oct 9 '15 at 12:22
  • I now tried the makefile with the PROJNAME resulting in wsannoii, so no character that can be interpreted as a regular expression and still I get the same result. Is it possible that it is not allowed to use macros for a target? – Cutú Chiqueño Oct 9 '15 at 13:25
  • You can use variables as target name, see here ftp.gnu.org/old-gnu/Manuals/make-3.79.1/html_chapter/… – dave_alcarin Oct 9 '15 at 14:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.