1288 lines
46 KiB
Plaintext
1288 lines
46 KiB
Plaintext
=======================================================================
|
|
Turbo Pascal Utilities
|
|
=======================================================================
|
|
|
|
-----------------------------------------------------------------------
|
|
Table of Contents
|
|
-----------------------------------------------------------------------
|
|
1. The TOUCH utility
|
|
2. The GREP utility
|
|
The GREP switches
|
|
How to search using GREP
|
|
Examples using GREP
|
|
3. The BINOBJ utility
|
|
4. Using TPUMOVER, the unit mover
|
|
A review of unit files
|
|
Using TPUMOVER
|
|
5. The Stand-Alone MAKE Utility
|
|
Creating makefiles
|
|
Comments
|
|
Explicit rules
|
|
Implicit rules
|
|
Command lists
|
|
Macros
|
|
Defined test macro ($d)
|
|
Base file name macro ($*)
|
|
Full file name macro ($<)
|
|
File name path macro ($:)
|
|
File name and extension macro ($.)
|
|
File name only macro ($&)
|
|
Directives
|
|
Using MAKE
|
|
The BUILTINS.MAK file
|
|
How MAKE searches for files
|
|
MAKE command-line options
|
|
MAKE error messages
|
|
Fatal errors
|
|
Errors
|
|
-----------------------------------------------------------------------
|
|
|
|
This file describes three stand-alone utility programs that come
|
|
with Turbo Pascal: TOUCH, GREP, BINOBJ, TPUMOVER and MAKE.
|
|
|
|
======================
|
|
1. The TOUCH Utility
|
|
======================
|
|
|
|
There are times when you want to force a particular target file
|
|
to be recompiled or rebuilt, even though no changes have been
|
|
made to its sources. One way to do this is to use the TOUCH
|
|
utility included with Turbo Pascal. TOUCH changes the date and
|
|
time of one or more files to the current date and time, making it
|
|
"newer" than the files that depend on it.
|
|
|
|
To force a target file to be rebuilt, "touch" one of the files
|
|
that target depends on. To touch a file (or files), enter
|
|
|
|
touch filename [ filename ... ]
|
|
|
|
at the DOS prompt. TOUCH will then update the file's creation
|
|
date(s).
|
|
|
|
Once you do this, you can invoke MAKE to rebuild the touched
|
|
target file(s).
|
|
|
|
|
|
=====================
|
|
2. The GREP Utility
|
|
=====================
|
|
|
|
GREP is a powerful search utility that can look for text in
|
|
several files at once.
|
|
|
|
The command-line syntax for GREP follows:
|
|
|
|
GREP [options] searchstring [filespec ... ]
|
|
|
|
where options consists of one or more single characters preceded
|
|
by a hyphen, searchstring defines the pattern to search for, and
|
|
filespec is the file specification. filespec tells GREP which
|
|
files (or groups of files) to search; it can be an explicit file
|
|
name or a generic file name incorporating the DOS wildcards (?
|
|
and *). You can also enter a path as part of filespec; if you use
|
|
filespec without a path, GREP only searches the current
|
|
directory. If you don't specify filespec, input to GREP must be
|
|
specified by redirecting stdin or piping.
|
|
|
|
|
|
The GREP Switches
|
|
===================
|
|
|
|
In the command line, options are one or more single characters
|
|
preceded by a hyphen (-). Each individual character is a switch
|
|
that you can turn on or off: type the plus symbol (+) after a
|
|
character to turn the option on, or type a hyphen (-) after the
|
|
character to turn the option off.
|
|
|
|
The default is on (the + is implied): for example, -R means the
|
|
same thing as -R+. You can list multiple options individually
|
|
like this: -I -D -L). Or you can combine them like this: -ILD or
|
|
-IL -D, and so on). It's all the same to GREP.
|
|
|
|
Here is a list of the switches and their meanings:
|
|
|
|
-C Count only: Only a count of matching lines is printed.
|
|
For each file that contains at least one matching line,
|
|
GREP prints the file name and a count of the number of
|
|
matching lines. Matching lines are not printed.
|
|
|
|
-D Directories: For each filespec specified on the command
|
|
line, GREP searches for all files that match the file
|
|
specification, both in the directory specified and in all
|
|
subdirectories below the specified directory. If you give
|
|
a filespec without a path, GREP assumes the files are in
|
|
the current directory.
|
|
|
|
-I Ignore case: GREP ignores upper/lowercase differences
|
|
(case folding). GREP treats all letters a-z as being
|
|
identical to the corresponding letters A-Z in all
|
|
situations.
|
|
|
|
-L List match files: Only the name of each file containing a
|
|
match is printed. After GREP finds a match, it prints the
|
|
file name and processing immediately moves on to the next
|
|
file.
|
|
|
|
-N Numbers: Each matching line that GREP prints is preceded
|
|
by its line number.
|
|
|
|
-O UNIX output format: Changes the output format of matching
|
|
lines to support more easily the UNIX style of
|
|
command-line piping. All lines of output are preceded by
|
|
the name of the file which contained the matching line.
|
|
|
|
-R Regular expression search: The text defined by
|
|
searchstring is treated as a regular expression instead
|
|
of as a literal string.
|
|
|
|
-U Update options: GREP will combine the options given on
|
|
the command line with its default options and write these
|
|
to the GREP.COM file as the new defaults. (In other
|
|
words, GREP is self-configuring.) This option allows you
|
|
to tailor the default option settings to your own taste.
|
|
|
|
-V Non-match: Only non-matching lines are printed. Only
|
|
lines that do not contain the search string are
|
|
considered to be non-matching lines.
|
|
|
|
-W Word search: Text found which matches the regular
|
|
expression will be considered a match only if the
|
|
character immediately preceding and following cannot be
|
|
part of a word. The default word character set includes
|
|
A-Z, 9-0, and the underbar (_). An alternate form of this
|
|
option allows you to specify the set of legal word
|
|
characters. Its form is -W[set], where set is any valid
|
|
regular expression set definition. If alphabetic
|
|
characters are used to define the set, the set will
|
|
automatically be defined to contain both the upper and
|
|
lower case values for each letter in the set, regardless
|
|
of how it is typed, even if the search is case-sensitive.
|
|
If the -W option is used in combination with the -U
|
|
option, the new set of legal characters is saved as the
|
|
default set.
|
|
|
|
-Z Verbose: GREP prints the file name of every file
|
|
searched. Each matching line is preceded by its line
|
|
number. A count of matching lines in each file is given,
|
|
even if the count is zero.
|
|
|
|
Several of these options are in direct conflict with each other.
|
|
In these cases, the following order applies (the first one is the
|
|
one that takes precedence):
|
|
|
|
-Z -L -C -N
|
|
|
|
Each occurrence of an option overrides the previous definition:
|
|
Its state reflects the way you last set it. At any given time,
|
|
each option can only be on or off.
|
|
|
|
You can install your preferred default setting for each option in
|
|
GREP.COM with the -U option. For example, if you want GREP to
|
|
always do a verbose search (-Z on), you can install it with the
|
|
following command:
|
|
|
|
GREP -U -Z
|
|
|
|
|
|
How to Search Using GREP
|
|
==========================
|
|
|
|
The value of searchstring defines the pattern GREP will search
|
|
for. A search string can be either a (via the -R switch) or a
|
|
literal string. In regular expressions, operators govern the
|
|
search; literal strings have no operators.
|
|
|
|
You can enclose the search string in quotation marks to prevent
|
|
spaces and tabs from being treated as delimiters. Matches will
|
|
not cross line boundaries (a match must be contained in a single
|
|
line).
|
|
|
|
When the -R switch is used, the search string is treated as a
|
|
regular expression (as opposed to a literal expression), and the
|
|
following symbols take on special meanings:
|
|
|
|
^ A caret at the start of the expression matches the start
|
|
of a line.
|
|
|
|
$ A dollar sign at the end of the expression matches the end
|
|
of a line.
|
|
|
|
. A period matches any character.
|
|
|
|
* An expression followed by an asterisk wildcard matches
|
|
zero or more occurrences of that expression: fo* matches
|
|
f, fo, foo, etc.
|
|
|
|
+ An expression followed by a plus sign matches one or more
|
|
occurrences of that expression: fo+ matches fo, foo, etc.,
|
|
but not f.
|
|
|
|
[] A string enclosed in brackets matches any character in
|
|
that string, but no others. If the first character in the
|
|
string is a caret (^), the expression matches any
|
|
character except the characters in the string. For
|
|
example, [xyz] matches x, y, and z, while [^xyz] matches a
|
|
and b, but not x or y. A range of characters can be
|
|
specified by two characters separated by a hyphen (-).
|
|
These can be combined to form expressions like [?a-bd-z]
|
|
to match ? and any letter except c.
|
|
|
|
\ The backslash "escape character" tells GREP to search for
|
|
the literal character that follows it. For example, \.
|
|
matches a period instead of any character.
|
|
|
|
Note: Four characters (?, +, *, and .) do not have any special
|
|
meaning when used in a set. The character ^ is only treated
|
|
specially if it immediately follows the beginning of the set
|
|
(that is, immediately after the [).
|
|
|
|
Any ordinary character not mentioned in this list matches that
|
|
character. A concatenation of regular expressions is a regular
|
|
expression.
|
|
|
|
|
|
Examples Using GREP
|
|
=====================
|
|
|
|
The following examples assume all options default to off.
|
|
|
|
----------------------------------------------------------------
|
|
|
|
Search String grep -n function dirdemo.pas
|
|
|
|
Finds File DIRDEMO.PAS:
|
|
51 LessFunc = function(X, Y: DirPtr): Boolean;
|
|
60 function NumStr(N, D: Integer): String;
|
|
73 function LessName(X, Y: DirPtr): Boolean;
|
|
78 function LessSize(X, Y: DirPtr): Boolean;
|
|
83 function LessTime(X, Y: DirPtr): Boolean;
|
|
|
|
Remarks Finds all functions in the file DIRDEMO.PAS. The -N
|
|
tells GREP to precede each matched line with its line
|
|
number.
|
|
|
|
-----------------------------------------------------------------
|
|
|
|
Search String grep {\$ dirdemo.pas
|
|
|
|
Finds File DIRDEMO.PAS:
|
|
{$I-,S-}
|
|
{$M 8192,8192,655360}
|
|
{$F+}
|
|
{$F-}
|
|
|
|
Remarks Finds all compiler directives in DIRDEMO.PAS. The \
|
|
(backslash) preceding the $ is necessary. Without it,
|
|
the $ would indicate the end of the line. All lines
|
|
with { (curly bracket) as the last character would
|
|
match this pattern and be printed out.
|
|
|
|
-----------------------------------------------------------------
|
|
|
|
Search String grep -i "^ *function.*).*real" *.pas
|
|
|
|
Finds File WORKERS.PAS:
|
|
function RoundPay(Wages: Real): Real;
|
|
|
|
Remarks Finds all lines that begin with zero or more spaces
|
|
followed by the word function, followed by any string
|
|
of zero or more characters, followed by a
|
|
parenthesis, followed by another string of zero or
|
|
more characters, followed by the word Real, and
|
|
ignores case. The net effect is to search for all
|
|
functions returning a Real. See if you can think of
|
|
other ways to do this.
|
|
|
|
The double quotes are necessary because of the space
|
|
in the pattern string. The quotes tell the DOS
|
|
command-line processor to treat the intervening
|
|
characters as a single argument. Without the quotes,
|
|
DOS will think the search string is actually two
|
|
arguments, and GREP will think that everything after
|
|
^ (the caret character) refers to file names, and
|
|
will complain
|
|
|
|
No files matching: *FUNCTION.*).*.
|
|
|
|
|
|
=======================
|
|
3. The BINOBJ Utility
|
|
=======================
|
|
|
|
A utility program called BINOBJ.EXE has been added to convert any
|
|
file to an .OBJ file so it can be linked into a pascal program as
|
|
a "procedure." This is useful if you have a binary data file that
|
|
must reside in the code segment or is too large to make into a
|
|
typed constant array. For example, you can use BINOBJ with the
|
|
Graph unit to link the graphics driver or font files directly
|
|
into your .EXE file. Then, to use your graph program, you need
|
|
only have the .EXE file (see the example BGILINK.PAS).
|
|
|
|
BINOBJ takes three parameters:
|
|
|
|
BINOBJ <source[.BIN]> <destination[.OBJ]> <public name>
|
|
|
|
where source is the binary file to convert, destination is the
|
|
name of the .OBJ to be produced, and public name is the name of
|
|
the procedure as it will be declared in your pascal program.
|
|
|
|
The following example, the procedure ShowScreen, takes a pointer
|
|
as a parameter and moves 4000 bytes of data to screen memory. The
|
|
file called MENU.DTA contains the image of the main menu screen
|
|
(80 * 25 * 2 = 4000 bytes).
|
|
|
|
Here's a simple (no error-checking) version of MYPROG.PAS:
|
|
|
|
program MyProg;
|
|
|
|
uses Crt;
|
|
|
|
procedure ShowScreen(ScreenData : Pointer);
|
|
{ Display a screenful of data--no error-checking! }
|
|
var
|
|
ScreenSegment: Word;
|
|
|
|
begin
|
|
if (Lo(LastMode) = 7) then { Mono? }
|
|
ScreenSegment := $B000
|
|
else
|
|
ScreenSegment := $B800;
|
|
Move(ScreenData^, { From pointer }
|
|
Ptr(ScreenSegment, 0)^, { To video memory }
|
|
4000); { 80 * 25 * 2 }
|
|
end;
|
|
|
|
var
|
|
MenuP : Pointer;
|
|
MenuF : file;
|
|
begin
|
|
Assign(MenuF, 'MENU.DTA'); { Open screen data file }
|
|
Reset(MenuF, 1);
|
|
GetMem(MenuP, 4000); { Allocate buffer on heap }
|
|
BlockRead(MenuF, MenuP^, 4000); { Read screen data }
|
|
Close(MenuF);
|
|
ShowScreen(MenuP); { Display screen }
|
|
end.
|
|
|
|
|
|
The screen data file (MENU.DTA) is opened and then read into a
|
|
buffer on the heap. Both MYPROG.EXE and MENU.DTA must be present
|
|
at run-time for this program to work. You can use BINOBJ to
|
|
convert MENU.DTA to an .OBJ file (MENUDTA.OBJ) and tell it to
|
|
associate the data with a procedure called MenuData. Then you can
|
|
declare the fake external procedure MenuData, which actually
|
|
contains the screen data. Once you link in the .OBJ file with the
|
|
$L compiler directive, MenuData will be 4000 bytes long and
|
|
contain your screen data. First, run BINOBJ on MENU.DTA:
|
|
|
|
binobj MENU.DTA MENUDTA MenuData
|
|
|
|
The first parameter, MENU.DTA, shows a familiar file of screen
|
|
data; the second, MENUDTA, is the name of the .OBJ file to be
|
|
created (since you didn't specify an extension, .OBJ will be
|
|
added). The last parameter, MenuData, is the name of the external
|
|
procedure as it will be declared in your program. Now that you've
|
|
converted MENU.DTA to an .OBJ file, here's what the new
|
|
MYPROG.PAS looks like:
|
|
|
|
program MyProg;
|
|
|
|
uses Crt;
|
|
|
|
procedure ShowScreen(ScreenData : Pointer);
|
|
{ Display a screenful of data--no error checking! }
|
|
var
|
|
ScreenSegment: Word;
|
|
begin
|
|
if (Lo(LastMode) = 7) then { Mono? }
|
|
ScreenSegment := $B000
|
|
else
|
|
ScreenSegment := $B800;
|
|
Move(ScreenData^, { From pointer }
|
|
Ptr(ScreenSegment, 0)^, { To video memory }
|
|
4000); { 80 * 25 * 2 }
|
|
end;
|
|
|
|
procedure MenuData; external;
|
|
{$L MENUDTA.OBJ }
|
|
begin
|
|
ShowScreen(@MenuData); { Display screen }
|
|
end.
|
|
|
|
Notice that ShowScreen didn't change at all, and that the ADDRESS
|
|
of your procedure is passed using the @ operator.
|
|
|
|
===================================
|
|
4. Using TPUMOVER, the Unit Mover
|
|
===================================
|
|
|
|
When you write units, you want to make them easily available to any
|
|
programs that you develop. We'll now show you how to use TPUMOVER to
|
|
remove seldom-used units from TURBO.TPL, and how to insert often-used
|
|
units into TURBO.TPL.
|
|
|
|
|
|
A Review of Unit Files
|
|
========================
|
|
|
|
There are two types of unit files: .TPU files and .TPL files. When you
|
|
compile a unit, Turbo Pascal puts the resulting object code in a .TPU
|
|
(Turbo Pascal Unit) file, which always contains exactly one unit.
|
|
|
|
A .TPL (Turbo Pascal Library) file, on the other hand, can contain multiple
|
|
units. For example, several units that come on your Turbo Pascal disks
|
|
are in the file TURBO.TPL. The file TURBO.TPL is currently the only
|
|
library file Turbo Pascal will load units from.
|
|
|
|
You may have noticed, though, that you can use the standard Turbo Pascal
|
|
units without giving a file name. That's because these units are stored in
|
|
the Turbo Pascal standard unit file--TURBO.TPL on your distribution disk.
|
|
Because the units are in that file, any program can use them without
|
|
"knowing" their location.
|
|
|
|
Suppose you have a unit called TOOLS.TPU, and you use it in many different
|
|
programs. Though adding Tools to TURBO.TPL takes up memory (TURBO.TPL is
|
|
automatically loaded into memory by the compiler), adding it to the
|
|
resident library makes "using" Tools faster because the unit is in memory
|
|
instead of on disk.
|
|
|
|
There are five standard units already in TURBO.TPL: System, Overlay,
|
|
Printer, Crt, and Dos.
|
|
|
|
|
|
Using TPUMOVER
|
|
================
|
|
|
|
You can use several command-line parameters that let you manipulate units
|
|
quickly. The syntax for these parameters is
|
|
|
|
TPUMOVER filename operations
|
|
|
|
where filename is either a .TPU file or a .TPL file,
|
|
and operations is an optional list of one or more of the following
|
|
commands:
|
|
|
|
+unitname Add a unit to the library.
|
|
-unitname Delete a unit from the library.
|
|
*unitname Extract a unit from the library.
|
|
|
|
If no operations are specified, TPUMOVER lists the units in the library
|
|
file along with size and dependency information.
|
|
|
|
|
|
=================================
|
|
5. The Stand-Alone MAKE Utility
|
|
=================================
|
|
|
|
This section contains complete documentation for creating makefiles and
|
|
using MAKE.
|
|
|
|
|
|
Creating Makefiles
|
|
====================
|
|
|
|
A makefile contains the definitions and relationships needed to help MAKE
|
|
keep your program(s) up to date. You can create as many makefiles as you
|
|
want and name them whatever you want. If you don't specify a makefile when
|
|
you run MAKE (using the -f option), then MAKE looks for a file with the
|
|
default name MAKEFILE.
|
|
|
|
You create a makefile with any ASCII text editor, such as Turbo Pascal's
|
|
built-in interactive editor. All rules, definitions, and directives end
|
|
with a carriage return; if a line is too long, you can continue it to the
|
|
next line by placing a backslash (\) as the last character on the line.
|
|
|
|
Whitespace--spaces and tabs--is used to separate adjacent identifiers (such
|
|
as dependencies) and to indent commands within a rule.
|
|
|
|
Creating a makefile is almost like writing a program--with definitions,
|
|
commands, and directives.
|
|
|
|
Comments
|
|
----------
|
|
|
|
Comments begin with a number sign (#); the rest of the line following the #
|
|
is ignored by MAKE. Comments can be placed anywhere and never have to start
|
|
in a particular column.
|
|
|
|
|
|
Explicit Rules
|
|
----------------
|
|
|
|
Explicit rules take the form
|
|
|
|
target [target ... ]: [source source ... ]
|
|
[command]
|
|
[command]
|
|
...
|
|
|
|
where target is the file to be updated, source is a file upon which target
|
|
depends, and command is any valid MS-DOS command (including invocation of
|
|
.BAT files and execution of .COM and .EXE files).
|
|
|
|
Explicit rules define one or more target names, zero or more source files,
|
|
and an optional list of commands to be performed. Target and source file
|
|
names listed in explicit rules can contain normal MS-DOS drive and
|
|
directory specifications, but they cannot contain wildcards.
|
|
|
|
Syntax here is important. target must be at the start of a line (in column
|
|
1), and each command must be indented (preceded by at least one space
|
|
character or tab). As mentioned before, the backslash (\) can be used as a
|
|
continuation character if the list of source files or a given command is
|
|
too long for one line. Finally, both the source files and the commands are
|
|
optional; it is possible to have an explicit rule consisting only of
|
|
|
|
target [target ...] followed by a colon.
|
|
|
|
The idea behind an explicit rule is that the command or commands listed
|
|
will create or update target, usually using the source files. When MAKE
|
|
encounters an explicit rule, it first checks to see if any of the source
|
|
files are target files elsewhere in the makefile. If so, those rules are
|
|
evaluated first.
|
|
|
|
Once all the source files have been created or updated based on other
|
|
explicit (or implicit) rules, MAKE checks to see if target exists. If not,
|
|
each command is invoked in the order given. If target does exist, its time
|
|
and date of last modification are compared against the time and date for
|
|
each source. If any source has been modified more recently than target, the
|
|
list of commands is executed.
|
|
|
|
A given file name can occur on the left side of an explicit rule only once
|
|
in a given execution of MAKE.
|
|
|
|
Each command line in an explicit rule begins with whitespace. MAKE
|
|
considers all lines following an explicit rule to be part of the command
|
|
list for that rule, up to the next line that begins in column 1 (without
|
|
any preceding whitespace) or up to the end of the file. Blank lines are
|
|
ignored.
|
|
|
|
An explicit rule, with no command lines following it, is treated a little
|
|
differently than an explicit rule with command lines.
|
|
|
|
o If an explicit rule exists for a target with commands, the only files
|
|
that the target depends on are the ones listed in the explicit rule.
|
|
|
|
o If an explicit rule has no commands, the targets depend on the files
|
|
given in the explicit rule, and they also depend on any file that
|
|
matches an implicit rule for the target(s).
|
|
|
|
Here are some examples of explicit rules from a makefile:
|
|
|
|
myutil.obj: myutil.asm
|
|
tasm myutil.asm,myutil.obj;
|
|
|
|
myapp.exe: myapp.pas myglobal.tpu myutils.tpu
|
|
tpc myapp /Tc:\tp5\bin
|
|
|
|
o The first explicit rule states that MYUTIL.OBJ depends upon
|
|
MYUTIL.ASM, and that MYUTIL.OBJ is created by executing the given
|
|
TASM command.
|
|
|
|
o The second rule states that MYAPP.EXE depends upon MYAPP.PAS,
|
|
MYGLOBAL.TPU, and MYUTILS.TPU, and is created by the given TPC
|
|
command. (The /T plus path name in these examples will be explained
|
|
later.)
|
|
|
|
If you reorder the rules so that the one for MYAPP.EXE comes first,
|
|
followed by the others, MAKE will recompile (or reassemble) only the files
|
|
that it has to in order to update everything correctly. This is because a
|
|
MAKE with no target on the command line will try to execute the first
|
|
explicit rule it finds in the makefile.
|
|
|
|
|
|
Implicit Rules
|
|
----------------
|
|
|
|
MAKE also allows you to define implicit rules, which are generalizations of
|
|
explicit rules. Here's an example to illustrate the relationship between
|
|
the two types. Consider this explicit rule from the previous sample
|
|
program:
|
|
|
|
myutil.obj: myutil.asm
|
|
tasm myutil.asm,myutil.obj;
|
|
|
|
This rule is a common one, because it follows a general principle: An .OBJ
|
|
file is dependent on the .ASM file with the same file name and is created
|
|
by executing TASM (Turbo Assember). In fact, you might have a makefile
|
|
where you have several (or even several dozen) explicit rules following
|
|
this same format.
|
|
|
|
By redefining the explicit rule as an implicit rule, you can eliminate all
|
|
the explicit rules of the same form. As an implicit rule, it would look
|
|
like this:
|
|
|
|
.asm.obj:
|
|
tasm $*.asm,$*.obj;
|
|
|
|
This rule means, "any file ending with .OBJ depends on the file with the
|
|
same name that ends in .ASM, and the .OBJ file is created using the command
|
|
|
|
tasm $*.asm,$*.obj
|
|
|
|
where $* represents the file's name with no extension." (The symbol $* is a
|
|
special macro and is discussed in the next section.)
|
|
|
|
The syntax for an implicit rule follows:
|
|
|
|
.source_extension.target_extension:
|
|
{command}
|
|
{command}
|
|
...
|
|
|
|
Note the commands are optional and must be indented. The source_extension
|
|
(which must begin in column 1) is the extension of the source file, that
|
|
is, it applies to any file having the format
|
|
|
|
fname.source_extension
|
|
|
|
Likewise, the target_extension refers to the the file
|
|
|
|
fname.target_extension
|
|
|
|
where fname is the same for both files. In other words, this implicit rule
|
|
replaces all explicit rules having the format
|
|
|
|
fname.target_extension:fname.source_extension
|
|
[command]
|
|
[command]
|
|
...
|
|
|
|
for any fname.
|
|
|
|
Implicit rules are used if no explicit rule for a given target can be found
|
|
or if an explicit rule with no commands exists for the target.
|
|
|
|
The extension of the file name in question is used to determine which
|
|
implicit rule to use. The implicit rule is applied if a file is found with
|
|
the same name as the target, but with the mentioned source extension. For
|
|
example, suppose you had a makefile (named MAKEFILE) whose contents were
|
|
|
|
.asm.obj:
|
|
tasm $*.asm,$*.obj;
|
|
|
|
If you had an assembly language routine named RATIO.ASM that you wanted to
|
|
compile to RATIO.OBJ, you could use the command
|
|
|
|
make ratio.obj
|
|
|
|
MAKE would take RATIO.OBJ to be the target and create it by executing the
|
|
command:
|
|
|
|
tasm ratio.asm,ratio.obj;
|
|
|
|
Implicit rules are also used if an explicit rule is given with no commands.
|
|
Suppose, as mentioned before, you had the following implicit rule at the
|
|
start of your makefile:
|
|
|
|
.pas.tpu:
|
|
tpc $<
|
|
|
|
You could then rewrite some explicit rules as follows:
|
|
|
|
myglobal.tpu: myglobal.pas
|
|
myutils.tpu: myutils.pas myglobal.tpu myutil.obj
|
|
|
|
Since you don't have explicit information on how to create these .TPU
|
|
files, MAKE applies the implicit rule defined earlier.
|
|
|
|
Several implicit rules can be written with the same target extension, but
|
|
only one such rule can apply at a time. If more than one implicit rule
|
|
exists for a given target extension, each rule is checked in the order the
|
|
rules appear in the makefile, until all applicable rules are checked.
|
|
|
|
MAKE uses the first implicit rule that it discovers for a file with the
|
|
source extension. Even if the commands of that rule fail, no more implicit
|
|
rules are checked.
|
|
|
|
All lines following an implicit rule are considered to be part of the
|
|
command list for the rule, up to the next line that begins without
|
|
whitespace or to the end of the file. Blank lines are ignored. The syntax
|
|
for a command line is provided later in this appendix.
|
|
|
|
MAKE does not know the full file name with an implicit rule, as it does
|
|
with explicit rules. For that reason, special macros are provided with MAKE
|
|
that allow you to include the name of the file being built by the rule.
|
|
|
|
|
|
Command Lists
|
|
---------------
|
|
|
|
Commands in a command list must be indented--that is, preceded by at least
|
|
one space character or tab--and take the form
|
|
|
|
[ prefix ... ] command_body
|
|
|
|
Each command line in a command list consists of an (optional) list of
|
|
prefixes, followed by a single command body.
|
|
|
|
The prefixes allowed in a command modify the treatment of these commands by
|
|
MAKE. The prefix is either the at (@) sign or a hyphen (-) followed
|
|
immediately by a number.
|
|
|
|
@ Keeps MAKE from displaying the command before executing it. The
|
|
display is hidden even if the -s option was not given on the MAKE
|
|
command line. This prefix applies only to the command on which it
|
|
appears.
|
|
|
|
-num Affects how MAKE treats exit codes. If a number (num) is
|
|
provided, then MAKE will abort processing only if the exit status
|
|
exceeds the number given. In this example, MAKE will abort only
|
|
if the exit status exceeds 4:
|
|
|
|
-4 myprog sample.x
|
|
|
|
If no -num prefix is given, MAKE checks the exit status for the
|
|
command. If the status is nonzero, MAKE will stop and delete the
|
|
current target file.
|
|
|
|
- With a hyphen but no number, MAKE will not check the exit status at
|
|
all. Regardless of what the exit status was, MAKE will continue.
|
|
|
|
The command body is treated exactly as if it were entered as a line to
|
|
COMMAND.COM, with the exception that redirection and pipes are not
|
|
supported. MAKE executes the following built-in commands by invoking a copy
|
|
of COMMAND.COM to perform them:
|
|
|
|
BREAK CD CHDIR CLS COPY
|
|
MD MKDIR PATH PROMPT REN
|
|
RENAME SET TIME TYPE VER
|
|
VERIFY VOL
|
|
|
|
MAKE searches for any other command name using the MS-DOS search algorithm:
|
|
|
|
o The current directory is searched first, followed by each directory
|
|
in the path.
|
|
|
|
o In each directory, first a file with the extension .COM is checked,
|
|
then an .EXE file, and finally a .BAT.
|
|
|
|
o If a .BAT file is found, a copy of COMMAND.COM is invoked to execute
|
|
the batch file.
|
|
|
|
|
|
This command will cause MYPROG.PAS to be searched for, using the full
|
|
search algorithm:
|
|
|
|
tpc myprog.pas /$B+,R+,I+
|
|
|
|
|
|
Macros
|
|
--------
|
|
|
|
Often certain commands, file names, or options are used again and again in
|
|
your makefile. In an example earlier in this appendix, all the TPC commands
|
|
used the switch /Tc:\tp5\bin, which means that the files TPC.CFG and
|
|
TURBO.TPL are in the subdirectory C:\TP5\BIN. Suppose you wanted to switch
|
|
to another subdirectory for those files; what would you do? You could go
|
|
through and modify all the /T options, inserting the appropriate path name.
|
|
Or, you could define a macro.
|
|
|
|
A macro is a name that represents some string of characters (letters and
|
|
digits). A macro definition gives a macro name and the expansion text;
|
|
thereafter, when MAKE encounters the macro name, it replaces the name with
|
|
the expansion text.
|
|
|
|
Suppose you defined the following macro at the start of your makefile:
|
|
|
|
TURBO=c:\tp5\bin
|
|
|
|
You've defined the macro TURBO, which is equivalent to the string
|
|
c:\tp5\bin. You could now rewrite the makefile as follows:
|
|
|
|
TURBO=c:\tp5\bin
|
|
myapp.exe: myapp.pas myglobal.tpu myutils.tpu
|
|
tpc myapp /T$(TURBO)
|
|
|
|
myutils.tpu: myutils.pas myglobal.tpu myutil.obj
|
|
tpc myutils /T$(TURBO)
|
|
|
|
|
|
Everywhere the Turbo directory is specified, you use the macro invocation
|
|
$(TURBO). When you run MAKE, $(TURBO) is replaced with its expansion text,
|
|
c:\TP5.BIN. The result is the same set of commands you had before but with
|
|
greater flexibility.
|
|
|
|
In fact, if you leave out the first line altogether, you can specify which
|
|
subdirectory you want each time you run MAKE, using the -D (Define) option:
|
|
|
|
make -DTURBO=c:\tp5\project
|
|
|
|
Macro definitions take the form
|
|
|
|
macro_name=expansion text
|
|
|
|
where macro_name is the name of a macro made up of a string of letters and
|
|
digits with no whitespace in it, though you can have whitespace between
|
|
macro_name and the equal sign (=). [expansion text] is any arbitrary string
|
|
containing letters, digits, whitespace, and punctuation; it is ended by a
|
|
carriage return. Note that macros are case sensitive. Thus the macro
|
|
names Turbo, turbo and TURBO are all different.
|
|
|
|
If macro_name has previously been defined, either by a macro definition in
|
|
the makefile or by the -D option on the MAKE command line, the new
|
|
definition replaces the old.
|
|
|
|
Macros are invoked in your makefile with the format
|
|
|
|
$(macro_name)
|
|
|
|
Macros in macros: Macros cannot be invoked on the left (macro_name) side of
|
|
a macro definition. They can be used on the right (expansion text) side,
|
|
but they are not expanded until the macro being defined is invoked. In
|
|
other words, when a macro invocation is expanded, any macros embedded in
|
|
its expansion text are also expanded.
|
|
|
|
MAKE comes with several special predefined macros built-in: $d, $*, $<, $:,
|
|
$., and $&. The first is a defined test macro, used in the conditional
|
|
directives !if and !elif; the others are file name macros, used in explicit
|
|
and implicit rules. The various file name macros work in similar ways,
|
|
expanding to some variation of the full path name of the file being built.
|
|
In addition, the current SET environment strings are automatically loaded
|
|
as macros, and the macro __MAKE__ is defined to be 1 (one).
|
|
|
|
|
|
Defined Test Macro ($d)
|
|
|
|
This macro expands to 1 if the given macro name is defined, or to 0 if it
|
|
is not. The content of the macro's expansion text does not matter. This
|
|
special macro is allowed only in !if and !elif directives. For example, if
|
|
you wanted to modify your makefile so that it would use a particular Turbo
|
|
Pascal directory if you didn't specify one, you could put this at the start
|
|
of your makefile:
|
|
|
|
!if !$d(TURBO) # if TURBO is not defined
|
|
TURBO=c:\tp5\bin # define it to C:\TP5\BIN
|
|
!endif
|
|
|
|
If you invoke MAKE with the command line
|
|
|
|
make -DTURBO=c:\tp5\project
|
|
|
|
then TURBO is defined as c:\tp5\project. If, however, you just invoke MAKE
|
|
by itself,
|
|
|
|
make
|
|
|
|
then TURBO is defined as c:\tp5\bin, your "default" subdirectory.
|
|
|
|
|
|
Base File Name Macro ($*)
|
|
|
|
This macro is allowed in the commands for an explicit or an implicit rule.
|
|
The macro expands to the file name being built, excluding any extension,
|
|
like this:
|
|
|
|
File name is A:\P\TESTFILE.PAS
|
|
$* expands to A:\P\TESTFILE
|
|
|
|
For example, you could modify the explicit MYAPP.EXE rule already given to
|
|
look like this:
|
|
|
|
myapp.exe: myapp.pas myglobal.tpu myutils.tpu
|
|
tpc $* /T$(TURBO)
|
|
|
|
|
|
Full File Name Macro ($<)
|
|
|
|
The full file name macro ($<) is also used in the commands for an explicit
|
|
or implicit rule. In an explicit rule, $< expands to the full target file
|
|
name (including extension), like this:
|
|
|
|
File name is A:\P\TESTFILE.PAS
|
|
$< expands to A:\P\TESTFILE.PAS
|
|
|
|
In an implicit rule, $< takes on the file name plus the source extension.
|
|
For example, the previous implicit rule
|
|
|
|
.asm.obj:
|
|
tasm $*.asm,$*.obj;
|
|
|
|
can be rewritten as
|
|
|
|
.asm.obj:
|
|
tasm $<,$*.obj;
|
|
|
|
|
|
File Name Path Macro ($:)
|
|
|
|
This macro expands to the path name (without the file name), like this:
|
|
|
|
File name is A:\P\TESTFILE.PAS
|
|
$: expands to A:\P\
|
|
|
|
|
|
File Name and Extension Macro ($.)
|
|
|
|
This macro expands to the file name, with extension, like this:
|
|
|
|
File name is A:\P\TESTFILE.PAS
|
|
$. expands to TESTFILE.PAS
|
|
|
|
|
|
File Name Only Macro ($&)
|
|
|
|
This macro expands to the file name only, without path or extension, like
|
|
this:
|
|
|
|
File name is A:\P\TESTFILE.PAS
|
|
$& expands to TESTFILE
|
|
|
|
|
|
Directives
|
|
------------
|
|
|
|
The version of MAKE bundled with Turbo Pascal allows something that other
|
|
versions of MAKE don't: conditional directives similiar to those allowed
|
|
for Turbo Pascal. You can use these directives to include other makefiles,
|
|
to make the rules and commands conditional, to print out error messages,
|
|
and to "undefine" macros.
|
|
|
|
Directives in a makefile begin with an exclamation point (!). Here is the
|
|
complete list of MAKE directives:
|
|
|
|
!include
|
|
!if
|
|
!else
|
|
!elif
|
|
!endif
|
|
!error
|
|
!undef
|
|
|
|
A file-inclusion directive (!include) specifies a file to be included into
|
|
the makefile for interpretation at the point of the directive. It takes the
|
|
following form:
|
|
|
|
!include "filename"
|
|
|
|
or
|
|
|
|
!include <filename>
|
|
|
|
These directives can be nested arbitrarily deep. If an include directive
|
|
attempts to include a file that has already been included in some outer
|
|
level of nesting (so that a nesting loop is about to start), the inner
|
|
include directive is rejected as an error.
|
|
|
|
Conditional directives (!if, !elif, !else, and !endif) give a programmer a
|
|
measure of flexibility in constructing makefiles. Rules and macros can be
|
|
"conditionalized" so that a command-line macro definition (using the -D
|
|
option) can enable or disable sections of the makefile.
|
|
|
|
The format of these directives parallels, but is more extensive than, the
|
|
conditional directives allowed by Turbo Pascal:
|
|
|
|
!if expression
|
|
[ lines ]
|
|
!endif
|
|
|
|
!if expression
|
|
[ lines ]
|
|
!else
|
|
[ lines ]
|
|
!endif
|
|
|
|
!if expression
|
|
[ lines ]
|
|
!elif expression
|
|
[ lines ]
|
|
!endif
|
|
|
|
The conditional directives form a group, with at least an !if directive
|
|
beginning the group and an !endif directive closing the group.
|
|
|
|
The expression allowed in an !if or an !elif directive uses a syntax
|
|
similar to that found in the C programming language. The expression is
|
|
evaluated as a simple 32-bit signed integer expression.
|
|
|
|
Numbers can be entered as decimal, octal, or hexadecimal constants. For
|
|
example, these are legal constants in an expression:
|
|
|
|
4536 # decimal constant
|
|
0677 # octal constant (note the leading zero)
|
|
0x23aF # hexadecimal constant
|
|
|
|
and any of the following unary operators:
|
|
|
|
- negation
|
|
~ bit complement
|
|
! logical not
|
|
|
|
An expression can use any of the following binary operators:
|
|
|
|
+ addition
|
|
- subtraction
|
|
* multiplication
|
|
/ division
|
|
% remainder
|
|
>> right shift
|
|
<< left shift
|
|
& bitwise and
|
|
| bitwise or
|
|
^ bitwise exclusive or
|
|
&& logical and
|
|
|| logical or
|
|
> greater than
|
|
< less than
|
|
>= greater than or equal to
|
|
<= less than or equal to
|
|
== equality
|
|
!= inequality
|
|
|
|
An expression can contain the following ternary operator:
|
|
|
|
? : The operand before the ? is treated as a test.
|
|
|
|
If the value of that operand is nonzero, then the second
|
|
operand (the part between the ? and the colon) is the
|
|
result. If the value of the first operand is zero, the
|
|
value of the result is the value of the third operand
|
|
(the part after the :).
|
|
|
|
Parentheses can be used to group operands in an expression. In the absence
|
|
of parentheses, binary operators are grouped according to the same
|
|
precedence given in the C language.
|
|
|
|
Grouping is from left to right for operators of equal precedence, except
|
|
for the ternary operator (? :), which is right to left.
|
|
|
|
Macros can be invoked within an expression, and the special macro $d() is
|
|
recognized. After all macros have been expanded, the expression must have
|
|
proper syntax. Any words in the expanded expression are treated as errors.
|
|
|
|
The error directive (!error) causes MAKE to stop and print a fatal
|
|
diagnostic containing the text after !error. It takes the format
|
|
|
|
!error [any_text]
|
|
|
|
This directive is designed to be included in conditional directives to
|
|
allow a user-defined abort condition.
|
|
|
|
The undefine directive (!undef) causes any definition for the named macro
|
|
to be forgotten. If the macro is currently undefined, this directive has no
|
|
effect.
|
|
|
|
Using MAKE
|
|
============
|
|
|
|
You now know a lot about how to write makefiles; now's the time to learn
|
|
how to use them with MAKE. The simplest way to use MAKE is to type the
|
|
command
|
|
|
|
MAKE
|
|
|
|
at the MS-DOS prompt. MAKE then looks for MAKEFILE; if it can't find it, it
|
|
looks for MAKEFILE.MAK; if it can't find that, it halts with an error
|
|
message.
|
|
|
|
You can specify a file with the -f option:
|
|
|
|
MAKE -fstars.mak
|
|
|
|
The general syntax for MAKE is
|
|
|
|
make option option ... target target ...
|
|
|
|
where option is a MAKE option (discussed later) and target is the name of a
|
|
target file to be handled by explicit rules.
|
|
|
|
If the command line does not include any target names, MAKE uses the first
|
|
target file mentioned in an explicit rule. If one or more targets are
|
|
mentioned on the command line, they will be built as necessary.
|
|
|
|
Here are some more examples of MAKE command lines:
|
|
|
|
make -n -fstars.mak
|
|
make -s
|
|
make -Iinclude -DTURBO=c:\tp5\project
|
|
|
|
|
|
The BUILTINS.MAK File
|
|
-----------------------
|
|
|
|
As you become familiar with MAKE, you will find that there are macros and
|
|
rules (usually implicit ones) that you use again and again. You've got
|
|
three ways of handling them. First, you can put them in every makefile you
|
|
create. Second, you can put them all in one file and use the !include
|
|
directive in each makefile you create. Third, you can put them all in a
|
|
file named BUILTINS.MAK.
|
|
|
|
Each time you run MAKE, it looks for a file named BUILTINS.MAK; if it finds
|
|
the file, MAKE reads it in before handling MAKEFILE (or whichever makefile
|
|
you want it to process).
|
|
|
|
The BUILTINS.MAK file is intended for any rules (usually implicit rules) or
|
|
macros that will be commonly used in files anywhere on your computer.
|
|
|
|
There is no requirement that any BUILTINS.MAK file exist. If MAKE finds a
|
|
BUILTINS.MAK file, it interprets that file first. If MAKE cannot find a
|
|
BUILTINS.MAK file, it proceeds directly to interpreting MAKEFILE (or
|
|
whatever makefile you specify).
|
|
|
|
|
|
How MAKE Searches for Files
|
|
-----------------------------
|
|
|
|
MAKE will search for BUILTINS.MAK in the current directory or in the exec
|
|
directory if your computer is running under DOS 3.x. You should place this
|
|
file in the same directory as the MAKE.EXE file.
|
|
|
|
MAKE always searches for the makefile in the current directory only. This
|
|
file contains the rules for the particular executable program file being
|
|
built. The two files have identical syntax rules.
|
|
|
|
MAKE also searches for any !include files in the current directory. If you
|
|
use the -I (Include) option, it will also search in the specified
|
|
directory.
|
|
|
|
|
|
MAKE Command-Line Options
|
|
---------------------------
|
|
|
|
-Didentifier Defines the named identifier to the string consisting of
|
|
the single character 1.
|
|
|
|
-Diden=string Defines the named identifier iden to the string after
|
|
the equal sign. The string cannot contain any spaces or
|
|
tabs.
|
|
|
|
-Idirectory MAKE will search for include files in the indicated
|
|
directory (as well as in the current directory).
|
|
|
|
-Uidentifier Undefines any previous definitions of the named
|
|
identifier.
|
|
|
|
-s Normally, MAKE prints each command as it is about to be
|
|
executed. With the -s option, no commands are printed
|
|
before execution.
|
|
|
|
-n Causes MAKE to print the commands, but not actually
|
|
perform them. This is useful for debugging a makefile.
|
|
|
|
-ffilename Uses filename as the MAKE file. If filename does not
|
|
exist and no extension is given, tries filename.MAK.
|
|
|
|
-? or -h Prints help message.
|
|
|
|
|
|
MAKE Error Messages
|
|
---------------------
|
|
|
|
Fatal Errors
|
|
|
|
Don't know how to make XXXXXXXX
|
|
This message is issued when MAKE encounters a nonexistent file name in
|
|
the build sequence, and no rule exists that would allow the file name to
|
|
be built.
|
|
|
|
Error directive: XXXX
|
|
This message is issued when MAKE processes an #error directive in the
|
|
source file. The text of the directive is displayed in the message.
|
|
|
|
Incorrect command line argument: XXX
|
|
This error occurs if MAKE is executed with incorrect command-line
|
|
arguments.
|
|
|
|
Not enough memory
|
|
This error occurs when the total working storage has been exhausted. You
|
|
should try this on a machine with more memory. If you already have 640K
|
|
in your machine, you may have to simplify the source file.
|
|
|
|
Unable to execute command
|
|
This message is issued after attempting to execute a command. This could
|
|
be a result of the command file not being found, or because it was
|
|
misspelled. A less likely possibility is that the command exists but is
|
|
somehow corrupted.
|
|
|
|
Unable to open makefile
|
|
This message is issued when the current directory does not contain a
|
|
file named MAKEFILE.
|
|
|
|
|
|
Errors
|
|
|
|
Bad file name format in include statement
|
|
Include file names must be surrounded by quotes or angle brackets. The
|
|
file name was missing the opening quote or angle bracket.
|
|
|
|
Bad undef statement syntax
|
|
An !undef statement must contain a single identifier and nothing else as
|
|
the body of the statement.
|
|
|
|
Character constant too long
|
|
Character constants can be only one or two characters long.
|
|
|
|
Command arguments too long
|
|
The arguments to a command executed by MAKE were more than 127
|
|
characters--a limit imposed by DOS.
|
|
|
|
Command syntax error
|
|
This message occurs if
|
|
|
|
o the first rule line of the makefile contained any leading
|
|
whitespace.
|
|
|
|
o an implicit rule did not consist of .ext.ext:.
|
|
|
|
o an explicit rule did not contain a name before the : character.
|
|
|
|
o a macro definition did not contain a name before the = character.
|
|
|
|
Division by zero
|
|
A divide or remainder in an !if statement has a zero divisor.
|
|
|
|
Expression syntax error in !if statement
|
|
The expression in an !if statement is badly formed--it contains a
|
|
mismatched parenthesis, an extra or missing operator, or a missing or
|
|
extra constant.
|
|
|
|
File name too long
|
|
The file name given in an !include directive was too long for MAKE to
|
|
process. File path names in MS-DOS must be no more than 78 characters
|
|
long.
|
|
|
|
Illegal character in constant expression X
|
|
MAKE encountered some character not allowed in a constant expression. If
|
|
the character is a letter, this indicates a (probably) misspelled
|
|
identifier.
|
|
|
|
Illegal octal digit
|
|
An octal constant was found containing a digit of 8 or 9.
|
|
|
|
Macro expansion too long
|
|
A macro cannot expand to more than 4096 characters. This error often
|
|
occurs if a macro recursively expands itself. A macro cannot legally
|
|
expand to itself.
|
|
|
|
Misplaced elif statement
|
|
An !elif directive was encountered without any matching !if directive.
|
|
|
|
Misplaced else statement
|
|
An !else directive was encountered without any matching !if directive.
|
|
|
|
Misplaced endif statement
|
|
An !endif directive was encountered without any matching !if directive.
|
|
|
|
No file name ending
|
|
The file name in an include statement was missing the correct closing
|
|
quote or angle bracket.
|
|
|
|
Redefinition of target XXXXXXXX
|
|
The named file occurs on the left-hand side of more than one explicit
|
|
rule.
|
|
|
|
Unable to open include file XXXXXXXXX.XXX
|
|
The named file could not be found. This could also be caused if an
|
|
include file included itself. Check whether the named file exists.
|
|
|
|
Unexpected end of file in conditional started on line #
|
|
The source file ended before MAKE encountered an !endif. The !endif was
|
|
either missing or misspelled.
|
|
|
|
Unknown preprocessor statement
|
|
A ! character was encountered at the beginning of a line, and the
|
|
statement name following was not error, undef, if, elif, include, else,
|
|
or endif.
|
|
|
|
|
|
* * * * *
|