3.3 Macros


Variables are fine for storing values as a single line of text, but what if we have a multiline value such as a command script we would like to execute in several places? For instance, the following sequence of commands might be used to create a Java archive (or jar ) from Java class files:

 echo Creating $@... $(RM) $(TMP_JAR_DIR) $(MKDIR) $(TMP_JAR_DIR) $(CP) -r $^ $(TMP_JAR_DIR) cd $(TMP_JAR_DIR) && $(JAR) $(JARFLAGS) $@ . $(JAR) -ufm $@ $(MANIFEST) $(RM) $(TMP_JAR_DIR) 

At the beginning of long sequences such as this, I like to print a brief message. It can make reading make 's output much easier. After the message, we collect our class files into a clean temporary directory. So we delete the temporary jar directory in case an old one is left lying about, [2] then we create a fresh temporary directory. Next we copy our prerequisite files (and all their subdirectories) into the temporary directory. Then we switch to our temporary directory and create the jar with the target filename. We add the manifest file to the jar and finally clean up. Clearly, we do not want to duplicate this sequence of commands in our makefile since that would be a maintenance problem in the future. We might consider packing all these commands into a recursive variable, but that is ugly to maintain and difficult to read when make echoes the command line (the whole sequence is echoed as one enormous line of text).

[2] For best effect here, the RM variable should be defined to hold rm -rf . In fact, its default value is rm -f , safer but not quite as useful. Further, MKDIR should be defined as mkdir -p , and so on.

Instead, we can use a GNU make "canned sequence" as created by the define directive. The term "canned sequence" is a bit awkward , so we'll call this a macro . A macro is just another way of defining a variable in make , and one that can contain embedded newlines! The GNU make manual seems to use the words variable and macro interchangeably. In this book, we'll use the word macro specifically to mean variables defined using the define directive and variable only when assignment is used.

 define create-jar  @echo Creating $@...  $(RM) $(TMP_JAR_DIR)  $(MKDIR) $(TMP_JAR_DIR)  $(CP) -r $^ $(TMP_JAR_DIR)  cd $(TMP_JAR_DIR) && $(JAR) $(JARFLAGS) $@ .  $(JAR) -ufm $@ $(MANIFEST)  $(RM) $(TMP_JAR_DIR) endef 

The define directive is followed by the variable name and a newline. The body of the variable includes all the text up to the endef keyword, which must appear on a line by itself. A variable created with define is expanded pretty much like any other variable, except that when it is used in the context of a command script, each line of the macro has a tab prepended to the line. An example use is:

 $(UI_JAR): $(UI_CLASSES)         $(create-jar) 

Notice we've added an @ character in front of our echo command. Command lines prefixed with an @ character are not echoed by make when the command is executed. When we run make , therefore, it doesn't print the echo command, just the output of that command. If the @ prefix is used within a macro, the prefix character applies to the individual lines on which it is used. However, if the prefix character is used on the macro reference, the entire macro body is hidden:

 $(UI_JAR): $(UI_CLASSES)         @$(create-jar) 

This displays only:

 $  make  Creating ui.jar... 

The use of @ is covered in more detail in the Section 5.1.2 in Chapter 5.

Managing Projects with GNU make
Managing Projects with GNU Make (Nutshell Handbooks)
ISBN: 0596006101
EAN: 2147483647
Year: 2003
Pages: 131

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net