[ Previous | Next | Table of Contents | Index | Library Home | Legal | Search ]

General Programming Concepts: Writing and Debugging Programs


Chapter 14. make Command

This chapter provides information about simplifying the recompiling and relinking processes using the make command. It is a useful utility that can save you time when managing projects.

The make program is most useful for medium-sized programming projects. It does not solve the problems of maintaining more than one source version and of describing large programs (see sccs command).

The make command assists you in maintaining a set of programs, usually pertaining to a particular software project. It does this by building up-to-date versions of programs.

In any project, you normally link programs from object files and libraries. Then, after modifying a source file, you recompile some of the sources and relink the program as often as required.

The make command simplifies the process of recompiling and relinking programs. It allows you to record, once only, specific relationships among files. You can then use the make command to automatically perform all updating tasks.

Using the make command to maintain programs, you can:

The make command requires a description file, file names, specified rules to tell the make program how to build many standard types of files, and time stamps of all system files.


Creating a Description File

The make program uses information from a description file that you create to build a file containing the completed program, which is then called a target file. The description file tells the make command how to build the target file, which files are involved, and what their relationships are to the other files in the procedure. The description file contains the following information:

By checking the dates of the parent files, the make program determines which files to create to get an up-to-date copy of the target file. If any parent file was changed more recently than the target file, the make command creates the files affected by the change, including the target file.

If you name the description file makefile or Makefile and are working in the directory containing that description file, enter:

make

to update the first target file and its parent files. Updating occurs regardless of the number of files changed since the last time the make command created the target file. In most cases, the description file is easy to write and does not change often.

To keep many different description files in the same directory, name them differently. Then, enter:

make -f Desc-File

substituting the name of the description file for the Desc-File variable.

Format of a make Description File Entry

The general form of an entry is:

target1 [target2..]:[:] [parent1..][; command]...
[(tab) commands]

Items inside brackets are optional. Targets and parents are file names (strings of letters, numbers, periods, and slashes). The make command recognizes wildcard characters such as * (asterisk) and ? (question mark). Each line in the description file that contains a target file name is called a dependency line. Lines that contain commands must begin with a tab character.

Note: The make command uses the $ (dollar sign) to designate a macro. Do not use that symbol in file names of target or parent files, or in commands in the description file unless you are using a predefined make command macro.

Begin comments in the description file with a # (pound sign). The make program ignores the # and all characters that follow it. The make program also ignores blank lines.

Except for comment lines, you can enter lines longer than the line width of the input device. To continue a line on the next line, put a \ (backslash) at the end of the line to be continued.

Using Commands in a make Description File

A command is any string of characters except a # (pound sign) or a new-line character. A command can use a # only if it is in quotes. Commands can appear either after a semicolon on a dependency line or on lines beginning with a tab that immediately follows a dependency line.

When defining the command sequence for a particular target, specify one command sequence for each target in the description file, or else separate command sequences for special sets of dependencies. Do not do both.

To use one command sequence for every use of the target file, use a single : (colon) following the target name on the dependency line. For example:

test:        dependency list1...
         command list...
            .
            .
            .
test:        dependency list2...

defines a target name, test, with a set of parent files and a set of commands to create the file. The target name, test, can appear in other places in the description file with another dependency list.

However, that name cannot have another command list in the description file. When one of the files that test depends on changes, the make command runs the commands in that one command list to create the target file named test.

To specify more than one set of commands to create a particular target file, enter more than one dependency definition. Each dependency line must have the target name, followed by :: (two colons), a dependency list, and a command list that the make command uses if any of the files in the dependency list changes. For example:

test::      dependency list1...
         command list1...
test::      dependency list2...
         command list2...

defines two separate processes to create the target file, test. If any of the files in dependency list1 changes, the make command runs command list1. If any of the files in dependency list2 changes, the make command runs command list2. To avoid conflicts, a parent file cannot appear in both dependency list1 and dependency list2.

Note: The make command passes the commands from each command line to a new shell. Be careful when using commands that have meaning only within a single shell process; for example, cd and shell commands. The make program forgets these results before running the commands on the next line.

To group commands together, use the \ (backslash) at the end of a command line. The make program then continues that command line into the next line in the description file. The shell sends both of these lines to a single new shell.

Calling the make Program from a Description File

To nest calls to the make program within a make command description file, include the $(MAKE) macro in one of the command lines in the file.

If the -n flag is set when the $(MAKE) macro is found, the new copy of the make command does not execute any of its commands, except another $(MAKE) macro. Use this characteristic to test a set of description files that describe a program. Enter the command:

make -n

The make program does not perform any of the program operations. However, it does write all of the steps needed to build the program, including output from lower-level calls to the make command.

Preventing the make Program from Writing Commands

To prevent the make program from writing the commands while it runs, do any of the following:

Preventing the make Program from Stopping on Errors

The make program normally stops if any program returns a nonzero error code. Some programs return status that has no meaning.

To prevent the make command from stopping on errors, do any of the following:

Example of a Description File

For example, a program named prog is made by compiling and linking three C language files x.c, y.c, and z.c. The x.c and y.c files share some declarations in a file named defs. The z.c file does not share those declarations. The following is an example of a description file, which creates the prog program:

# Make prog from 3 object files
prog: x.o y.o z.o
# Use the cc program to make prog
    cc  x.o y.o z.o -o prog
# Make x.o from 2 other files
x.o:   x.c defs
# Use the cc program to make x.o
    cc -c x.c
# Make y.o from 2 other files
y.o: y.c defs
# Use the cc program to make y.o
    cc  -c y.c
# Make z.o from z.c
z.o:   z.c
# Use the cc program to make z.o
    cc  -c z.c

If this file is called makefile, just enter the command:

make

to update the prog program after making changes to any of the four source files: x.c, y.c, z.c, or defs.

Making the Description File Simpler

To make this file simpler, use the internal rules of the make program. Based on file-system naming conventions, the make command recognizes three .c files corresponding to the needed .o files. This command can also generate an object from a source file, by issuing a cc -c command.

Based on these internal rules, the description file becomes:

# Make prog from 3 object files
prog:  x.o y.o z.o
# Use the cc program to make prog
    cc  x.o y.o z.o -o prog
# Use the file defs and the .c file
# when making x.o and y.o
x.o y.o:   defs

Internal Rules for the make Program

The internal rules for the make program are in a file that looks like a description file. When the -r flag is specified, the make program does not use the internal rules file. You must supply the rules to create the files in your description file. The internal-rules file contains a list of file-name suffixes (such as .o, or .a) that the make command understands, plus rules that tell the make command how to create a file with one suffix from a file with another suffix. If you do not change the list, the make command understands the following suffixes:

.a Archive library.
.C C++ source file.
.C\~ SCCS file containing C++ source file.
.c C source file.
.c~ Source Code Control System (SCCS) file containing C source file.
.f FORTRAN source file.
.f~ SCCS file containing FORTRAN source file.
.h C language header file.
.h~ SCCS file containing C language header file.
.l lex source grammar.
.l~ SCCS file containing lex source grammar.
.o Object file.
.s Assembler source file.
.s~ SCCS file containing assembler source file.
.sh Shell-command source file.
.sh~ SCCS file containing shell-command source file.
.y yacc-c source grammar.
.y~ SCCS file containing yacc-c source grammar.

The list of suffixes is similar to a dependency list in a description file, and follows the fake target name .SUFFIXES. Because the make command looks at the suffixes list in left-to-right order, the order of the entries is important.

The make program uses the first entry in the list that satisfies the following two requirements:

The make program creates the name of the rule from the two suffixes of the files that the rule defines. For example, the name of the rule to transform a .c file to an .o file is .c.o.

To add more suffixes to the list, add an entry for the fake target name .SUFFIXES in the description file. For a .SUFFIXES line without any suffixes following the target name in the description file, the make command erases the current list. To change the order of the names in the list, erase the current list and then assign a new set of values to .SUFFIXES.

Example of Default Rules File

The following example shows a portion of the default rules file:

# Define suffixes that make knows.
.SUFFIXES:  .o .C .C\~ .c .c~ .f .f~ .y .y~ .l .l~ .s .s~ .sh .sh~ .h .h~ .a
 #Begin macro definitions for
#internal macros
YACC=yacc
YFLAGS=
ASFLAGS=
LEX=lex
LFLAGS=
CC=cc
CCC=xlC
AS=as
CFLAGS=
CCFLAGS=
# End macro definitions for
# internal macros
# Create a .o file from a .c
# file with the cc program.
c.o:
         $(CC) $(CFLAGS) -c $<

# Create a .o file from
# a .s file with the assembler.
s.o:
         $(AS)$(ASFLAGS) -o $@ $<

.y.o:
# Use yacc to create an intermediate file
         $(YACC) $(YFLAGS) $<
# Use cc compiler
         $(CC) $(CFLAGS) -c y.tab.c
# Erase the intermediate file
         rm y.tab.c
# Move to target file
         mv y.tab.o $@.
.y.c:
# Use yacc to create an intermediate file
         $(YACC) $(YFLAGS) $<
# Move to target file
         mv y.tab.c $@

Single-Suffix Rules

The make program has a set of single-suffix rules to build source files directly into a target file name that does not have a suffix (command files, for example). The make program also has rules to change the following source files with suffix to object files without a suffix:

.C: From a C++ language source file.
.C\~: From an SCCS C++ language source file.
.c: From a C language source file.
.c~: From an SCCS C language source file.
.sh: From a shell file.
.sh~: From an SCCS shell file.

For example, to maintain the cat program, enter:

make cat

if all of the needed source files are in the current directory.

Using the Make Command with Archive Libraries

Use the make command to build libraries and library files. The make program recognizes the suffix .a as a library file. The internal rules for changing source files to library files are:

.C.a C++ source to archive.
.C\~.a SCCS C++ source to archive.
.c.a C source to archive.
.c~.a SCCS C source to archive.
.s~.a SCCS assembler source to archive.
.f.a Fortran source to archive.
.f~.a SCCS Fortran source to archive.

Changing Macros in the Rules File

The make program uses macro definitions in the rules file. To change these macro definitions, enter new definitions for each macro on the command line or in the description file. The make program uses the following macro names to represent the language processors that it uses:

AS For the assembler.
CC For the C compiler.
CCC For the C++ compiler.
YACC For the yacc command.
LEX For the lex command.

The make program uses the following macro names to represent the flags that it uses:

CFLAGS For C compiler flags.
CCFLAGS For C++ compiler flags.
YFLAGS For yacc command flags.
LFLAGS For lex command flags.

Therefore, the command:

make "CC=NEWCC"

directs the make command to use the NEWCC program in place of the usual C language compiler. Similarly, the command:

make "CFLAGS=-O"

directs the make command to optimize the final object code produced by the C language compiler.

To review the internal rules that the make command uses, refer to the /usr/ccs/lib/make.cfg file.

Defining Default Conditions in a Description File

When the make command creates a target file but cannot find commands in the description file or internal rules to create a file, it looks at the description file for default conditions. To define the commands that the make command performs in this case, use the .DEFAULT target name in the description file:

.DEFAULT:
                command
                command
                   .
                   .
                   .

Because .DEFAULT is not a real target file, it is called a fake target. Use the .DEFAULT fake target name for an error-recovery routine or for a general procedure to create all files in the program that are not defined by an internal rule of the make program.

Including Other Files in a Description File

Include files other than the current description file by using the word include as the first word on any line in the description file. Follow the word with a blank or a tab, and then the file name for the make command to include in the operation.

Note: Only one file is supported per include statement.

For example:

include /home/tom/temp

include /home/tom/sample

directs the make command to read the temp and sample files and the current description file to build the target file.

Do not use more than 16 levels of nesting with the include files feature.


Defining and Using Macros in a Description File

A macro is a name (or label) to use in place of several other names. It is a way of writing the longer string of characters in shorthand. To define a macro:

  1. Start a new line with the name of the macro.
  2. Follow the name with an = (equal sign).
  3. To the right of the = (equal sign), enter the string of characters that the macro name represents.

The macro definition can contain blanks before and after the = (equal sign) without affecting the result. The macro definition cannot contain a : (colon) or a tab before the = (equal sign).

The following are examples of macro definitions:

# Macro -"2" has a value of "xyz"
2 = xyz
 
# Macro "abc" has a value of "-ll -ly"
abc = -ll -ly
 
# Macro "LIBES" has a null value
LIBES =

A macro that is named, but not defined, has the same value as the null string.

Using Macros in a Description File

After defining a macro in a description file, use the macro in description file commands by putting a $ (dollar sign) before the name of the macro. If the macro name is longer than one character, put ( ) (parentheses) or { } (braces) around it. The following are examples of using macros:

$(CFLAGS)
$2
$(xy)
$Z
$(Z)

The last two examples in the previous list have the same effect.

The following fragment shows how to define and use some macros:

# OBJECTS is the 3 files x.o, y.o and
# z.o (previously compiled)
OBJECTS = x.o y.o z.o
# LIBES is the standard library
LIBES = -lc
# prog depends on x.o y.o and z.o
prog:  $(OBJECTS)
# Link and load the 3 files with
# the standard library to make prog
      cc $(OBJECTS) $(LIBES) -o prog

The make program using this description file links and loads the three object files (x.o, y.o, and z.o) with the libc.a library.

A macro definition entered on the command line overrides any duplicate macro definitions in the description file. Therefore, the command:

make "LIBES= -ll"

loads the files with the lex (-11) library.

Note: When entering macros with blanks in them on the command line, put " " (double quotation marks) around the macro. Without the double quotation marks, the shell interprets the blanks as parameter separators and not as part of the macro.

The make command handles up to 10 levels of nested macro expansion. Based on the definitions in the following example:

macro1=value1

macro2=macro1

the expression $($(macro2)) would evaluate to value1.

The evaluation of a macro occurs each time the macro is referenced. It is not evaluated when it is defined. If a macro is defined but never used, it will never be evaluated. This is especially important if the macro is assigned values that will be interpreted by the shell, particularly if the value might change. A variable declaration such as:

OBJS = 'ls *.o'

could change in value if referenced at different times during the process of building or removing object files. It does not hold the value of the ls command at the time the OBJS macro is defined.

Internal Macros

The make program has built-in macro definitions for use in the description file. These macros help specify variables in the description file. The make program replaces the macros with one of the following values:

$@ Name of the current target file.
$$@ Label name on the dependency line.
$? Names of the files that have changed more recently than the target.
$< Parent file name of the out-of-date file that caused a target file to be created.
$* Name of the current parent file without the suffix.
$% Name of an archive library member.

Target File Name

If the $@ macro is in the command sequence in the description file, the make command replaces the symbol with the full name of the current target file before passing the command to the shell to be run. The make program replaces the symbol only when it runs commands from the description file to create the target file.

Label Name

If the $$@ macro is on the dependency line in a description file, the make command replaces this symbol with the label name that is on the left side of the colon in the dependency line. For example, if the following is included on a dependency line:

cat:     $$@.c

the make program translates it to:

cat:     cat.c

when the make command evaluates the expression. Use this macro to build a group of files, each of which has only one source file. For example, to maintain a directory of system commands, use a description file like:

# Define macro CMDS as a series
# of command names
CMDS = cat dd echo date cc cmp comm ar ld chown
# Each command depends on a .c file
$(CMDS):      $$@.c
# Create the new command set by compiling the out of
# date files ($?) to the target file name ($@)
         $(CC) -O $? -o $@

The make program changes the $$(@F) macro to the file part of $@ when it runs. For example, use this symbol when maintaining the usr/include directory while using a description file in another directory. That description file is similar to the following:

# Define directory name macro INCDIR
INCDIR = /usr/include
# Define a group of files in the directory
# with the macro name INCLUDES
INCLUDES = \
         $(INCDIR)/stdio.h \
         $(INCDIR)/pwd.h \
         $(INCDIR)/dir.h \
         $(INCDIR)/a.out.h \
# Each file in the list depends on a file
# of the same name in the current directory
$(INCLUDES):       $$(@F)
# Copy the younger files from the current
# directory to /usr/include
         cp $? $@
# Set the target files to read only status
         chmod 0444 $@

This description file creates a file in the /usr/include directory when the corresponding file in the current directory has been changed.

Younger Files

If the $? macro is in the command sequence in the description file, the make command replaces the symbol with a list of parent files that have been changed since the target file was last changed. The make program replaces the symbol only when it runs commands from the description file to create the target file.

First Out-of-Date File

If the $< macro is in the command sequence in the description file, the make command replaces the symbol with the name of the file that started the file creation. The file name is the name of the parent file that was out-of-date with the target file, and therefore caused the make command to create the target file again.

In addition, use a letter (D or F) after the < (less-than sign) to get either the directory name (D) or the file name (F) of the first out-of-date file. For example, if the first out-of-date file is:

/home/linda/sample.c

then the make command gives the following values:

$(<D)   =   /home/linda
$(<F)   =   sample.c
$<      =   /home/linda/sample.c

The make program replaces this symbol only when the program runs commands from its internal rules or from the .DEFAULT list.

Current File-Name Prefix

If the $* macro is in the command sequence in the description file, the make command replaces the symbol with the file-name part (without the suffix) of the parent file that the make command is currently using to generate the target file. For example, if the make command is using the file:

test.c

then the $* macro represents the file name test.

In addition, use a letter (D or F) after the * (asterisk) to get either the directory name (D) or the file name (F) of the current file.

For example, the make command uses many files (specified either in the description file or in the internal rules) to create a target file. Only one of those files (the current file) is used at any moment. If that current file is:

/home/tom/sample.c

then the make command gives the following values for the macros:

$(*D)  =  /home/tom
$(*F)  =  sample
$*     =  /home/tom/sample

The make program replaces this symbol only when running commands from its internal rules (or from the .DEFAULT list), but not when running commands from a description file.

Archive Library Member

If the $% macro is in a description file, and the target file is an archive library member, the make command replaces the macro symbol with the name of the library member. For example, if the target file is:

lib(file.o)

then the make command replaces the $% macro with the member name, file.o.

Changing Macro Definitions in a Command

When macros in the shell commands are defined in the description file, you can change the values that the make command assigns to the macro. To change the assignment of the macro, put a : (colon) after the macro name, followed by a replacement string. The form is as follows:

$(macro:string1=string2)

When the make command reads the macro and begins to assign the values to the macro based on the macro definition, the command replaces each string1 in the macro definition with a value of string2. For example, if the description file contains the macro definition:

FILES=test.o sample.o form.o defs

you can replace the form.o file with a new file, input.o, by using the macro in the description-file commands, as follows:

cc -o $(FILES:form.o=input.o)

Changing the value of a macro in this manner is useful when maintaining archive libraries. For more information, see the ar command.


How the make Command Creates a Target File

The make command creates a file containing the completed program called a target file, using a step-by-step procedure.

The make program:

  1. Finds the name of the target file in the description file or in the make command
  2. Ensures that the files on which the target file depends exist and are up-to-date
  3. Determines if the target file is up-to-date with the files it depends on.

If the target file or one of the parent files is out-of-date, the make program creates the target file using one of the following:

If all files in the procedure are up-to-date when running the make program, the make command displays a message to indicate that the file is up-to-date, and then stops. If some files have changed, the make command builds only those files that are out-of-date. The command does not rebuild files that are already current.

When the make program runs commands to create a target file, it replaces macros with their values, writes each command line, and then passes the command to a new copy of the shell.


Using the make Command with Source Code Control System (SCCS) Files

The SCCS command and file system is primarily used to control access to a file, track who altered the file, why it was altered, and what was altered. An SCCS file is any text file controlled with SCCS commands. Using non-SCCS commands to edit SCCS files can damage the SCCS files. See Chapter 23, Source Code Control System (SCCS) to learn more about SCCS.

All SCCS files use the prefix s. to set them apart from regular text files. The make program does not recognize references to prefixes of file names. Therefore, do not refer to SCCS files directly within the make command description file. The make program uses a different suffix, the ~ (tilde), to represent SCCS files. Therefore, .c~.o refers to the rule that transforms an SCCS C language source file into an object file. The internal rule is:

.c~.o:
         $(GET) $(GFLAGS) -p  $<  >$*.c
         $(CC) $(CFLAGS) -c $*.c
         -rm -f $*.c

The ~ (tilde) added to any suffix changes the file search into an SCCS file-name search, with the actual suffix named by the . (period) and all characters up to (but not including) the ~ (tilde). The GFLAGS macro passes flags to the SCCS to determine which SCCS file version to use.

The make program recognizes the following SCCS suffixes:

.C\~ C++ source
.c~ c source
.y~ yacc source grammar
.s~ Assembler source
.sh~ Shell
.h~ Header
.f~ FORTRAN
.l~ lex source

The make program has internal rules for changing the following SCCS files:

.C\~.a:

.C\~.c:

.C\~.o:

.c~:

.c~.a:

.c~.c:

.c~.o:

.f~:

.f~.a:

.f~.o:

.f~.f:

.h~.h:

.l~.o:

.s~.a:

.sh~:

.s~.o:

.y~.c:

.y~.o:

Description Files Stored in the Source Code Control System (SCCS)

If you specify a description file, or a file named makefile or Makefile is in the current directory, the make command does not look for a description file within SCCS. If a description file is not in the current directory and you enter the make command, the make program looks for an SCCS file named either s.makefile or s.Makefile. If either of these files are present, the make command uses a get command to direct SCCS to build the description file from that source file. When the SCCS generates the description file, the make command uses the file as a normal description file. When the make command finishes executing, it removes the created description file from the current directory.


Using the make Command with Non-Source Code Control System (SCCS) Files

Start the make program from the directory that contains the description file for the file to create. The variable name desc-file represents the name of that description file. Then, enter the command:

make -f desc-file

on the command line. If the name of the description file is makefile or Makefile, you do not have to use the -f flag. Enter macro definitions, flags, description file names, and target file names along with the make command on the command line as follows:

make [flags] [macro definitions] [targets]

The make program then examines the command-line entries to determine what to do. First, it looks at all macro definitions on the command line (entries that are enclosed in quotes and have equal signs in them) and assigns values to them. If the make program finds a definition for a macro on the command line different from the definition for that macro in the description file, it chooses the command-line definition for the macro.

Next, the make program looks at the flags. For more information, see the make command for a list of the flags that it recognizes.

The make program expects the remaining command-line entries to be the names of target files to be created. Any shell commands enclosed in back quotes that generate target names are performed by the make command. Then the make program creates the target files in left-to-right order. Without a target file name, the make program creates the first target file named in the description file that does not begin with a period. With more than one description file specified, the make command searches the first description file for the name of the target file.


How the make Command Uses the Environment Variables

Each time the make command runs, it reads the current environment variables and adds them to its defined macros. Using the MAKEFLAGS macro or the MFLAGS macro, the user can specify flags to be passed to the make command. If both are set, the MAKEFLAGS macro overrides the MFLAGS macro. The flags specified using these variables are passed to the make command along with any command-line options. In the case of recursive calls to the make command, using the $(MAKE) macro in the description file, the make command passes all flags with each invocation.

When the make command runs, it assigns macro definitions in the following order:

  1. Reads the MAKEFLAGS environment variable.

    If the MAKEFLAGS environment variable is not present or null, the make command checks for a non-null value in the MFLAGS environment variable. If one of these variables has a value, the make command assumes that each letter in the value is an input flag. The make program uses these flags (except for the -f, -p, and -d flags, which cannot be set from the MAKEFLAGS or MFLAGS environment variable) to determine its operating conditions.

  2. Reads and sets the input flags from the command line. The command line adds to the previous settings from the MAKEFLAGS or MFLAGS environment variable.
  3. Reads macro definitions from the command line. The make command ignores any further assignments to these names.
  4. Reads the internal macro definitions.
  5. Reads the environment. The make program treats the environment variables as macro definitions and passes them to other shell programs.

Example of a Description File

The following example description file could maintain the make program. The source code for the make command is spread over a number of C language source files and a yacc grammar.

# Description file for the Make program
# Macro def: send to be printed
P = qprt
#  Macro def: source filenames used
    FILES = Makefile version.c defs main.c \
            doname.c misc.c files.c \
            dosy.c gram.y lex.c gcos.c
    # Macro def: object filenames used
    OBJECTS = version.o main.o doname.o \
              misc.o files.o dosys.o \
              gram.o
    # Macro def: lint program and flags
    LINT = lint -p
    # Macro def: C compiler flags
    CFLAGS = -O
    # make depends on the files specified
    # in the OBJECTS macro definition
    make:    $(OBJECTS)
    # Build make with the cc program
             cc $(CFLAGS) $(OBJECTS) -o make
    # Show the file sizes
             @size make

# The object files depend on a file
 # named defs
    $(OBJECTS):  defs
    # The file gram.o depends on lex.c
    # uses internal rules to build gram.o
    gram.o:  lex.c
    # Clean up the intermediate files
    clean:
             -rm *.o gram.c
             -du
    # Copy the newly created program
    # to /usr/bin and deletes the program
    # from the current directory
    install:
             @size make /usr/bin/make
             cp make /usr/bin/make ; rm make
    # Empty file "print" depends on the
    # files included in the macro FILES
    print:   $(FILES)
    # Print the recently changed files
             pr $? | $P
    # Change the date on the empty file,
    # print, to show the date of the last
    # printing
             touch print

# Check the date of the old
    # file against the date
    # of the newly created file
    test:
             make -dp | grep -v TIME >1zap
             /usr/bin/make -dp | grep -v TIME >2zap
             diff 1zap 2zap
             rm 1zap 2zap
    # The program, lint, depends on the
    # files that are listed
    lint:    dosys.c doname.c files.c main.c misc.c \
             version.c gram.c
    # Run lint on the files listed
    # LINT is an internal macro
             $(LINT) dosys. doname.c files.c main.c \
             misc.c version.c gram.c
             rm gram.c
    # Archive the files that build make
    arch:
             ar uv /sys/source/s2/make.a $(FILES)

The make program usually writes out each command before issuing it.

The following output results from entering the simple make command in a directory containing only the source and description file:

cc -O -c version.c
cc -O -c main.c
cc -O -c doname.c
cc -O -c misc.c
cc -O -c files.c
cc -O -c dosys.c
yacc  gram.y
mv y.tab.c gram.c
cc -O -c gram.c
cc version.o main.o doname.o misc.o files.o dosys.o
   gram.o -o make
make: 63620 + 13124 + 764 + 4951 = 82459

None of the source files or grammars are specified in the description file. However, the make command uses its suffix rules to find them and then issues the needed commands. The string of digits on the last line of the previous example results from the size make command. Because the @ (at sign) on the size command in the description file prevented writing of the command, only the sizes are written.

The output can be sent to a different printer or to a file by changing the definition of the P macro on the command line, as follows:

make print "P = print -sp"

OR

make print "P = cat >zap"


[ Previous | Next | Table of Contents | Index | Library Home | Legal | Search ]