Specific syntax for lines in the makefile



Last revision August 4, 2004

Table of contents:
  1. Managing programming source code with make
  2. How does make work?
  3. Specific syntax for lines in the makefile
  4. Specific syntax for the make command line

This section describes the specific syntax and use of different types of lines in the makefile: target lines, command lines, and macro definitions. There are many subtleties and special features fully described in the make documentation.

Macro definitions, target dependencies, and processing commands must fit on a single logical line. If you have too much information to fit on one physical line, you can continue onto the next physical line by putting a backslash (\) as the last character of the line to be continued. The backslash, newline, and any blanks or tabs at the beginning of the next line are replaced by a single blank when the file is processed, thus logically joining the two physical lines.

Comment lines

Just as in shell scripts, the # character indicates that the # and all following characters in the line are a comment that is to be ignored. Use comment lines to make notes to yourself and others about the purpose of various commands in the makefile. Example:
      # Math library needed when linking this program.

Target file dependencies

Lines with an embedded colon (:) are processed as dependency descriptions. The name to the left of the colon is the target file; the names to the right of the colon are the files that the target depends upon. These are usually the files that are combined or processed in some way to create the target, either directly or indirectly. These files are the "generators" of the target.

There can actually be more than one target name to the left of the colon if two or more targets share the same set of generators.

Target file names refer to files in the current directory by default, but you can specify full pathnames to other directories if desired. You can use the shell wildcard file specifications * and ? in either target or generator file names. They will be applied to locate files in the current or specified directory. The C-shell special file matching character ~, which stands for "home directory", cannot be used.

You can have "pseudo-targets" that do not describe file dependencies but rather are used to invoke some maintenance function. These pseudo-targets do not have any dependencies upon other files; the list of generators after the colon is empty. When you tell the make program to check that this pseudo-target is up to date, it simply performs all the commands associated with that target.

Examples of target file dependency lines:

  • A single target file representing the final program that depends on two object files that must be created first.
      bigsim : bigsim.o subs.o
  • Two different object files both depend upon a single include file.
      bigsim.o subs.o : defs.h
  • A common pseudo-target in the makefile is
      clean:
    Followed simply by a command to "cleanup" the directory by removing all .o files, core files, and other temporary intermediate files. You execute the clean function with the Unix command:
      make clean
  • Another common pseudo-target is
      install:
    Followed by commands to install the final executables in the desired system directories.

Processing commands

You generally need to specify at least one command in your makefile to create the final target program or file from its generators. Although make has default rules for compiling source code modules into object modules, it has no default for linking those modules together.

Command lines must immediately follow the target line to which they apply, and start with a tab character. Alternatively, you can put a command on the same line as the target file specification, separated by a semi-colon character (;).

There can be more than one command specified for a single target line. Just start each one with a tab character and put them one after another. Any individual command can be continued onto more than one line by putting a backslash (\) as the last character of the line to be continued.

A command line can be a complex command (pipe, sequential processes, etc.), just as if typed at the terminal, however, the Bourne shell, not the C-shell, is used to execute the command, so don't rely upon any special C-shell features like variable substitution or "if-then" conditions. Check the manual entry for sh to see the equivalent syntax for the Bourne shell. Alternatively, if you want to specify a command in a makefile using C-shell syntax, enclose the entire command within a set of single quotes (') and preface it with csh -c. This will force an instance of the C-shell to start up and process that quoted command line.

After substituting for macros, each command line is executed in a separate shell process. This means that environmental changes, particularly cd, only affect that single command line.

Normally, if a command returns a non-zero (error) status code, make stops any further processing of the makefile. You can tell it to ignore the non-zero status code from a specific command by starting that command with a hyphen (-) character; the hyphen is a signal to make; it is stripped from the command before the command is passed to the shell to be executed. This is especially useful in a clean or install target that may have more than one command.

Here are examples of commands following target lines. In these examples, <tab> stands for the TAB character.

  • Target line for main program specifies a command line to link it with special libraries.
      bigsim : bigsim.o subs.o
      <tab> cc -o bigsim bigsim.o subs.o -lloc -lvplot
  • install target line is followed by commands to install the program and an auxiliary file that it needs
      install :
      <tab> installbsd -s bigsim /usr/local/bin
      <tab> cp -p bigsim.config /usr/local/etc
  • clean target line is followed by a command to remove all intermediate files. Because they may not exist when clean target is specified, include the hyphen character at the beginning of the command. This tells make to continue even if there is an error from the remove command:
      clean:
      <tab> -rm *.o core a.out

Macro definitions

Macros provide a mechanism for text substitution within the makefile. That is, the macro is a type of variable that can be used as a shorthand for a longer or common piece of text. Macros can be used anywhere in a makefile: as target or dependency names or lists, as parts of commands, or even in the definitions of other macros.

The general form to define a macro in a makefile is:
      macroname=string_of_characters
macroname is a single "word" using only alphanumeric characters; as always, case is significant. The string_of_characters on the right hand side of the equals sign is any arbitrary text, including embedded blanks, up to the end of the line; it can be continued onto the next line(s) by using a backslash (\) as the last character on the line(s) to be continued. This text does not need to be quoted. It becomes the value of the macro.

Specifically, any line containing an equals sign (=) not preceded by a colon or tab is processed as a macro definition.

Macro definitions or re-definitions (overriding what is in the makefile) can also appear on the command line that you type to start the make program.

Macro substitution is invoked in the makefile by preceding the macro name with a dollar sign ($). If the macro name is longer than one character, it must be enclosed in a set of matching parentheses or curly braces. This syntax is different from C-shell variable substitution! To use a real dollar sign elsewhere in the file, type $$.

Examples:

  • Define the macro named a with the line
      a = sub1.o sub2.o
    Then substitute for "a" in a target line, for instance, with
      prog: $a
  • Define the macro named subs with the line
      subs = sub1.o sub2.o sub3.o
    Use it like
      prog: $(subs)

make uses many pre-defined macros to control its normal operation. You can re-define some of these in your makefile to change how make works. For example, when make automatically runs the compiler to turn a source code file into an object code module, it passes a standard set of options to the compiler. Those options are defined in the macros CFLAGS for the C compiler and FFLAGS for the Fortran compiler. If you want to completely change those default compilation options, you can simply redefine those macros, for example:
     FFLAGS=-u -C -g
This tells make to use the -u option (force explicit variable typing), -C option (check array subscripts), and -g option (include information for the debugger) when compiling all Fortran source code files specified in this makefile.

Note that the -c compiler option is always used by make when compiling source code files, so that automatic linking will not be attempted. You do not need to include this option when setting CFLAGS or FFLAGS.

You can also just add another option to the existing compiler option list. For example,
      FFLAGS=$FFLAGS -u
resets the Fortran compiler options macro (FFLAGS) to be its original value with the new option -u appended.

Check the make documentation to learn the names of other pre-defined macros and their default values.

Comments or Questions?