# Makepp's makefile syntax

makepp tries to be extremely compatible with GNU make, so almost everything that GNU make supports in its makefile is supported. If you're not familiar with writing makefiles, you'll want to read the tutorial before reading this file.

Every nonblank line in the makefile is either a comment, a variable assignment, part of a rule, a conditional, or a statement.

Variable syntax
  Details on assigning values to variables, and using those values elsewhere.
Rule syntax
  A rule is what tells makepp the recipe for making a file.
Statement syntax
  A statement is any line that begins with a word, such as `include` or `begin_perl`.
  - `include`
  - `load_makefile`
  - `perl_begin` and `perl_end`
  - `repository`
  - `sub`
Conditionals
  Makepp supports several different ways of selecting different parts of your makefile to use.
Wildcards in makefiles
  Wildcards can be used reliably in rules. Wildcards match either files that currently exist, or files for which there is a build rule.
Filenames with special characters
  If your filenames contain spaces or characters like `"'\:*%`, then makepp may be confused unless you quote them.

## Variable assignment syntax

VARIABLE = text string
  This is the usual assignment statement that all makes support. The expression on the right hand side is not evaluated until the value of `$(VARIABLE)` is actually used somewhere. Thus, if you do the following:

      X = 1
      Y = $(X)
      X = 2

  Then `$(Y)` later in the makefile will evaluate to "2". Leading and trailing whitespace around the text string is stripped; there is at present no way to put trailing whitespace into a variable.
VARIABLE := expr
  This is the same as "VARIABLE = expr" except that the right hand side is evaluated at the time of the assignment. Thus if

      X := 1
      Y := $(X)
      X := 2

  then `$(Y)` later in the makefile will evaluate to "1" since that's what `$(X)` was when `$(Y)` was defined.
VARIABLE += expr
  Appends the string to the variable. If the variable was previously assigned with :=, then the right hand side is evaluated before appending.
VARIABLE ?= expr
  Sets the value of the variable, but only if the variable is not specified earlier in the makefile, on the command line, or in the environment.

### Variable substitution

Makepp's variable substitution rules are similar to those of other makes, but somewhat more powerful. `$(CC)` or `${CC}` both represent the value of the variable CC. If you need a literal dollar sign, put in a double dollar sign (`$$`).

makepp uses rc-style substitution (so called because it was pioneered by the rc shell). This is best illustrated by an example:

    MODULES = a b c d

    mylib.a : module_dir/$(MODULES).o $(OTHER_OBJECTS)
    	$(CXX) $(dependencies) -o $(target)

The prefix `module_dir/` is prepended to each word in MODULES, and the suffix `.o` is appended to each word.

Makepp also supports substitution references. A substitution reference has the form `$(VAR:A=B)`, where A is a pattern to match and B is a pattern to replace it with. For example:

    source_files = a.c b.c c.c d.c
    object_files = $(source_files:%.c=%.o)

will set `$(object_files)` to `a.o b.o c.o d.o`. The `%` is a special character matches any arbitrary string. Substitution references are an abbreviation for the `patsubst` function.

### Automatic variables

makepp supports most of the automatic variables that other versions of make use. In addition, it has less cryptic, longer names for most of them that you can use instead. (For legacy makefiles that redefine these names, the definition in the makefile overrides the default meaning. For example, if you say "`target = abc`" in your makefile, then `$(target)` will always expand to `abc`, and will no longer be equivalent to `$@`.)

`$(target)` or `$(output)` or `$@`
  The target of the current rule. Actually, since makepp supports multiple targets for any rule, this is the first target.
`$(targets)` or `$(outputs)`
  All targets of the current rule. Same as `$(target)` unless there is more than one target.
`$(dependency)` or `$(input)` or `$<`
  The first explicit dependency of the rule.
`$(dependencies)` or `$(inputs)` or `$^`
  All the dependencies of the target, not including `.h` files discovered by scanning for includes.
`$(sorted_dependencies)` or `$(sorted_inputs)` or `$+`
  All the dependencies of the target, in sorted order, with duplicates removed. Equivalent to `$(sort $(inputs))`.
`$?`
  In most make versions, this is the dependencies of the target which have changed. This does not fit into makepp's conceptual framework, because on the next build it will make sure the command is exactly identical to the previous build, or else it considers the file out of date. So makepp attempts to support this variable for backward compatibility by making it equivalent to all dependencies (the same as `$+`).

  This variable has no long name because its use is highly discouraged.

`$(stem)` or `$*`
  The stem in a pattern rule (i.e., whatever the '%' matched). Alternatively, if this is not a pattern rule, recognizes the file name without the extension (i.e., it's equivalent to `$(basename $(input))`.
`$(foreach)`
  The current filename from the `foreach` clause. See below for more details on `foreach`.

### Functions

Any expression of the format `$(name arg1 arg2 arg3)` or `$(name)` where `name` is not the name of a variable, is interpreted as a function call. The name may contain letters, underscores, or hyphens; to avoid confusion, you may use hyphens or underscores interchangeably, since internally hyphens are converted to underscores. Evaluating such an expression simply invokes a perl subroutine. You can define perl subroutines to do whatever you like. See the sub statement and the section on extending makepp for more details.

makepp has a number of builtin functions which may be useful. It supports almost all of GNU make's textual functions (see GNU make's documentation for details), and some of its own. The most useful functions are:

$(`absolute-filename` files)
  Converts relative filenames into absolutes. For example, `$(absolute-filename xyz.c)` might return `/usr/src/our_project/subdir/xyz.c`.
$(`basename` filenames)
  The basename is the entire file name (with the directory), minus the text after the last period. E.g., `$(basename myfile/version-1.0-module.c)` is `myfile/version-1.0-module`
$(`filter` patterns, words)
  Returns all words in the list that match the patterns. Patterns may simply be other words, or they may have a `%` character, which means to match any string at that point.
$(`filter-out` patterns, words)
  Returns all words in the list that do not match the patterns. Patterns may simply be other words, or they may have a `%` character, which means to match any string at that point.
$(`notdir` filenames)
  Returns the non-directory portion of the filename(s).
$(`only-targets` filenames)
  Returns only those filenames in the list that are actually targets of some rule (either explicit or pattern rules). This can be used for a clean target, for example:

      .PHONY: clean

      clean:
      	rm -f $(only_targets *)

  Now if you type `makepp clean`, it will delete everything it knows how to build.

  Note that this refers only to files that are known to be targets at the time you invoke `only-targets`. If `only-targets` appears in the dependencies or actions of a rule, then all possible targets will be known. If you evaluate try to evaluate it earlier in the makefile with a `:=` variable like this:

      ALL_TARGETS := $(only_targets *)

      target1: dependency1
      	actions

      target2: dependency2
      	actions

  then `only_targets` will not know about the subsequent rules.

  Similarly, `only_targets` doesn't know about targets produced in makefiles that are loaded with recursive make.

$(`only-nontargets` filenames)
  Returns only those filenames in the list that are not targets of any rule (either explicit or pattern rules). This can be used for generating a distribution target, for example:

      .PHONY: distribution

      distribution:
      	mkdir our_product-$(VERSION)
      	cp $(filter-out %~, $(only_nontargets *)) our_product-$(VERSION)
      	tar cf - our_product-$(VERSION) | gzip -9c > our_product-$(VERSION).tar.gz

  In this case, the `$(only_nontargets *)` returns every file in the current directory that is not a target of some rule. The `$(filter-out %~, ...)` removes editor backups.

  Similar to `only-targets` (see above), `only-nontargets` only knows about targets that have been defined already. This is only a problem if you use it to define variables with the `:=` assignment.

$(`patsubst` pattern, substitute, words)
  Performs a substitution on each word in the word list. A `%` character matches any string. This is best illustrated by an example:

      OBJS = $(patsubst %.c, object_dir/%.o, $(C_SOURCES))

  takes every file in C_SOURCES and returns the name of an object file in object_dir. Sometimes it is more concise to use a substitution reference, e.g., the above could have been written as

      OBJS = $(C_SOURCES:%.c=object_dir/%.o)

$(`phony` words)
  Indicates that the list of words are actually phony targets, and returns the list of targets. It's intended to be used like this:

      $(phony all): my_program

      $(phony clean):
      	rm -f *.o my_program

  You can also declare one or more targets as phony with a line like this anywhere in your makefile:

      .PHONY: all clean

$(`print` text)
  Outputs the text and returns it. This is mostly useful for debugging, when you don't understand why variable substitution has the result that it does. For example,

      XYZ := $(print $(patsubst %.c, %o, $(SOURCE_FILES)))

  will print out the result of the `patsubst` call.

      XYZ := $(patsubst %.c, %o, $(print $(SOURCE_FILES)))

  will print out the last argument to the `patsubst` call.
$(`shell` shell-command)
  Returns the output from the given shell command, with newlines replaced by spaces.

makepp also supports many other, less useful functions that GNU make has (see the GNU make documentation for details, because I don't feel like typing it in now). (The only ones it does not support are `join`, `foreach`, `origin`, `call`, `error`, and `warning`.) These are intended mainly to support existing makefiles; it's very easy to write your own functions in perl, or to put perl code to manipulate variables directly in your makefile, so you can do any kind of manipulation even if one of these built-in functions isn't adequate.

## Rule syntax

A rule is what tells makepp how to build a file or a class of files. Makepp supports the same rule syntax as other makes, plus some additions of its own.

### Explicit rules

    target1 target2: dependency1 dependency2 ...
    	actions to be performed

This syntax specifies that in order to make either target1 or target2, all the files dependency1, dependency2, etc., must already have been made. Then the given actions are executed by the shell to make the targets. Unlike traditional makes, makepp usually assumes that one invocation of the action makes all of the targets (unless there are no dependencies). For example, one invocation of yacc creates both output files for this rule:

    y.tab.c y.tab.h : parser.y
    	$(YACC) -d parser.y

In some cases, however, makepp will execute the rule actions once for each target, so that old makefiles don't break. This happens if all of the following are true:

- The rule action mentions the automatic variable `$@`. (The synonymns `$(output)` or `$(target)` do not trigger this behavior.)
- The rule action does not mention the automatic variable `$(outputs)` (or its synonymn `$(targets)`).
- This is not a pattern rule, and there is no foreach clause.

For example,

    all test install:
    	for subdir in $(SUBDIRS); do cd $$subdir && $(MAKE) $@; cd ..; done

is a common idiom in makefiles, and makepp supports it. (Note that you should never use recursive make in any new makefiles you write--use the `load_makefile` statement, or implicit makefile loading instead).

The list of targets may not contain any automatic variables (except `$(foreach)`). The dependency list may contain only automatic variables referring to the target (`$(output)`, `$(outputs)`, or their synonymns). The action may contain any automatic variables.

#### Rule actions

If makepp decides that the rule needs to be reexecuted, each line of the rule is executed sequentially, and if any returns a non-zero status, the remainder are not executed (and makepp aborts with an error unless you specified the `-k` option on the command line.) Each action should be only one line. If an action is too long to write conveniently on a single line, you can split it into several lines and put a backslash to indicate that the several lines should be combined into one.

In order to distinguish actions from the next rule, the action should be indented more than the line containing the targets and dependencies. Unlike other implementations of make, makepp doesn't really care how much you indent it or whether you use tab characters rather than spaces (since such things are hard to see by looking at the makefile on the screen). To keep backward compatibility, the rules makepp uses to decide when actions end and the next rule begins are somewhat complicated:

- The first action line must be indented more than the line containing the target.
- If a line is indented by one tab character or 8 spaces or more, then it is considered an action line.
- A blank line or a comment line with the `#` character at the right margin ends the rule, unless the next non-blank line is indented more than 8 spaces (or more than one tab).
- If a line is indented as much or more than the first action line, then it is considered an additional action line.

As with other implementations of make, the first explicit rule in a file is the default target, and is made if you do not specify any targets on the command line.

It is safe to specify wildcards in the dependency list. Wildcards match not only files that exist, but files which can be created given the rules in the makefile. (See below for more information on wildcards.) For example, to build a library from all .o files in a directory, you could write this:

    libmine.a: *.o
    	ar ru $(target) $(dependencies)

This will work even if none of the `.o` files have been created yet.

As usual, the actions must be indented, though (unlike the standard make) makepp doesn't really care how much. The actions are terminated by a line that does not begin with whitespace or a comment.

Normally, each shell command is printed as it is executed. However, if the first word of the action is `noecho` (or if it begins with the character `@`), then the command is not printed. For example,

    %.o: %.cxx
          noecho $(LIBTOOL) -c $(input)

This means that when the libtool command is executed, it is not printed. (Libtool itself usually prints the modified command that it executes, so it's redundant to print it twice.)

Normally, if the shell command returns a non-zero status, then makepp aborts because the command failed. However, some programs incorrectly set the status on exit, or there may be an error which really isn't fatal and shouldn't abort the whole compilation. You can cause makepp to ignore the return status by specifying `ignore_error` as the first word of the command line (or `-` as the first character). For example,

    $(phony distribution):
    	ignore_error rm -r my_program-$(VERSION) # Get rid of previous junk.
    	mkdir my_program-$(VERSION)
    	cp $(FILES) my_program-$(VERSION)
    	tar cf my_program-$(VERSION).tar my_program-$(VERSION)

This command makes a directory, copies a bunch of files into it, and then puts everything into a tar file for distribution. It's a good idea to clean out the previous contents of the directory, if there was anything there previously, and that's what the first line does. The `rm` might fail, but its return status is ignored.

### Pattern rules

A pattern rule is a rule that is applied based on some textual pattern. This is used to apply the same rule to a whole class of files. The syntax is the same as GNU make's pattern rules:

    %.o: %.c
    	$(CC) -c $(input) -o $(output)

This says that any file which matches `*.c` can be converted into the corresponding .o file using the given command. (Note that if you specify the command line option `--percent-subdirs`, then the above rule will also compile `.c` files in subdirectories as well.)

(If you're used to traditional make, you might not recognize the automatic variables `$(input)` and `$(output)`. `$(input)` is a synonymn for `$<`, and `$(output)` is a synonymn for `$@`.)

Note that several pattern dependencies may be supplied. For example, if your `xyz.o` file depends on the corresponding `xyz.cpp` file, and also on a file called `moc_xyz.cpp`, this could be expressed with:

    %.o: %.cpp moc_%.cpp
    	$(CXX) -c $(inputs) -o $(output)

You may also have several pattern targets. For example,

    %.tab.h %.tab.c : %.y
    	yacc -d $(input)
    	mv y.tab.h $(stem).tab.h
    	mv y.tab.c $(stem).tab.c

### :foreach rules

The above pattern rule syntax is powerful enough to support almost all builds, but occasionally it is necessary to do something more complicated. Makepp provides a more powerful syntax: the `:foreach` clause for the rule.

    target-expression : depedency-expression : foreach file-list
    	actions

The variable `$(foreach)` is set in turn to each file matching the file-list, and the target and dependency expressions are evaluated. The file-list may contain wildcards, and these match even files which don't exist yet but which can be built (see the section on wildcards for details).

The above pattern rule can be expressed in this format as follows:

    $(patsubst %.c, %.o, $(foreach)) : $(foreach) : foreach *.c
    	... shell commands here

(In fact, it's converted to that internally.) This is an unwieldy syntax but it is extremely flexible, because the `$(foreach)` variable may appear in any way in the expression. For example, if you want to specify to make a .o file from a .cpp file, but only if a corresponding .h file exists, you could do it like this:

    $(foreach:%.h=%.o) : $(foreach:%.h=%.cpp) : foreach *.h
    	... shell commands here

(This uses the slightly more concise substitution reference syntax rather than calling `patsubst` explicitly. See the section on variable substitution for details.)

### Legacy suffix rules

For backward compatibility, makepp supports the old-style suffix rules.

    .suffix1.suffix2:
    	actions

is equivalent to

    %.suffix2: %.suffix1
    	actions

but much harder to remember.

### Conflicting rules

When there is more than one way to make a file, makepp uses a simple procedure to determine which rule to use.

1. It is an error to have conflicting explicit rules for building a file.
2. Pattern rules and foreach rules with wildcards never override explicit rules. Thus explicit rules can be used to specify exceptions for pattern rules. (Note that simply using a `:foreach` clause doesn't make something a pattern rule. It must have a wildcard (like "*" or "?") as part of the filename in the `:foreach` clause. If it is just an explicit list of files, it is treated as an explicit rule for those files.)
3. When conflicting pattern rules come from different makefiles, rules from "nearer" makefiles override rules from "farther" makefiles. "Nearer" means that the makefile is located closer to the target in the directory hierarchy (i.e., the file name of the target relative to the directory the makefile is run from is shorter). If this doesn't distinguish the makefiles, then the rule from the makefile which is loaded latest is used.
4. Rules later in a makefile override rules that are earlier. (This is backwards from GNU make.) This means that you should put your more general rules earlier, and your more specific rules later. For example,

       %.o: %.c                            # General compilation rule.
       	action

       special_%.o: special_%.c            # Special rule for files with a
       	different action            # "special_" prefix.

### Rule options

Sometimes it is necessary to supply additional options to modify how makepp executes the rule. These options are specified as `:optionname value`, either on the line containing the dependencies, or separated on subsequent lines.

Supplying the options on separate lines may make it possible for you to use the same makefile with makepp and a traditional make. For example,

    target : dependencies
    	: signature target_newer
    	actions

will work fine with a traditional unix make, because it interprets the `: signature` line as a shell command, and a command beginning with a colon does nothing.

`:signature` signature_method

  This tells makepp what algorithm to use to determine if the file is out of date. See the section on signature checking for more details. Legal values for this option are (currently):

  `exact_match`
    Makepp's default algorithm. Insists that all dependencies have the same signature as on the last build, and the build command is the same.
  `target_newer`
    Insists that dependencies be older than the target, but does not check the build command or whether the signatures are the same. This is makepp's default algorithm for all files involved in rebuilding the makefile.
`:scanner` name

  This tells makepp how to scan for include files. Usually, makepp guess how to do this based on the words in the command itself (see the section on scanning for more details). However, if makepp guesses wrongly, you may want to explicitly indicate the scanner, like this:

      %.o: %.abc
      	: scanner c_compilation
      	action here

  This causes makepp to perform the same scanning that it does for C/C++ build commands, even if it doesn't recognize the action as a C compilation.

  Legal values for `:scanner` are (currently):

  `none`
    Don't bother scanning the command or any files at all. Makepp will not know about any dependencies or targets other than those explicitly listed in the rule. This is the default for all commands that makepp does not recognize.
  `c_compilation`
    Uses thes scanner for C/C++ compilation. See the section on scanning for includes for details on what this does.

  The default scanner depends on the command. If you do not specify a `:scanner` option, then the first word of the command is examined. If it looks like a compile command, then makepp will use the `c_compilation` scanner; otherwise it usese the `none` scanner.

  You can write new scanners or change makepp's default scanner by writing your own perl subroutines.

## Statement syntax

A statement is any line beginning with a word which does not have a "`:`" in it. (A colon implies that the line is a rule.) For example, these are statements:

    include extra_rules.mk
    load_makefile subdir

The command word is actually the name of a perl subroutine, and you can define your own perl subroutines to do whatever you want.

Makepp has a number of builtin statements which you may occasionally need to use.

### include

This inserts the contents of another makefile into the current makefile. It can be useful if you have boilerplate files with a number of rules or variables, and each directory only needs to make a few modifications. The `include` statement also used to be commonly used in traditional makes in conjunction with automatic include file scanners, but this is no longer necessary with makepp.

`include` searches the current directory, then the parent of the current directory, then its parent, etc. If it does not find a file of the given name by the time it reaches the top of the directory hierarchy, then it looks in the makepp dadta directory (`/usr/local/share/makepp` if you installed makepp in `/usr/local`) for one of the include files that comes with makepp. If you want to include a template file in every makefile in a whole directory hierarchy, you can place your makefile template at the top directory. The makefiles do not have to know exactly where they are in the hierarchy; each makefile can contain a line like this:

    include standard_definitions.mk

instead of something more complicated, like this:

    include ../../../standard_definitions.mk  # Is this the right number of ..?

You can specify as many files as you want, and variables are allowed:

    include file1 file2 file3 $(other_include_files)

A minor variant on this, the `-include` statement, includes the file if it exists but doesn't generate a fatal error if it does not. The `-include` statement used to be important for include file scanning, but is seldom useful for makepp. (Makepp will not try to make the file and then reread it, unlike GNU make.)

### load_makefile

    load_makefile /some/directory/somewhere/Makefile
    load_makefile subdir
    load_makefile VAR1=value1 VAR2=value2 subdir

This statement causes makepp to cd to the directory containing the makefile and load its rules into makepp's internal database. If you specify just a directory instead of a makefile, `load_makefile` looks for `Makeppfile`, `makefile`, or `Makefile` in that directory.

Any variables you specify with the syntax `VAR=value` (or `VAR="value1 value2"`) are passed to the loaded makefiles. They override any settings in those makefiles, just as if you had typed them on the command line.

Using `load_makefile` is different from the command

    include dir/makefile

in two ways. First, `load_makefile` does not transfer any variables from the top-level makefile into the subordinate makefile; each makefile exists in its own namespace. The subordinate makefile cannot influence the variables in the top-level makefile in any way.

Second, each build command is tagged with the directory of the makefile that it came from. When makepp executes a rule from a different makefile, it first cd's to the directory containing that makefile before executing the command. Makefiles which are seen with the `include` statement are actually treated as part of the makefile that included them, and therefore their rules are not tagged with a different directory.

You usually do not have to load a makefile explicitly, unless it has an unusual name, or it has targets which are not contained in the same directory as the makefile itself, or you have disabled implicit makefile loading. By default, if makepp is trying to build a file and doesn't have a rule to build it, or if it is evaluating a wildcarded filename in a directory, it will automatically attempt to load a makefile from that directory. See the section on building with multiple directories for more details.

You cannot use `load_makefile` to load several makefiles that apply to the same directory. Use `include` for several pieces of the makefile that apply to the same directory, and `load_makefile` for makefiles that apply to different directories.

### perl_begin

This statement introduces a block of code which is interpreted verbatim by perl. It can be useful for defining functions, but you can do this more concisely with the sub statement. A block of perl code in your makefile can be useful for several reasons:

- To set values of variables that depend on things that are easier to access from perl. For example, you can access all of the configuration information that perl knows about your system, including how to build shared libraries, etc. (Type `perldoc Config` if you want to see what configuration information perl has available.)

      perl_begin

      use Config;

      $ARCH = $Config{'archname'};	# Use perl's knowledge of the architecture.
      $CC = $Config{'cc'};		# Use the same C compiler as perl did.
      $SHARED_OBJ_CFLAGS = $Config{'cccdlflags'};
      				# Flags needed to compile objects which will
      				# go into a shared library.
      $SHARED_OBJ_LDFLAGS = $Config{'ccdlflags'} . " " . $Config{'lddlflags'};
      		      		# Linker flags to make a shared library.
      $SHARED_CC_LINK = $Config{'ld'}; # Command to produce shared libraries.

      $SHARED_EXTENSION = $Config{'dlext'}; # Extension of shared libraries.
      if ($ARCH =~ /^i[56]86/) {	# Some sort of intel machine > 486?
        $CFLAGS = "-O6 -malign-double"; # These do better with quadword alignment.
      } else {
        $CFLAGS = "-O6";
      }

      perl_end

      %.o: %.c
      	$(CC) $(CFLAGS) $(SHARED_OBJ_CFLAGS) -c $(input) -o $(output)

      libmylib.$(DLEXT): *.o
      	$(SHARED_CC_LINK) $(inputs) -o $(output) $(SHARED_OBJ_LDFLAGS)

  Note how we define a bunch of variables in the perl block, and then we use them afterwards in the rest of the makefile. You can use the full power of the perl interpreter to set your variables in arbitrarily complicated ways. You can run shell commands from your perl code, access a database, or whatever you want.

- To extend makepp to support building of objects other than files, or to use custom signature checking.

The remainder of the line following the `perl_begin` statement is ignored. All text up until a line that begins at the left margin with `perl_end` is sent verbatim to the perl interpreter.

### repository

Specifies one or more repository directories. The first repository specified has precedence over the others if the same file exists in multiple repositories and there is no build command for it.

If you specify just a directory after `repository`, its contents are linked into the current directory. You can link its contents into any arbitrary place in the file system by specifying the location before an equals sign, e.g,

    repository subdir1/subdir2=/users/joe/joes_nifty_library

### sub

This statement provides a way to define a perl subroutine inside your makefile. The syntax is identical to that of the perl sub statement, except that the closing brace must be at the left margin.

A perl subroutine is invoked whenever a statement is seen, or when an expression like `$(name words)` is seen. For example, suppose that for some reason you need to load the contents of a file into a make variable. (You could do this by saying `$(shell cat filename)` but it's possible to do it without ever invoking the shell.) This can be done by placing the following into your makefile:

    sub f_file_contents {
      my ($filename) = @_;		# Name the arguments.
      my $file_contents;
      open FILE, $filename || die "$!\n";
      my $line;
      while (defined($line = )) {  # Read another line.
        $file_contents .= $line;
      }
      close FILE;

      return $file_contents;
    }

Now, with this function defined, you can write

    X = $(file_contents filename)

and the variable `$(X)` will contain the contents of the given file.

See the section on extending makepp for more details.

## Conditionals

Often it is convenient to do different things in your makefile depending on what architecture you are on, or what set of options you are building with. Makepp supports several ways of doing such conditionals.

`ifeq`, `ifneq`, `ifdef`, and `ifndef`
  These are the conditionals that GNU make supports. Makepp's implementation is completely compatible with GNU make (as far as I know). Later I will update this manual to explain it in more detail, but for the moment, refer to the GNU make manual.
Perl statements in your makefile
  Often your conditionals may be complicated or hard to express using equality/inequality of strings. But you can include perl code verbatim in your makefile. You have access to the full power of the perl interpreter. For example:

      perl_begin

      if ($ARCH =~ /^i[56]86/) {
        $CFLAGS = '-O6 -malign-double';	# On intel machines > 486, there
      					# is a substantial speed penalty
      					# for doubles that aren't quadword aligned.
      } else {
        $CFLAGS = '-O6';
      }

      perl_end

      %.o: %.c
      	$(CC) $(CFLAGS) -c $(input) -o $(output)

  Any make variable can be accessed directly as a perl scalar. In this case, we've set the value of `CFLAGS` differently based on a regular expression match on the architecture flags.

## Wildcards

makepp makes it much safer and more reliable to use wildcards in your makefile. makepp's wildcard expansion returns all existing files that match the wildcard, and all files which do not yet exist but which can be built using the rules. Thus a rule like this:

    libmylib.a : *.o
    	$(CC) $(inputs) -o $(output)

will do exactly what it should, even if none of the .o files exists in the directory yet. (Of course, if you create extra bogus .o files in the directory, makepp has no way of knowing that you don't want them in `mylib.a`.) In other versions of make, the `*.o` wildcard will only return existing object files and so the dependency list will vary depending on what files have been created.

makepp supports all the usual shell wildcards (`*`, `?`, and `[]`). It also has a wildcard `**` which matches any number of intervening directories. (This idea was stolen from zsh.) For example, `**/*.c` matches all the `.c` files in the entire source tree. `objects/**/*.o` matches all the `.o` files contained anywhere in the subdirectory `objects` or any of its subdirectories or any of their subdirectories. The `**` wildcard will not follow soft links to directories.

## Special characters in filenames

makepp can support filenames that have special characters in them like a colon or a space. Suppose, for example, you want to create a file called `a:thing` from the file `b:thing`. You can't write the rule this way:

    a:thing : b:thing
    	commands here

because makepp won't know which colons separate targets from dependencies and which are part of the filenames. Instead, simply enclose the name in quotes, like this:

    "a:thing" : "b:thing"
    	commands here

Now the rule is unambiguous.

makepp's quoting rules are quite similar to the shell's. You can, for example, use single quotes instead of double quotes, or you can escape special characters with a backslash:

    a\:thing : 'b:thing'
    	commands here

Suppose, for example, that your filename is `'"!;\$`. Now why you'd want such a filename I don't know, but here are several ways you could specify it to make (and the shell):

    \''"!;\$$'
    "'\"!;\\$$"

Note that (unlike the shell) variables beginning with `$` are expanded even inside single quotes. Dollar signs cannot be protected by quotes or backslashes. To get a literal dollar sign, use a double dollar sign.

Generally, you should be able to deal with just about any special character by quoting it in some way. This includes spaces, control characters, etc. However, be aware that at present, makepp's comment stripping is somewhat simplistic, and any `#` characters preceded by whitespace will be interpreted as comments no matter how they are quoted.

When a target or dependency name is put into an automatic variable like `$(target)`, then the quotes and any backslashes are stripped. This means that if you want to reference the filename in the actions, you will probably have to quote it again, like this:

    "a file name with spaces":
    	echo "Special contents" > "$@"

If you don't put the quotes around `$@`, then the shell will see the command

    echo "Special contents" > a file name with spaces

which writes the string "Special contents file name with spaces" to the file called `a`. This is probably not what you want.

Table of contents | Next (command line syntax) | Previous (signature checking)
Last modified: Tue Nov 14 15:58:55 PST 2000