User Tools

Site Tools


wiki:make:patterns_rules

Automatic Variables

We have some redundancy in our current makefile. We repeat the dependencies in the command. We can remove this redundancy by using the somewhat cryptic $^. $^ is an automatic variable: it means “all the prerequisites of this rule”.

  #This is a makefile for analyzing molecule data   
  result.dat: sorted_lengths.txt
          ./middle.sh $^ -5 -3
          
  sorted_lengths.txt: *.pdb
          ./sorted_lengths.sh $^

There are other automatic variables as well: for example, $< means “the first prerequisite in the list”, $@ means the target, and $? means “all prerequisites that are out of date”. Don't worry if you can't remember them: Now you can recognize them and if needed look them up by googling “make automatic variables”.

If we delete our result.dat and sorted_lengths.txt and run make again we see:

  $ rm result.dat
  $ rm sorted_lengths.txt
  $ make
  ./sorted_lengths.sh cubane.pdb ethane.pdb methane.pdb octance.pdb pentane.pdb propane.pdb
  ./middle.sh sorted_lengths.txt -5 -3

Who can explain why now all the .pdb files are in the command instead of *.pdb?

Macros

We may want to change the lines that are being selected by the middle.sh. It can be cumbersome to search through a large makefile for an individual command to edit a part of it. We can do this by defining a macro, just as we would define a constant or variable in a program. Here's our Makefile with a macro defined and used:

  #This is a makefile for analyzing molecule data   
  
  END_LINE=-5
  LINES=-3
  
  result.dat: sorted_lengths.txt
          ./middle.sh $^ ${END_LINE} ${LINES}
          
  sorted_lengths.txt: *.pdb
          ./sorted_lengths.sh $^
          

The definition looks like definitions in most programming languages: the macros are called END_LINE and LINES, and their values are -5 and -3. To use the macro, we put a dollar sign in front of it (just as we would do in the shell) and wrap its name in curly brackets. This tells Make to insert the macro's value.

This is certainly a step forward: now, when we want to move our Makefile from one machine to another, we only have to change one definition in one place.

Parenthesizing Macros in Make

We have to put curly brackets or parentheses around a macro's name when we use it; we can't just write $MACRO. If we do, Make will interpret it as $M (a reference to the macro `M`) followed by “ACRO”. Since we probably don't have a macro called M, $M will expand to the empty string, so $MACRO without parentheses will just be “ACRO”.

Why?

To make a long story short, it's another wart left over from its history. Almost everyone trips over it occasionally, and as with other bugs, it can be very hard to track down.

It's common practice to use macros to define all the flags that tools need, so that if a tool is invoked in two or more actions, it's passed a consistent set of flags.

We can also define a macro like $LINES on the command line each time we run Make. To do this, we set the variable on the command line when invoking make:

  $ make LINES=-4

This is almost always a bad idea, though. We have to remember to type the definition each time, and we have to type it correctly each time. This isn't too bad with just one definition, but is infeasible when there are half a dozen. There's also no record in the Makefile itself of the flag, which makes life harder for other people who want to re-create our work: how do they know what to type?

Pattern Rules

Sometimes we want to create an output for each one of our inputs. This often happens in compiling where each source code file is turned into a compiled binary file.

For example a common rule for a fortran code is:

  %.o: %.f90
       gfortran -c $^

In this rule, % is a wildcard. When it is expanded, it has the same value on both sides of the rule: if it matches '1' on the left, it must match '1' on the right as well. % only means something to Make, though. It doesn't have a value in the rule's action, which is handed off to the shell for execution. So in the action, we have to use the automatic variables $^.

Here all binary files .o depend on all fortran 90 source code files .f90. % ensures that all the targets correspond to all .f90 files make can find in the directory.

Why is the make wildcard % better to use here than the shell wild card *? Like '*.o : *.f90?

We will see a detailed example of this in the next section on managing the building of programs with make.

wiki/make/patterns_rules.txt · Last modified: 2022/07/21 06:59 by 127.0.0.1