10

I have the following Makefile:

all: generate print # <-- doesn't work

date: 
    date > date.txt

ls:
    ls -la > ls.txt

generate: ls date

print: *.txt
    cat $^

clean:
    rm *.txt

The targets date and ls generate a file each, the target print, prints them out.

How do I write the target all, so that it first generates the files and then prints it?

scrrr
  • 5,135
  • 7
  • 42
  • 52
  • Hm, I think what I really need is that the wildcard expansion in print happens later. Because of what I just read here: http://www.gnu.org/software/make/manual/html_node/Secondary-Expansion.html I think this is not possible. *.txt is evaluated before generate is called. So what I am trying to do will probably not work. – scrrr Mar 26 '14 at 10:09

3 Answers3

13

Just add the pipe symbol:

all: | generate print

From the make manual:

Order-only prerequisites can be specified by placing a pipe symbol (|) in the prerequisites list: any prerequisites to the left of the pipe symbol are normal; any prerequisites to the right are order-only:

targets : normal-prerequisites | order-only-prerequisites
Hawken MacKay Rives
  • 1,171
  • 1
  • 16
  • 26
akond
  • 15,865
  • 4
  • 35
  • 55
  • 3
    I think the problem is that the inputs for print are evaluated at the very beginning (when the *.txt wildcard matches nothing), so this doesn't work either. Hm – scrrr Mar 26 '14 at 09:56
  • 2
    How is this a valid answer? Order-only prerequisites are not an answer to the question. They only order the execution of their own respective recipe without the need to update the target! They have nothing to do with execution order! https://stackoverflow.com/a/24856711/5737988 – BUFU Sep 08 '20 at 14:24
3

The dependancy hierarchy of the rules you want is all -> print -> generate. 'print' should be dependant on 'generate'.

The Makefile you have is interesting. On first pass it generates the .txt files using { all -> generate -> ls, date } hierarchy but the print fails. On second pass if you don't do clean it works.

The 'print' rule you have is a valid rule. But doesn't allow make to know that you need to do the 'generate' actions before doing the 'print'.

You could EXplicitly make a print rule which says it is dependant on generating date.txt and ls.txt. Try change your 'all' and 'print' rules like this . . .

EDIT: SORRY! First Answer I gave doesn't work. Tested it. This works.

all: print # <- just print target here as you don't want generate to happen after print
.
print: generate ls.txt date.txt
    cat $^

Make could decide to do print action first and the generate action afterwards if print is not made dependant on the files explicitly or generate.

This works but we get an error as the cat of non existant file generate doesn't work.

Taking this a bit further . . . Get rid of the generate rule. And I think the date and ls rule would be better if they explicitly detailed what file they generated, i.e.

all: print

date.txt:
    date > date.txt

ls.txt:
    ls -la > ls.txt

print: ls.txt date.txt
    cat $^

*.txt. If you want to operate on multiple files with same extension then you can do different things e.g. put the list of files in a make variable. You can have a make rule to calculate this list of files (using shell cmd in make). But that make rule cannot be dependant on the files already existing if it is the thing that is generating them.

The make manual gives a rule very close to your original print rule - using wildcard in rule prerequisites. http://www.gnu.org/software/make/manual/make.html#Wildcard-Examples

Make has quite a simple hierarchy of dependancies. Make will follow dependancies in order. Getting your head around the sequence a makefile will follow can be tricky but it is actually quite simple enough so well worth while working on understanding it.

It is a common problem for makefiles for some part of make system to be missing a dependancy on another. Often build systems will get away with this but sometimes it can cause weirdness (e.g. object files being compiled after being linked in).

The make manual has a good introduction. http://www.gnu.org/software/make/manual/make.html#Introduction

gaoithe
  • 4,218
  • 3
  • 30
  • 38
  • 1
    Thank you, gaoithe. See my comment below the question, though. I think the problem is the time of wildcard-expansion which cannot be solved easily, except, as you correctly said, by listing the files explicitly. And thus avoiding wildcards altogether. – scrrr Mar 26 '14 at 10:10
  • The wildcards make following what make will do a bit harder to follow. I would have thought using the order-only prerequisites rule as in akond's answer would work . . . but it doesn't. Hmm. Interesting. http://www.gnu.org/software/make/manual/make.html#Wildcard-Pitfall I think discusses this problem you have exactly. – gaoithe Mar 26 '14 at 16:12
  • Ad suggested by http://www.gnu.org/software/make/manual/make.html#Wildcard-Function using wildcard in print . . . also DOESN'T work. Makefile executes an empty cat. (Need to hit ctrl-D to cause it to carry on). `print: $(wildcard *.txt)`. Putting the wildcard into variable the result is same. So yes, I think it comes down to having to have an explicit link all the way through rules to target. – gaoithe Mar 26 '14 at 16:18
  • Understand: make will read and parse ALL the makefiles entirely FIRST before it starts to run any of the recipes. At the time make parses the rule `print : *.txt` it must expand the wildcard so that it knows how to construct the internal graph of dependencies. At that time, there are no files matching `*.txt`. Using the `wildcard` function doesn't change this fundamental role: the makefiles are always parsed first. I don't know why you need `print` to depend on these files; why don't you just use the rule: `print: ; cat *.txt` ? – MadScientist Jan 04 '17 at 22:58
2

Secondary Expansion not work for me.

I choose to delay wildcard call by use another make in recipe:

all: generate
    $(MAKE) print
Nate Scarlet
  • 551
  • 5
  • 7