Build Switches in Programmer's WorkBench (PWB)

Created: April 26, 1992

ABSTRACT

The MicrosoftÒ Programmer’s WorkBench (PWB) is a flexible, extensible platform for program development. Using PWB, developers can build a final project (executable) file from a collection of source files. This process involves creating a make file based on a set of rules describing how the project will be built. This article describes the build switches that define these rules. It explains the advanced use of build switches and provides examples of each switch.

INTRODUCTION

This article explains how MicrosoftÒ Programmer’s WorkBench (PWB) builds a final project file from a collection of files. In the simplest case, the final project is an executable (.EXE) file, and the collection of files consists of source files, such as Microsoft C (.C) or Microsoft FORTRAN (.FOR) files.

The process of building the project involves two steps:

1.PWB creates a make file, which is a text file that describes how to build the project. For example, the make file might describe how to compile .C files into .OBJ files and then link those .OBJ files into an executable file.

2.PWB uses this make file and the NMAKE program maintenance utility to call the commands that build the project.

PWB creates a make file by using the information you entered (your list of source files) and by using a set of rules. These rules derive from build switches, which define the operations the source files require and determine how resulting files will be operated on to produce the final project. The build switches affect the make file directly by causing certain commands, macros, and inference rules to be written to the make file. A build switch corresponds to each command, macro, and inference rule.

PWB includes templates (that is, generic build instructions) for common programming projects for the Microsoft WindowsÔ, MS-DOSÒ, and OS/2Ò operating systems. The Set Initial Build Options box shows the available templates. It is impractical for PWB to supply templates for all possible projects; therefore, to build a project not covered by one of the default template projects, you must create a custom set of build switches for your make file.

The types of projects that you can produce from a modified set of build switches range from the simple, such as an executable file built from Microsoft Pascal or FORTRAN source files, to the complex, such as an OS/2 dynamic-link library (DLL) built from C++ and assembly source files.

The following sections describe each build switch and its function. A separate section describes the use of advanced build switch features, such as predefined and special macros. Next, the steps required to create your own custom set of build switches are described. Finally, a set of examples illustrating these procedures is provided.

Learning to use build switches is similar to learning a new programming language. You should not expect to read the following material and create a new template immediately. Before attempting to create complex project templates from scratch, experiment by modifying some existing build-switch templates.

This material is easier to understand if you know how to write an NMAKE make file. You should thoroughly understand NMAKE’s advanced features, especially predefined macros and macro substitutions.

Note:

Much of the following information is provided in the PWB Help system. To access this information, get help on the word build by using the PWB Help system or QuickHelp command-line help.

CONVENTIONS

This article uses the following conventions.

Example Description

[option] Items in square brackets are optional.
run|debug A vertical bar indicates a choice between two or more items. You must choose one of these items unless square brackets delimit the choices (for example, [run|debug]).

BUILD SWITCHES

PWB uses build switches to define the following features for the build process:

NMAKE-style macros

List of targets to build

Target rules (the list of commands, defined in other build switches, used to build a target)

Inference rules (the list of commands, defined in other build switches, used to build object files or other files from source files)

Commands used in target rules or inference rules

Include tags to be detected in source files

Error message syntax to be detected in the log file

Macro Build Switch

The build: macro form of the build switch specifies NMAKE macros that are used for build operations (see below for more information on the build: command form of the build switch). PWB places these macros in the NMAKE description file (make file) associated with the current project. The value assigned to a macro must be in the form of a C string (enclosed in double quotation marks, with all special characters escaped).

Your own build switches need not use macros, but macros simplify writing, modifying, and maintaining project files and build rules. Macro names are case sensitive.

The syntax of the build: macro switch is

build: macro name "value"

where name is the name of the macro and value is the value to assign to the macro. The value must be enclosed in double quotation marks.

For example,

build: macro PFLAGS "/c /Ox /Fpi87"

results in the following line in the NMAKE description file:

PFLAGS = /c /Ox /Fpi87

You can use macros in your own build commands. They are referenced using the following syntax:

$(macroname)

where macroname is the name of the macro. For example,

$(PFLAGS)

evaluates to the value of the PFLAGS macro (as defined above).

Many compiler options and Link Options dialog boxes in PWB affect certain predefined macros in the make file. An example of a predefined macro is CFLAGS_G, which PWB uses for all general C compiler options. When an option in the C Compiler Options dialog box within PWB is changed, the CFLAGS_G macro changes accordingly. You can use these predefined macros in any of your build commands, but do not modify them. For more information, see the “Reserved Macros” section.

The following is a valid use of macros in a build command:

build: macro PL "pl"

build: macro PFLAGS "/c /Zi"

build: command pl_pas_obj "$(PL) $(PFLAGS) $(CFLAGS_G) $<"

These build switches define two macros, PL and PFLAGS, and define a command, pl_pas_obj, which uses these two macros as well as the CFLAGS_G predefined macro. For more information about the build: command form of the build switch, see the “Command Build Switch” section.

For additional examples of using the build: macro build switch, see Appendix B.

All Build Switch

The build: all form of the build switch lists the targets to build when you build your project by choosing the Build or Rebuild All command from the PWB Make menu. The syntax of the build: all switch is as follows:

build: all [$(PROJ).ext]...

Target names must have the $(PROJ) predefined macro as a basename and must have an .ext extension of a maximum of three characters. PROJ is a predefined macro that returns the basename of the project. This is the basename of the project file, not the first file in the program list. A set of build switches can have only one build: all switch.

The build: all switch creates a pseudotarget named “all” in the corresponding PWB make file. The “all” pseudotarget is always the first description block in the make file. Because NMAKE always executes the first target found in a make file (unless directed otherwise), the targets that the build: all switch specifies are built when you choose Build or Rebuild All from the Make menu.

For example, to build a dynamic-link library, use the following build switch to define the target:

build: all $(PROJ).dll

To build multiple targets, list them on the same line and separate them with a space. For example:

build: all $(PROJ).exe $(PROJ).hlp

See the next section for information on how to use the build: target form of the build switch to define lists of commands for creating target files. Use the build: command form of the build switch to define commands.

For additional information about the build: all build switch, see Examples 4, 5, and 6 in Appendix B.

Target Build Switch

The build: target form of the build switch specifies the combinations of commands used to create a target file. A target file is either a file with the build: all switch specified (as shown previously) or simply an additional file that you would like to build. The syntax of the build: target switch is as follows:

build: target name [cmd]...

The name specifies the name of the target file being built. You can use it in a build: all switch, in which case the target is built when you choose Build or Rebuild All from the Make menu. If you do not specify the target in the build: all line, you can build it by choosing the Build Target command from the Make menu. The name must have the form

$(PROJ).ext

where .ext is the extension of the target file.

Each cmd is the name of a command used to build the given target. Use the build: command form of the build switch to define each cmd. For example,

build: target $(PROJ).exe lrf_exe ilink_exe rc_exe

indicates that PWB uses the commands lrf_exe, ilink_exe, and rc_exe to build the $(PROJ).EXE target file.

For additional information about the build: target build switch, see Examples 4, 5, and 6 in Appendix B.

Command Build Switch

The build: command switch specifies a command to be used with the build: inference and build: target switches. The syntax of the build: command switch is:

build: [release|debug] command name "cmdline"

The build: command switch specifies the actual command lines used to compile source files or to build target files.

The release and debug options specify the type of build to which the command applies. You specify the build type by selecting Debug or Release from the Build Options dialog box from the Options menu. The meanings of the release and debug options for the build: command switch are as follows.

Option Description

release The command is used only for release builds.
debug The command is used only for debug builds.
(neither) The command is used for both types of builds.

The name argument is the name of the command as it appears in a target or an inference rule. The command names used in build switches have no meanings in themselves (you can name a command anything you want), but many of the default command names that PWB uses, as well as the examples in this article, use the following convention for ease of understanding:

tool_fromext_toext

where tool is the name of the tool used (cc for C compiler, for example), fromext is the extension that the tool takes as a source file, and toext is the resulting file extension. For example, the command that uses the C compiler is cc_c_obj because it uses the cc (C compiler) tool, the source files are .C files, and the resulting files are .OBJ files.

The cmdline argument of the build: command switch specifies the actual command line that name represents. The argument must be in the form of a C string (enclosed in double quotation marks, with all special characters escaped).

For example:

build: command pl_pas_obj "pl /c $(PFLAGS) $<"

indicates that the quoted string is the value of the pl_pas_obj command. When the pl_pas_obj command is used in the build: inference or build: target switch, it refers to the following command line:

pl /c $(PFLAGS) $<

In this example, the pl_pas_obj command compiles .PAS files into .OBJ files. Because this build switch has no debug or release tag, this command is used for both debug and release modes. The following example shows the use of the debug and release tags:

build: debug command cxx_c_obj "cxx /c $(CXXFLAGS_D) $<"

build: release command cxx_c_obj "cxx /c $(CXXFLAGS_R) $<"

The first command is used when you choose Debug in the dialog box that appears when you choose Build Options from the Options menu. If you select Release in the dialog box, the second command is used.

Sometimes a build: command that executes multiple MS-DOS commands is necessary. To create one, include the text “\n\t” between the commands to insert a new line and a tab between the commands in the PWB-generated make file, as in the following example:

build: command multiple_cmd "pl /c $<\n\techo finished"

This example places the two commands—"pl /c $<" and "echo finished"—on consecutive lines in the make file wherever the multiple_cmd command is used. You can also use “\n ” for a delimiter, as long as you have one or more tabs or spaces after the \n.

Note:

For build commands, certain macro calls have a special meaning to PWB. The definitions of these macros are automatically generated from the files in the program list and their derivatives. For more information, see the “Reserved Macros” section.

For additional examples of the build: command build switch, see Appendix B.

Debug and Run Command Build Switches

Another use of the build: command switch is to specify the commands PWB uses to run or to debug your program. The following two additional build switches—run and debug—pass parameters to the program and configure CodeViewÒ:

build: command run|debug "cmdline"

These build switches define which commands execute when you choose Execute or Debug from the Run menu. The cmdline argument must be in the form of a C string (enclosed in double quotation marks, using C escape sequences for special characters). The default values for these switches are as follows:

build: command run "$(PROJ).exe $(RUNFLAGS)"

build: command debug "CV $(CVFLAGS) $(PROJ).exe $(RUNFLAGS)"

The RUNFLAGS macro contains the command-line parameters you enter in the Command Line box from the Run menu. The CVFLAGS macro contains the debugging options you select from the CodeView Options command in the Options menu.

If you want to use a particular set of command-line parameters or CodeView options for a project, you can predefine them with build-switch macros. These definitions set the default values shown in the dialog boxes. You are still free to change the defaults; PWB uses the new values in the project file.

Inference Build Switch

The build: inference form of the build switch specifies the rules that build a target file from a source file. The role of the inference switch is analogous to the inference rule in a Microsoft NMAKE make file. (For more information on NMAKE inference rules, see Microsoft C Advanced Programming Techniques or Help.)

The syntax of the build: inference switch is as follows:

build: inference rule [cmd]...

The rule is an inference rule of the form used in an NMAKE description file (.c.obj, for example).

Each cmd is the name of a command used to build object files from source files. For instructions on using the build: command form of the build switch to define what each cmd command does, see the “Command Build Switch” section. Each inference rule can have more than one cmd. For example,

build: inference .pas.obj pl_pas_obj copy_src

indicates that PWB uses the pl_pas_obj and copy_src commands to compile files with a .PAS extension in order to generate files with an .OBJ extension. These two commands are automatically executed for each .PAS file in the program list.

Additional build: inference switch examples are provided in Appendix B.

The build: inference build switch does not support transitivity between inference rules. Transitivity in inference rules implies that to build file A to file C we must first build file A to file B and then build file B to file C. For example, the following two inference rules cause unexpected behavior if used together:

build: inference .c.obj cc_c_obj

build: inference .cxx.c cxx_cxx_c

In this example, an inference rule automatically builds .CXX files into .C files. In addition, an inference rule builds .C files into .OBJ files. PWB cannot recognize that your original source files begin with a .CXX extension (rather than a .C extension) and are to be built to an .OBJ extension; therefore, the files do not build correctly.

You can avoid this limitation by creating a single inference rule to replace the two inference rules that are normally required to build the file (as in the previous example). This new inference rule should build your original source files directly into the target file type, bypassing the intermediate step. In this way, transitivity is not a problem because there are no transitive inference rules. For example, the following build: inference switch can replace the two in the previous example:

build: inference .cxx.obj cxx_cxx_c cc_c_obj

This single rule results in .CXX files being built to .OBJ files directly. Both commands are still executed (cxx_cxx_c and cc_c_obj), but in a single step instead of in two steps.

One problem with using inference rules that create intermediate files (as in the above example, which creates a .C file) is that the intermediate file may change the build process and cause unexpected behavior. When an intermediate file exists on the disk, the first inference rule to build that target is used if the target file is ever out of date (the .C file in the above example). Unfortunately, the first inference rules that the build process finds are the predefined inference rules (.c.obj and .asm.obj, for example). So, if you have either a .C or an .ASM file that matches the basename of the out-of-date target, the predefined inference rules are used on it, rather than the inference rule that you created. For instance, examine the following inference rule:

build: inference .src.obj hx_src_c cc_c_obj

Assume that hx_src_c compiles your .SRC file into a file with a .C extension, and cc_c_obj compiles the .C file into an .OBJ file. You thus have a .C file left on the disk after the .OBJ file is built. Suppose that you then change one of the .SRC files. The next time you try to rebuild, the NMAKE utility checks the .C file corresponding to your .OBJ file (rather than the .SRC file). The .C file is probably not out of date in relation to the .OBJ file, so NMAKE checks no further; thus, the .OBJ file is not rebuilt.

You can work around this limitation by deleting or renaming the intermediate file, as in the following example:

build: inference .src.obj hx_src_c cc_c_obj del_sav ren_c_sav

build: command del_sav "if exist $*.sav del $*.sav"

build: command ren_c_sav "ren $*.c $*.sav"

These steps are somewhat awkward, but they ensure that no interfering intermediate files are available the next time NMAKE is called because those files will have been renamed. Yet, if an intermediate file is needed for any reason (for example, for debugging), it is still available under the new name.

Example 2 in Appendix B shows a way to deal with this transitivity problem.

Include Build Switch

The build: include form of the build switch comes into play only when you select Set Include Dependencies (the Set Dependencies command in PWB version 1.0) in the Edit Program List dialog box. To set dependencies, PWB must search each of your source files for include directives to determine the correct dependencies. The build: include switch defines the actual pattern used to detect these include directives. The syntax of the build: include switch is as follows:

build: include ext "pattern" [case] [system]

The ext specifies the file extension for the types of files that can contain such include tags. The ext must be preceded by a period (.C or .ASM, for example).

The pattern has the form of a tagged UNIXÒ regular expression. The pattern argument must be in the form of a C string (enclosed in double quotation marks, using C escape sequences for special characters). Only one tag should be interpreted as the name of the included file. (Appendix A contains a quick reference to UNIX regular expressions used in PWB. For more complete information about UNIX regular expressions, see Help for the word regex.)

The case option, if it appears, tells PWB that the pattern is case sensitive. The system option, if it appears, flags the file as a “system” include file. (See the note below for information on the build: [no] system form of the build switch.)

For example:

build: include .c "^#include \"\\(\\:p\\)\"" case

This build: include switch causes PWB to scan .C files for lines that match the regular expression enclosed in the double quotation marks. This regular expression matches lines that contain the following: a pound sign directly after the beginning of the line (denoted by ^#), the word “include”, a double quotation mark (\"), a path (\:p), and a double quotation mark. The path is the tagged expression because "\\( and \\)\" enclose it. The case tag denotes that this expression is case sensitive (namely, the “include” text). This regular expression matches the sample include directives

#include "myincl.h"

#include "c:\include\system.h"

but the following lines do not match:

#INCLUDE "dos.h"

#include <stdio.h>

#include "\\c6srvr\include!stdio.h"

The following is a slightly more complicated example:

build: include .cxx "^[ \t]*#[ \t]*include[ \t]*

<\\([^>]+\\)>" case system

Note:

The strings in commands must all appear on one line. Some are broken into multiple lines here for ease of reading.

This build: include switch is similar to the previous example, except that the expression is more complex and the addition of the system specifier means that this rule is used when the build: include system switch is set. The following lines are matched by this regular expression:

#include <stdio.h> #

include <sys\include.h>

#include <f:\c600\include\dos.h>

Note:

Another use of the include build switch involves enabling or disabling (by using the system option) the scanning for files that have been tagged as “system” include files. To do so, use the following syntax:

build: include system

build: include no system

The no system form above means that the “system” include build switches are not used when scanning for dependent files.

The following additional forms of the build: include switch are available in PWB version 1.1 or later:

build: include dependencies

build: include no dependencies

These switches determine whether PWB automatically scans all source files for include dependencies when your program list is saved.

Message Build Switch

The build: message form of the build switch specifies the format of error messages from a build tool, such as a compiler or a linker. The switch provides PWB with a pattern by which it can recognize the particular lines in the Compile Results window that are the error messages while ignoring other text, such as the copyright banner from a tool, input prompts, or the command line.

Because this ability to recognize the message patterns lets PWB select error messages from all the Compile Results window contents, you can browse through the build errors with the nextmsg editor function or with the Next Error, Previous Error, or Set Error command from the Search menu. As you jump from error to error with one of these commands, PWB highlights the error message and extracts information, such as the source file in which the error is located, the error position, and/or the token that caused the error.

The syntax of the build: message switch is as follows:

build: message "pattern" [file [line [col] | token]]

The pattern specifies the format of the error message. This argument must be in the form of a C string (enclosed in double quotation marks, using C escape sequences for special characters). The format of the pattern is a tagged UNIX regular expression. (Appendix A contains a quick reference to UNIX regular expressions used in PWB. For more information about UNIX regular expressions, see Help for the word regex.) The optional arguments after the pattern determine the meaning(s) of the tagged expression(s).

To construct a pattern string, you can use one, two, or three tagged expressions. The tagged expressions are interpreted according to the following optional arguments.

Argument Description

file The first tag of the pattern is the name of the file that caused the error. If file is not specified, PWB displays only the error message on the status line; if file is specified, PWB also displays the file in the active window.
token If there are two arguments ("pattern" file token), the second tag of the pattern is the token that caused the error. If token is specified, PWB scans the source file, highlights all occurrences of the token in error, and sets the cursor to the first occurrence.
line col If there are three arguments, the second tag of the pattern is the line, and the third tag of the pattern is the column where the error appeared. If these numbers are specified, PWB moves the cursor to the given line and column in the source file. The col argument and the corresponding tag are optional.

These arguments must be specified in the following order:

[file [line [col] | token]]

The brackets denote an optional argument, and the “|” character denotes a choice. For example, the following order of the arguments is valid:

file

file line

file line col

file token

The following order is invalid:

line file

token col

line token

file col token

The following is an example of a complete build: message switch:

build: message "^\\(\\:p\\):\\([0-9]+\\):" file line

In this example, the file and line arguments specify that the first tagged expression is the file name and the second tagged expression is the line number. The lines that this regular expression match are as follows: lines with a path directly after the beginning of the line—denoted by ^\\(\\:p\\)—followed by a colon, followed by a number—denoted by \\([0-9]+\\)—followed by a colon. In this example, the two tagged expressions—denoted by \\( and \\)—correspond to the file name and line number where the error occurred. Upon finding an error message in the Compile Results window that matches this regular expression, PWB opens the file specified by the first tagged expression and highlights the line specified by the number in the second tagged expression.

Example 6 in Appendix B provides additional information on using the build: message switch.

HINTS FOR DEBUGGING REGULAR EXPRESSIONS

When you write UNIX regular expressions to use in your new build: include and build: message switches, getting the regular expression correct the first time may be difficult. This section provides suggestions for debugging UNIX regular expressions easily without having to write and install a set of build switches to test your expressions.

The PWB psearch function lets you use exactly the same types of regular expressions used in build switches. This function searches your text for a string specified by a regular expression. To use this in debugging regular expressions, write a macro that uses the psearch function and your regular expression to do a standard text search on the Compile Results window. For example, add the following lines to your TOOLS.INI file under the [pwb] tag:

msg:= "error \\:n: file \\(\\:p\\)"

findmsg:= arg arg msg psearch

findmsg: F11

You may assign the findmsg macro to any key. We use F11 in this example. You must also ensure that the unixre PWB switch is set to yes. The string in quotation marks in the msg macro is the UNIX regular expression on which to search.

To test your regular expression on a compiler message or on your source file (for a build: include switch), do the following:

1.Add the text above to your TOOLS.INI file, substituting your regular expression for the one assigned to msg above. If you use the above expression, you will find errors similar to the following:

error 2534: file test.c

2.Save your TOOLS.INI file and then reinitialize PWB by calling the PWB initialize function (SHIFT+F8 is the default keystroke assigned to the initialize function).

3.Switch windows to either the Compile Results window (for debugging a build: message switch) or your source file (for the build: include switch).

4.Press F11 to see if one of your compiler messages is found. If not, the expression is incorrect.

If the expression is not correct, change it in your TOOLS.INI file and then repeat steps 2 through 4 above.

When the UNIX regular expression is correct, add it directly into your build switches.

RESERVED MACROS

PWB reserves certain macro names and certain forms of macros for its own use. PWB uses these reserved macros to interpret build rules when creating a program list and to specify source files of a specific type or unique files that can appear in the program list.

To use any reserved (or “special”) macro in the “Constant Reserved Macros” and “Macros Used by Extensions” sections below, add it to the command line for a build command. PWB automatically creates the definition of the macro from files in the program list, applying inference rules as necessary.

If you change the value of a special macro by manually editing the make file, PWB overwrites your changes.

Note:

In the following explanations, the ext part of the macro name can contain only one, two, or three characters from the set [A-Z0-9].

Target Files Macro

Syntax: extS
Examples: OBJS, SBRS, RESS, CS, CXS

A macro of this form lists files with the given extension created in target build commands. PWB generates the value of the macro using files in the program list and applicable inference rules.

For example, assume you have the following files in your program list:

TEST1.C

TEST2.C

AAA.OBJ

BBB.OBJ

CCC.RES

DDD.RC

The following macros are predefined inside a PWB program list, assuming you have an inference rule to build .OBJ files from .C files.

Macro Value

CS TEST1.C TEST2.C
OBJS TEST1.OBJ TEST2.OBJ AAA.OBJ BBB.OBJ
RESS CCC.RES
RCS DDD.RC

To use any of the above macros in your build switches, use the standard NMAKE macro reference format: $(macroname); therefore, to use the OBJS macro, place $(OBJS) in your build switch.

Note that the OBJS macro contains AAA.OBJ and BBB.OBJ as well as TEST1.OBJ and TEST2.OBJ. The TEST1.OBJ and TEST2.OBJ files were added to this macro because we have an inference rule to build .OBJ files from .C files.

To include external modules from the program list, PWB prepends macros with derived names such as extS_EXT to the value of the target files macros. The use of the extS_EXT macro and how it relates to the target files macro is explained in the next section.

Examples 4, 5, and 6 in Appendix B provide additional information on using the target files macro.

External Files Macro

Syntax: extS_EXT
Examples: OBJS_EXT, LIBS_EXT

A macro of this form lists files with the given extension that are not created by a build command but are explicitly included in the program list. An external files macro is prepended to a target files macro for the same extension.

Using the same example as above, the OBJS_EXT macro is set to the value AAA.OBJ BBB.OBJ. The AAA.OBJ and BBB.OBJ files were explicitly contained in the program list rather than being built as a result of a build: command switch. The lines for .OBJ files that would be written to the make file for the above example are as follows:

OBJS_EXT = AAA.OBJ BBB.OBJ

OBJS = $(OBJS_EXT) TEST1.OBJ TEST2.OBJ

Supplementary File Macro

Syntax: ext_FILE
Example: DEF_FILE, HP_FILE

This macro contains the name of one additional file used in a build command and explicitly included in the program list (for example, a module definition file to be used in linking).

The use of this macro implies that only one file of this type is valid in a program list. If a macro of this type is used in a build command and you try to include two files of this type in a program list, an error is triggered. To allow more than one file with the same extension in a program list, use the target files macro form extS as specified earlier in this article.

For the target files macro, external files macro, and supplementary file macro, the build command is not included in the program list if none of the macros used in a build command evaluate to a value.

For example, if you have a command that uses the OBJS macro and one of your target switches uses this command, the command is not written to the make file unless some .OBJ files are in the program list or unless an inference rule creates some .OBJ files.

On the other hand, if you want PWB to allow files with special extensions in your program list, you must do one of the following:

Create an inference rule that requires files with the special extension. For instance, if the switch

build: inference .src.obj src_obj

is added to the build switches, any .SRC files are legally allowed in the program list without flagging an error.

Make a rule that uses the target files macro for the extension you require. For example, to allow the addition of files with a .PSC extension in the program list, use the $(PSCS) macro in one of your build commands, and be sure that this build command is referenced somewhere in a target build switch.

To allow only one type of file with a certain extension, use the supplementary file macro in a build command that is used in a target build switch. For example, to allow only one .DEF file in the program list, use the $(DEF_FILE) macro in one of your build commands, and use this build command in a target build switch.

In some circumstances, creating dummy build commands may be necessary so that PWB can recognize certain types of files for your program list. If you want to recognize some files that do not apply to either of the two cases above, you must create dummy build commands. For an illustration of where this is necessary, see Example 6 in Appendix B.

Constant Reserved Macros

PWB reserves the following macro names in PWB program lists. You can freely use these macros, and PWB automatically defines them for you.

Macro Purpose

DEBUG The value of the debug state. Set with the Build Options dialog box from the Options menu; appears in the make file as either DEBUG = 0 or DEBUG = 1. A value of 0 means that Release is set, and a value of 1 means that Debug is set in the Build Options dialog box.
PROJ The name of the project. This is the basename of the current program list when a program list is set. For example, if the current program list is APP.MAK, the corresponding PROJ definition in the program list is PROJ = APP.
PROJFILE The name of the make file used to build the project.
RUNFLAGS The command line passed to the program by the Execute and Debug commands from the Run menu. Set with the Command Line dialog box from the Run menu.

Macros Used by Extensions

PWB extensions (for example, the C compiler extension, which controls the C Compiler Options dialog boxes) also use macros extensively to hold data that they manage.

The following is a partial list of macros that PWB extensions use. You can freely use these macros in your build commands, but some of them cannot be redefined (see the notes below). For a complete list, see Current Assignment And Switch Settings, which you access by choosing Editor Settings from the Options menu.

Note:

The following macros are used in PWB version 1.0 and may be different in subsequent versions.

This first group of macros holds the general, debug, and release command-line options for Microsoft compilers and linkers.

Macro Usage

CFLAGS_G Flags from the C Compiler Options dialog box
CFLAGS_D Flags from the C Compiler Debug Options dialog box
CFLAGS_R Flags from the C Compiler Release Options dialog box
LFLAGS_G Flags from the LINK Options dialog box
LFLAGS_D Flags from the LINK Debug Options dialog box
LFLAGS_R Flags from the LINK Release Options dialog box

Note:

If any option in the dialog boxes referenced above is changed, the corresponding macro changes accordingly.

Macro Usage

AFLAGS_G Global assembler flags
AFLAGS_D Debug assembler flags
AFLAGS_R Release assembler flags

The CFLAGS_G macro defines the “general” command-line switches (the switches that are always used) for the C compiler, as its _G suffix indicates. (The _R suffix identifies the release-switch macros, and the _D suffix identifies the debug-switch macros.)

The following group of macros hold the names of the compilers and tools; you can redefine these macros in your build switches.

Macro Usage Default

CL The name of the C compiler driver cl
CV The name of the CodeView program cv
ILINK The name of the incremental linker ilink
ASM The name of the assembler masm
CVP The protected mode CodeView cvp
LINK The linker link
PWBRMAKE The PWB Browser utility pwbrmake

These macros make it especially easy to use a non-Microsoft compiler or tool; substitute the name of its executable file and its command-line switches in the appropriate macro definition(s).

The following group of macros hold the lists of libraries and run-time objects that some extensions use.

Macro Usage

LLIBS_G Linker libraries—general
LLIBS_R Linker libraries—release
LLIBS_D Linker libraries—debug
RT_OBJS System run-time object files
RT_LIBS System run-time libraries

PWB extensions define the final two macros, RT_OBJS and RT_LIBS, as necessary. They contain the names of system run-time .OBJs and .LIBs appropriate for the project.

In PWB version 1.0, the C language extension defines these macros when you select certain templates. For example, if you select “OS/2 VIO Multi-threaded DLL, C Runtime in a DLL” from the Set Initial Build Options dialog box, the RT_OBJS macro is set to CRTDLL.OBJ.

In PWB version 1.1, when you use Set Main Language to select a main language other than None, the language extension provides the definition of these macros. If you set the main language to None, no RT_OBJS or RT_LIBS macro is defined, and you must explicitly include the necessary run-time objects and/or libraries in the project.

CREATING YOUR OWN CUSTOM BUILD SWITCHES

To incorporate your own build switches into PWB, add build switch definitions for your own custom templates to the [pwb] section of the TOOLS.INI file.

You may have already created a custom set of build switches without knowing it. When you use the Save Current Build Options command to store a customized set of standard build options, PWB inserts the appropriate set of build switches in your TOOLS.INI file. These switches form a complete and self-contained template; they are not simply a description of the customizations.

The following section describes the procedure for creating your own template of build switches by either modifying an existing set of build switches or creating your own set.

Note:

Although you can modify the build switches in PWB in several ways, you must follow the steps below for the build switches to work properly. (For example, some build switches are in the CURRENT.STS file and are also available by selecting Editor Settings from the Options menu. If you change any build switch in either place, they may not work properly.)

1.Set all appropriate compiler and linker options for your new template under the Options menu. The best way to do this is to first choose the Build Options command from the Options menu. Next, choose Set Main Language to set the correct language if you are using PWB version 1.1 or later. Now choose Set Initial Build Options, and choose the initial set of build options that are closest to the project you would like to build.

2.If you want the same defaults chosen by the initial build options for the type of build you selected, skip this step. Otherwise, go to Compiler Options and LINK Options on the Options menu and change the default settings that your new build-switch template will use. Be sure that the general, release, and debug options are all set to the values you want as the starting defaults when using this new build-switch template.

3.Choose Build Options from the Options menu, and then select Save Current Build Options. Type a name for your new options (this name can be any text—for example, “Microsoft Pascal Compiler Options”). To accept the name, press ENTER or click OK. A new template of build switches is now written to your TOOLS.INI file in its own tagged section. The format of the tag varies according to your version of PWB.

In PWB version 1.0, the tag takes the form:

[pwb-Build Options:name of new options]

In PWB version 1.1 and later, the tag takes the form:

[pwb-Build Options for language:name of new options]

The language is the language you set by choosing Set Main Language. For example, BASIC or C is a possible value. Again, Set Main Language applies only to PWB version 1.1 and later.

4.Bring your TOOLS.INI file into an editor (PWB will work fine). Look for the above tag in the file, and modify or add the appropriate build switches (according to the previous sections of this article) under the tag. When all the build switches are modified, save the file (if you are in PWB, also open the File menu, choose Close, and then exit PWB).

5.Start PWB, and take the following steps to try your new build switches:

A.If you have already set a program list, use the Clear Program List command from the Make menu to save and exit the project.

B.Choose Build Options from the Options menu. Next, set your main language to the language you chose in Step 1 if you are using PWB version 1.1 or later. Choose Set Initial Build Options and choose the name of your new options, which will now appear on the list of choices in the dialog box.

C.Set a new program list (choose Set Program List from the Make menu and type the name of a new make file), and enter all your source files as usual. Now build the program; PWB uses your new set of build switches.

The next time you want to use your customized options for a new project, follow Steps 5a, 5b, and 5c above. You need not follow Steps 1 through 4 because your new build switches are saved in your TOOLS.INI file; therefore, they are always available from the initial build option choices.

MODIFYING A PWB MAKE FILE WITH A "USER SUPPLIED INFORMATION" SECTION

An alternative to creating a new PWB build-switch template is to edit each make file separately, inserting the additional instructions directly into the PWB-generated make file rather than creating build switches to do this for you.

To add your own rules directly to a PWB make file, add the following comment line at the end of the make file:

# << User_supplied_information >>

The pound sign (#) must be in the first column, and the rest of the line must exactly match what is shown, including the case and spacing.

Only the user can modify whatever appears below this line. NMAKE uses it when performing a build, but PWB cannot delete or change it. This feature lets you modify a make file without PWB changing or deleting your customizations.

Note:

You cannot modify a make file if it is set using Set Program List from the Make menu. Select Clear Program List to clear and save the current make file before attempting any modifications.

APPENDIX A: UNIX REGULAR EXPRESSIONS

The following is a short explanation of UNIX regular expressions used in the build: message and build: include PWB build switches. For a complete explanation of the regular expressions, see Help for the word regex.

The build: include and build: message switches both require a UNIX regular expression as a match string when searching through source files for include files or when searching through the Compile Results window for error messages.

The regular expression used in these switches must be in the form of a quoted C string; therefore, any special characters that are normally escaped within a C string by using the backslash (\) must also be escaped here.

The following table lists a subset of the special characters used in UNIX regular expressions. The entire set of characters and their accompanying documentation can be obtained by requesting help on the word regex, either from within PWB or from the command line with QuickHelp. The term class indicates a set of characters; PWB interprets all other characters literally.

Expression Description

\ Escape. Causes PWB to ignore the special meaning of the next character. This character must be quoted with another backslash.
. Wildcard. Matches any single character.
^ Beginning of line.
$ End of line.
[class] Character class.
[^class] Matches any character not specified in the class. For example, [^0-9] matches any character that is not a digit.
X* Zero or more of any pattern.
X+ One or more of the previous pattern.
\( ... \) Tagged expression. The backslashes used here must be escaped with backslashes.
\:letter Predefined string. The backslash must be escaped with another backslash. See below for a listing of a few predefined strings.
\number Reference to the characters matched by the tagged expression. The number is a one-digit number and indicates which expression. The first tagged expression is represented as \1, and so on. The backslash must be escaped.
\{X\!Y\} Alternation. Matches one from a set of alternate patterns. The backslashes in this expression must be escaped with backslashes.

Predefined Strings (Partial List)

Letter Description Example

:a Alphanumeric XXhpfs123
:c Alphabetic Hello
:q Quoted string "count: %d" or 'hat123cat'
:i C-style identifier _printf
:n Number 243.42
:p Path d:\test\hello.c

APPENDIX B: BUILD SWITCH EXAMPLES

The following examples illustrate ways to modify build switches to create your own templates. You can add these examples to existing build switches, but do not make them the only build switches in your template. You can use these methods to incorporate almost any external tool into the PWB build process, including alternative compilers, preprocessors, text formatters, syntax checkers, and so on.

Note:

In this section, some build-switch statements are divided between two or more lines and indented. Blank lines visually divide the switches into groups. These changes are for ease of reading; they do not appear in the TOOLS.INI file.

Example 1. Simple C Preprocessor

This example demonstrates how you can add a C preprocessor to the PWB build process. When you do so, PWB automatically recognizes the C preprocessor files and executes the correct commands to build them. The following switches set up an inference rule to build .CXX preprocessor source files into .OBJ files by using the CXX macro. In the build: command switch, the special NMAKE macro $< is replaced by the dependent file.

Note:

The following switches assume that the “cxxcomp” program builds a .CXX file directly into an .OBJ file without leaving a .C or .ASM file on the disk; if PWB detects a .C file (or an .ASM file) that matches your .OBJ file, it tries to compile the .C file into an .OBJ file before it tries to build with the .CXX file. If your preprocessor leaves a .C file in the current directory, you must rename or delete the file for these rules to work correctly. For more information about this behavior, see the “Inference Build Switch” section. See Example 2 for how to set up a rule that automatically renames your .C file.

build: macro CXX "cxxcomp"

build: inference .cxx.obj cxx_cxx_obj

build: debug command cxx_cxx_obj "$(CXX) $(CFLAGS_G) $(CFLAGS_D) $<"

build: release command cxx_cxx_obj "$(CXX) $(CFLAGS_G) $(CFLAGS_R)

$<"

The first line defines a macro named CXX and assigns it a value of cxxcomp (the name of the tool). The second line defines an inference rule that automatically builds .CXX files into .OBJ files by using the cxx_cxx_obj command. The third and fourth lines actually define the cxx_cxx_obj command that was used in the inference line. The cxx_cxx_obj debug command uses three macros—CXX, CFLAGS_G, and CFLAGS_D. The CXX macro was defined in the first line; the CFLAGS_G and CFLAGS_D macros are predefined macros (see the “Reserved Macros” section). The release command is similar to the debug command except that it uses the CFLAGS_R macro instead of CFLAGS_D.

Example 2. SQL Preprocessor

This example demonstrates how to incorporate a SQL preprocessor into the PWB build process. In addition, it handles transitive inference rules. The following switches, when incorporated into existing build switches, automatically build all .SQC files in your program list into .C files and then into .OBJ files.

Because PWB does not support transitivity between inference rules (for example, between an .sqc.c inference rule and a .c.obj inference rule), building .SQC to .OBJ must use one inference rule with multiple commands, as follows:

build: macro SQL "sqlprep"

build: macro SQLFLAGS "/B /P"

build: macro WORKDIR "d:\\work"

build: inference .sqc.obj sql_sqc_c copy_sqc cc_c_obj del_sav

ren_c_sav

build: command sql_sqc_c "$(SQL) $(SQLFLAGS) $<"

build: command copy_sqc "copy $< $(WORKDIR)"

build: debug command cc_c_obj "$(CC) /c $(CFLAGS_G) $(CFLAGS_D)

/Fo$@ $*.c"

build: release command cc_c_obj "$(CC) /c $(CFLAGS_G) $(CFLAGS_R)

/Fo$@ $*.c"

build: command del_sav "if exist $*.sav del $*.sav"

build: command ren_c_sav "ren $*.c $*.sav"

Note:

The strings in commands must all appear on one line. Some are broken into multiple lines here for ease of reading.

The first three lines define macros that are used in the subsequent build: command switches. The inference rule on the fourth line determines that to build an .OBJ from an .SQC file, five commands must be executed: sql_sqc_c, copy_sqc, cc_c_obj, del_sav, and ren_c_sav.

The first two commands following the inference rule correspond to the first two commands in the inference rule. The first command calls the sqlprep tool to operate on the source file. The second command copies certain files to a separate directory and is included here to show how easily you can add any additional commands to the build process.

The next two lines define a set of commands—one for release mode and one for debug mode. If the program is built in debug mode, the second cc_c_obj command is executed.

The last two lines define the del_sav and ren_c_sav commands. The del_sav command deletes the old .SAV file so that the ren_c_sav command always succeeds. The ren_c_sav command simply renames the .C file to an .SAV extension to avoid the presence of a .C file. The combination of these two commands ensures that a .C file with the same basename as the SQL source file does not exist. The presence of a .C file with the same basename as the SQL source file during the next rebuild “confuses” NMAKE, preventing correct updating. For more information about this behavior and why these special steps are needed, see the “Inference Build Switch” section.

Note that two of the above commands use the predefined macros CFLAGS_R, CFLAGS_D, and CFLAGS_G. PWB automatically defines these, and their values change according to the selection in the C Compiler Options dialog box. For more information about these predefined macros, see the “Reserved Macros” section.

Example 3. Adding the Microsoft Pascal Compiler to the PWB Build Process

The following switches, when incorporated into existing PWB build switches, allow the addition of .PAS files to a PWB program list and cause PWB to call the Pascal compiler on all .PAS files:

build: macro PASCAL "pl"

build: macro PFLAGS_G "/FPi"

build: macro PFLAGS_D "/Zi /Pa /Pd /Fc /Zz"

build: macro PFLAGS_R ""

build: inference .pas.obj pl_pas_obj

build: debug command pl_pas_obj "$(PASCAL) /c $(PFLAGS_G)

$(PFLAGS_D) $<"

build: release command pl_pas_obj "$(PASCAL) /c $(PFLAGS_G)

$(PFLAGS_R) $<"

Note:

The strings in commands must all appear on one line. Some are broken into multiple lines here for ease of reading.

These switches instruct PWB to use the pl command on any .PAS files in the program list—the program is linked to an .EXE file using existing build switches. To allow PWB to understand the error message that the Pascal compiler produces, you must create additional build: message switches that take the format of the error messages into account.

To change the compiler options, you normally select or change the options on the Compiler Options menu in PWB. In this case, however, there is no Pascal extension for PWB, so there is no direct menu access for setting the compiler switches in the various build macros. Therefore, you must use an alternative method to change the options from the defaults in the build switches.

You can change the compiler options in three ways:

You can modify the build switches and reinstall them.

You can go into each PWB-generated make file and modify the macro values.

You can create a set of PWB macros that directly assign values to each of the build-switch macros.

The third method is the most convenient.

The following three macros provide this functionality:

SetPFLAGSG:= arg "Pascal General Options?" prompt -> cancel \

lasttext home "build:macro PFLAGS_G \"" endline "\"" assign

SetPFLAGSD:= arg "Pascal Debug Options?" prompt -> cancel \

lasttext home "build:macro PFLAGS_D \"" endline "\"" assign

SetPFLAGSR:= arg "Pascal Release Options?" prompt -> cancel \

lasttext home "build:macro PFLAGS_R \"" endline "\"" assign

Add these lines to the [pwb] section of your TOOLS.INI file and assign each to a key combination (for example, SetPFLAGSG : CTRL+J). Pressing the key combination prompts you for general, debug, or release options. You can enter the new set of switches at this prompt, and the PWB macros assign the new set of switches to the appropriate build-switch macros.

Example 4. Creating a Library

This example demonstrates how to make your own PWB build switch template that automatically builds a library rather than an executable (.EXE) file.

You add an additional command to each inference rule so that every time a program compiles, the resulting .OBJ file is replaced in the library. The command used here is lib_obj_lib, which calls the Microsoft Library Manager utility, LIB.EXE, to do the work.

These switches are intended to be changed in, or added to, an existing template of build switches:

build: macro LIB "lib"

build: all $(PROJ).lib

build: target $(PROJ).lib lib

build: inference .asm.obj asm_asm_obj lib_obj_lib

build: inference .c.obj cc_c_obj lib_obj_lib

build: command lib_obj_lib "$(LIB) $(PROJ).lib -+$(<B).obj;"

build: command lib "@ECHO $(OBJS) >NUL"

The build: all switch redefines the project to be built. When you choose Build from the Make menu, the $(PROJ).LIB file (the library) is built rather than an .EXE file.

The build: target switch defines the rule to be used to build the library, which is the command named lib. The lib command really does nothing of importance—it simply echoes some text to NUL. This command is a dummy command. It references the OBJS macro, which makes OBJS the dependent for the target $(PROJ).LIB and is required for the asm_asm_obj and cc_c_obj inference rules to be placed in the file. For a discussion of this behavior and why the dummy rule is necessary, see the “Reserved Macros” section.

One drawback to using this template of build switches to create a library is that the library must exist for these build switches to work properly. Initially, you must create the library from the MS-DOS or OS/2 command line.

Example 5. Building an OS/2 Presentation Manager DLL

This example demonstrates the use of some advanced NMAKE features, such as macro substitution and inline files, and how to use these features in PWB build switches.

The following switches are taken from one of the default PWB version 1.0 build-switch templates, the “OS/2 Presentation Manager Multi-threaded DLL” template for the C language. The example below is not the complete set of switches required to build OS/2 Presentation ManagerÔ (PM) multithreaded DLLs but is a subset that demonstrates a few aspects of PWB build switches.

build: macro BIND "bind"

build: macro RC "rc"

build: macro IMPLIB "implib"

build: all $(PROJ).dll

build: target $(PROJ).dll lrf link res implib

build: inference .rc.res rc_rc_res

build: inference .c.obj cc_c_obj

build: release command lrf "$(LRF) @<<$(PROJ).lrf\n

$(RT_OBJS: = +^\n) $(OBJS: = +^\n)\n$@\n

$(MAPFILE_R)\n $(LLIBS_G: = +^\n) +\n

$(LLIBS_R: = +^\n) +\n$(LIBS: = +^\n)\n$(DEF_FILE)

$(LFLAGS_G) $(LFLAGS_R);\n<<"

build: debug command lrf "$(LRF) @<<$(PROJ).lrf \n

$(RT_OBJS: = +^\n) $(OBJS: = +^\n)\n$@\n

$(MAPFILE_D)\n$(LLIBS_G: = +^\n) +\n

$(LLIBS_D: = +^\n) +\n$(LIBS: = +^\n)\n$(DEF_FILE)

$(LFLAGS_G) $(LFLAGS_D);\n<<"

build: release command link "$(LINKER) @$(PROJ).lrf"

build: debug command link "$(ILINK) -a -e \"$(LINKER)

@$(PROJ).lrf\" $@"

build: command rc_rc_res "$(RC) /r $< $@"

build: command res "$(RC) $(RESS) $@"

build: command implib "$(IMPLIB) $*.lib $@"

Note:

The strings in commands must all appear on one line. Some are broken into multiple lines here for ease of reading.

The first few build: macro statements define macros to be used in later build commands. The build: all line specifies that a file with the .DLL extension is to be built when you choose Build or Rebuild All from the Make menu. The actual commands used to build $(PROJ).DLL—lrf, link, res, and implib—are specified on the build: target line.

The next two inference rules specify how PWB is to build .RES files from .RC files and how it is to build .OBJ files from .C files. The first build: command switch, lrf, demonstrates the use of the reserved macros OBJS, RT_OBJS, LIBS, and DEF_FILE. The OBJS and LIBS macros expand to a list of all the corresponding files in the make file (.OBJ and .LIB, respectively), as well as those generated by inference rules (see the “Reserved Macros” section).

The use of NMAKE macro substitution is demonstrated a number of times within the debug and release lrf commands above. For example, the following is the part of the command that performs macro substitution on the OBJS macro:

$(OBJS: = +^\n)

This NMAKE syntax specifies that any spaces in the OBJS macro are replaced by “ +\n” (a space, a plus character, and a new line). The caret (^) in this example is not the new-line character but an escape character that causes the new line following it to be treated as a literal character, rather than as a line delimiter, and to be included in the macro substitution. So, if the OBJS macro evaluated to

ABC.OBJ HELLO.OBJ TEST.OBJ

the corresponding expansion of the OBJS macro, as specified above with the macro substitution, would be as follows:

ABC.OBJ +

HELLO.OBJ +

TEST.OBJ

This type of substitution is used in creating a linker response file and guarantees that no line will exceed the MS-DOS or OS/2 command-line limit. Placing each .OBJ name on a separate line does this. If the OBJS macro is expanded in one line and if the number of .OBJ files is large, the link command fails because the command line is too long.

PWB predefines the RT_OBJS macro in the example. It contains the names of any .OBJ files placed directly in the program list. The DEF_FILE macro evaluates to the single file with the .DEF extension in the program list. If you attempt to put more than one .DEF file into the program list, an error is triggered. The final command of interest is res, which uses the RESS macro. This macro evaluates to all the files with an .RES extension that are generated from the inference rules or are contained in the program list.

Example 6. Building a Microsoft Windows Help File

This example demonstrates a situation in which some dependent files with nonstandard extensions are not actually part of the build commands. To add the files to the program list, you must develop a “dummy” build-switch rule that uses the new extensions so that PWB will recognize them.

The build switches in this example allow Windows Help files to be compiled from within PWB. The Windows Help Compiler (HC.EXE) is different from most tools: Instead of taking various command-line options and input files as arguments, it takes one parameter, which is the name of a file that contains all the input data.

HC.EXE (HC) accepts a single input file with an .HPJ extension. The .HPJ file contains a list of help-topic text files with .RTF extensions and some compiler commands for HC.EXE. HC reads the data from the .HPJ file and then compiles all the .RTF files into the finished Windows Help file, which has an .HLP extension.

We want to put the .HPJ file into the program list so that if we change the options or source files in this file, the .HLP file is rebuilt. In addition, we need to be able to add the .RTF files to the program list so that any changes to the help text cause the .HLP file to be rebuilt.

The following build switches accomplish this:

build: macro HC "hc"

build: all $(PROJ).hlp

build: target $(PROJ).hlp hc_rtf_hlp enable_rtfs

build: command hc_rtf_hlp "$(HC) $(PROJ).hpj"

build: command enable_rtfs "ECHO $(RTFS) $(HPJ_FILE) >NUL"

build: message "\\(\\:f\\.rtf\\)" file

The enable_rtfs build command is a “dummy” command that is only used so that the RTFS and the HPJ_FILE macros can be used in an actual command that was specified in a target build command. This alone allows PWB to recognize the .RTF and .HPJ file extensions.

For more information about the need for the “dummy” rule in this example, see the “Reserved Macros” section.