|
NAMEdmake - maintain program groups, or interdependent filesSYNOPSISdmake [-P#] [-{f|C|K} file] [-{w|W} target ...] [macro[[!][*][+][:]]=value ...] [-ABcdeEghiknpqrsStTuVxX] [-v[cdfimrtw]] [-m[trae]] [target ...]DESCRIPTIONdmake is a re-implementation of the UNIX Make utility with significant enhancements. dmake executes commands found in an external file called a makefile to update one or more target names. Each target may depend on zero or more prerequisite targets. If any of the target's prerequisites is newer than the target or if the target itself does not exist, then dmake will attempt to make the target.If no -f command line option is present then dmake searches for an existing makefile from the list of prerequisites specified for the special target .MAKEFILES (see the STARTUP section for more details). If "-" is the name of the file specified to the -f flag then dmake uses standard input as the source of the makefile text. Any macro definitions (arguments with embedded "=" signs) that appear on the command line are processed first and supercede definitions for macros of the same name found within the makefile. In general it is impossible for definitions found inside the makefile to redefine a macro defined on the command line, see the MACROS section for exceptions. If no target names are specified on the command line, then dmake uses the first non-special target found in the makefile as the default target. See the SPECIAL TARGETS section for the list of special targets and their function. Makefiles written for most previous versions of Make will be handled correctly by dmake. Known differences between dmake and other versions of make are discussed in the COMPATIBILITY section found at the end of this document. dmake returns 0 if no errors were detected and a non-zero result if an error occurred. OPTIONS
INDEXHere is a list of the sections that follow and a short description of each. Perhaps you won't have to read the entire man page to find what you need.
STARTUPWhen dmake begins execution it first processes the command line and then processes an initial startup-makefile. This is followed by an attempt to locate and process a user supplied makefile. The startup file defines the default values of all required control macros and the set of default rules for making targets and inferences. When searching for the startup makefile, dmake searches the following locations, in the order specified, until a startup file is located:
The above search is disabled by specifying the -r option on the command line. An error is issued if a startup makefile cannot be found and the -r option was not specified. A user may substitute a custom startup file by defining the MAKESTARTUP environment variable or by redefining the MAKESTARTUP macro on the command line. To determine where dmake looks for the default startup file, check your environment or issue the command "dmake -V". A similar search is performed to locate a default user makefile when no -f command line option is specified. By default, the prerequisite list of the special target .MAKEFILES specifies the names of possible makefiles and the search order that dmake should use to determine if one exists. A typical definition for this target is: .MAKEFILES : makefile.mk Makefile makefile If the first line of the user makefile is of the form: #!command command_args dmake builds the internal dependency graph as it parses a user specified makefile. The graph is rooted at the special target .ROOT. .ROOT is the top level target that dmake builds when it starts to build targets. All user specified targets (those from the command line or taken as defaults from the makefile) are made prerequisites of the special target .TARGETS. dmake by default creates the relationship that .ROOT depends on .TARGETS and as a result everything is made. This approach allows the user to customize, within their makefile, the order and which, target, is built first. For example the default makefiles come with settings for .ROOT that specify: .ROOT .PHONY .NOSTATE .SEQUENTIAL : .INIT .TARGETS
.DONE
with .INIT and .DONE defined as: .INIT .DONE .PHONY:;
which nicely emulates the behaviour of Sun's make extensions. The building of .ROOT's prerequisites is always forced to be sequential. However, this definition is trivially changed by supplying the definition: .ROOT : .TARGETS
which skips the preamble and postamble phases of building .TARGETS. Please note that even though .INIT and .DONE are special exceptions, see section SPECIAL TARGETS, the use of self defined targets starting with `.' should be avoided as they would be handled as .<suffix> meta targets. The target names _INIT and _DONE for example would work equally well without the .<suffix> drawback. SYNTAXThis section is a summary of the syntax of makefile statements. The description is given in a style similar to BNF, where { } enclose items that may appear zero or more times, and [ ] enclose items that are optional. Alternative productions for a left hand side are indicated by '→', and newlines are significant. All symbols in bold type are text or names representing text supplied by the user.
target-definition → targets [attrs] op { PREREQUISITE } [; rcp-line]
Where, TAB represents a <tab> character, STRING represents an arbitrary sequence of characters, and LINE represents a possibly empty sequence of characters terminated by a non-escaped (not immediately preceded by a backslash '\') new-line character. MACRO, PREREQUISITE, and TARGET each represent a string of characters not including space or tab which respectively form the name of a macro, prerequisite or target. The name may itself be a macro expansion expression. A LINE can be continued over several physical lines by terminating it with a single backslash character. Comments are initiated by the pound # character and extend to the end of line. All comment text is discarded, a '#' may be placed into the makefile text by escaping it with '\' (ie. \# translates to # when it is parsed). An exception to this occurs when a # is seen inside a recipe line that begins with a <tab> or is inside a group recipe. If you specify the -c command line switch then this behavior is disabled and dmake will treat all # characters as start of comment indicators unless they are escaped by \. A set of continued lines may be commented out by placing a single # at the start of the first line. A continued line cannot span more than one makefile. white space is defined to be any combination of <space>, <tab>, and the sequence \<nl> when \<nl> is used to terminate a LINE. Note the special treatment of \<nl> in macro definion and recipe lines below. When processing macro definition lines, any amount of white space is allowed on either side of the macro operator and white space is stripped from both before and after the macro value string. A \<nl> sequence in a macro definition is deleted from the macro value before assigning this value. During recipe expansion the sequence \<nl> is treated as white space but is deleted from the final recipe string. You must escape the \<nl> with another \ in order to get a \ at the end of a recipe or macro definition line. When processing target definition lines, the recipe for a target must, in general, follow the first definition of the target (See the RULES AND TARGETS section for an exception), and the recipe may not span across multiple makefiles. Any targets and prerequisites found on a target definition line are taken to be white space separated tokens. The rule operator (op in SYNTAX section) is also considered to be a token but does not require white space to precede or follow it. Since the rule operator begins with a `:', traditional versions of make do not allow the `:' character to form a valid target name. dmake allows `:' to be present in target/prerequisite names as long as the entire target/prerequisite name is quoted. For example: a:fred : test would be parsed as TARGET = a, PREREQUISITES={fred, :, test}, which is not what was intended. To fix this you must write: "a:fred" : test Which will be parsed as expected. Quoted target and prerequisite specifications may also contain white space thereby allowing the use of complex function macro expressions.. See the EXAMPLES section for how to apply " quoting to a list of targets. ATTRIBUTESdmake defines several target attributes. Attributes may be assigned to a single target, a group of targets, or to all targets in the makefile. Attributes are used to modify dmake actions during target update. The recognized attributes are:
/tmp/mytarget
With .WINPATH set it expands to:
C:/cygwin/tmp/mytarget
All attributes are user setable and except for .UPDATEALL and .MKSARGS may be used in one of two forms. The .MKSARGS attribute is restricted to use as a global attribute, and the use of the .UPDATEALL attribute is restricted to rules of the second form only. ATTRIBUTE_LIST : targets assigns the attributes specified by ATTRIBUTE_LIST to each target in targets or targets ATTRIBUTE_LIST : ... assigns the attributes specified by ATTRIBUTE_LIST to each target in targets. In the first form if targets is empty (ie. a NULL list), then the list of attributes will apply to all targets in the makefile (this is equivalent to the common Make construct of ".IGNORE :" but has been modified to the notion of an attribute instead of a special target). Not all of the attributes have global meaning. In particular, .LIBRARY, .NOSTATE, .PHONY, .SETDIR, .SYMBOL and .UPDATEALL have no assigned global meaning. Any attribute may be used with any target, even with the special targets. Some combinations are useless (e.g. .INCLUDE .PRECIOUS: ... ), while others are useful (e.g. .INCLUDE .IGNORE : "file.mk" will not complain if file.mk cannot be found using the include file search rules, see the section on SPECIAL TARGETS for a description of .INCLUDE). If a specified attribute will not be used with the special target a warning is issued and the attribute is ignored. MACROSdmake supports six forms of macro assignment.
Macro expressions specified on the command line allow the macro value to be redefined within the makefile only if the macro is defined using the '+=' and '+:=' operators. Other operators will define a macro that cannot be further modified. Each of the preceeding macro assignment operators may be prefixed by ! to indicate that the assignment should be forced and that no warnings should be issued. Thus, specifying ! has the effect of silently forcing the specified macro assignment. When dmake defines a non-environment macro it strips leading and trailing white space from the macro value. Macros imported from the environment via either the .IMPORT special target (see the SPECIAL TARGETS section), or the -e, or -E flags are an exception to this rule. Their values are always taken literally and white space is never stripped. In addition, named macros defined using the .IMPORT special target do not have their values expanded when they are used within a makefile. In contrast, environment macros that are imported due to the specification of the -e or -E flags are subject to expansion when used. To specify a macro expansion enclose the name in () or {} and precede it with a dollar sign $. Thus $(TEST) represents an expansion of the macro variable named TEST. If TEST is defined then $(TEST) is replaced by its expanded value. If TEST is not defined then $(TEST) expands to the NULL string (this is equivalent to defining a macro as 'TEST=' ). A short form may be used for single character named macros. In this case the parentheses are optional, and $(I) is equivalent to $I. Macro expansion is recursive, hence, if the value string contains an expression representing a macro expansion, the expansion is performed. Circular macro expansions are detected and cause an error to be issued. When defining a macro the given macro name is first expanded before being used to define the macro. Thus it is possible to define macros whose names depend on values of other macros. For example, suppose CWD is defined as CWD = $(PWD:b) then the value of $(CWD) is the name of the current directory. This can be used to define macros specific to this directory, for example: _$(CWD).prt = list of files to print... The actual name of the defined macro is a function of the current directory. A construct such as this is useful when processing a hierarchy of directories using .SETDIR attributed targets and a collection of small distributed makefile stubs. Macro variables may be defined within the makefile, on the command line, or imported from the environment. dmake supports several non-standard macro expansions: The first is of the form:
where modifier_list may be a combination of:
or a single one of:
Thus if we have the example: test = d1/d2/d3/a.out f.out d1/k.out
The following macro expansions produce the values on the right of '→'
after expansion.
For this macro test = d1/d2/../a.out "d1/file name.ext"
the following results are returned:
If a token ends in a string composed from the value of the macro DIRBRKSTR (ie. ends in a directory separator string, e.g. '/' in UNIX) and you use the :d modifier then the expansion returns the directory name less the final directory separator string. Thus successive pairs of :d modifiers each remove a level of directory in the token string. The infered names of targets :i modifier returnes the actual filename associated to the target, see BINDING TARGETS. If the value is not a target or prerequisite the value is returned unchanged. For the following example: test = aprog bprog
If aprog and bprog are targets or prerequisits and they are bound to /tmp/aprog
and bprog (see .SOURCE special target) the macro expansion has the following
effect:
The normalized path names :n modifier honors the setting of .WINPATH to determine the output format of the result. The map escape codes modifier changes the following escape codes \a => <bel>, \b => <backspace>, \f => <formfeed>, \n => <nl>, \r => <cr>, \t => <tab>, \v => <vertical tab>, \" => ", and \xxx => <xxx> where xxx is the octal representation of a character into the corresponding ASCII value. The tokenization, prepend and append modifier may use the same escape codes that are supported by the map escape codes modifier in the string that is inserted, prepended or added by the respective macro modifier. These modifiers may quote this string to include otherwise problematic characters. E.g. spaces, colons and parentheses. The tokenization modifier takes all white space separated tokens from the macro value and separates them by the separator string. Thus the expansion: $(test:f:t"+\n") produces: a.out+ f.out+ k.out The prefix operator ^ takes all white space separated tokens from the macro value and prepends string to each. $(test:f:^mydir/) produces: mydir/a.out mydir/f.out mydir/k.out The suffix operator + takes all white space separated tokens from the macro value and appends string to each. $(test:b:+.c) produces: a.c f.c k.c The next non-standard form of macro expansion allows for recursive macros. It is possible to specify a $(macro_name) or ${macro_name} expansion where macro_name contains more $( ... ) or ${ ... } macro expansions itself. For example $(CC$(_HOST)$(_COMPILER)) will first expand CC$(_HOST)$(_COMPILER) to get a result and use that result as the name of the macro to expand. This is useful for writing a makefile for more than one target environment. As an example consider the following hypothetical case. Suppose that _HOST and _COMPILER are imported from the environment and are set to represent the host machine type and the host compiler respectively. CFLAGS_VAX_CC = -c -O # _HOST == "_VAX", _COMPILER == "_CC" CFLAGS_PC_MSC = -c -ML # _HOST == "_PC", _COMPILER == "_MSC" # redefine CFLAGS macro as: CFLAGS := $(CFLAGS$(_HOST)$(_COMPILER)) The final non-standard macro expansion is of the form: string1{token_list}string2 where string1, string2 and token_list are expanded. After expansion, string1 is prepended to each token found in token_list and string2 is appended to each resulting token from the previous prepend. string1 and string2 are not delimited by white space whereas the tokens in token_list are. A null token in the token list is specified using "". Thus using another example we have:
This last expansion is activated only when the first characters of token_list appear immediately after the opening '{' with no intervening white space. The reason for this restriction is the following incompatibility with Bourne Shell recipes. The line { echo hello;} {echo hello;} is not. Hence the latter triggers the enhanced macro expansion while the former causes it to be suppressed. See the SPECIAL MACROS section for a description of the special macros that dmake defines and understands. RULES AND TARGETSA makefile contains a series of entries that specify dependencies. Such entries are called target/prerequisite or rule definitions. Each rule definition is optionally followed by a set of lines that provide a recipe for updating any targets defined by the rule. Whenever dmake attempts to bring a target up to date and an explicit recipe is provided with a rule defining the target, that recipe is used to update the target. A rule definition begins with a line having the following syntax:<targets> [<attributes>] <ruleop> [<prerequisites>] [;<recipe>] targets is a non-empty list of targets. If the target is a special target (see SPECIAL TARGETS section below) then it must appear alone on the rule line. For example: .IMPORT .ERROR : ...
is not allowed since both .IMPORT and .ERROR are special targets. Special targets are not used in the construction of the dependency graph and will not be made. attributes is a possibly empty list of attributes. Any attribute defined in the ATTRIBUTES section above may be specified. All attributes will be applied to the list of named targets in the rule definition. No other targets will be affected.
ruleop is a separator which is used to identify the targets from the prerequisites. Optionally it also provides a facility for modifying the way in which dmake handles the making of the associated targets. In its simplest form the operator is a single ':', and need not be separated by white space from its neighboring tokens. It may additionally be followed by any of the modifiers { !, ^, -, :, | }, where:
Targets defined using a single `:' operator with a recipe may be redefined again with a new recipe by using a `:' operator with a `:' modifier. This is equivalent to a target having been initially defined with a rule using a `:' modifier. Once a target is defined using a `:' modifier it may not be defined again with a recipe using only the `:' operator with no `:' modifier. In both cases the use of a `:' modifier creates a new list of prerequisites and makes it the current prerequisite list for the target. The `:' operator with no recipe always modifies the current list of prerequisites. Thus assuming each of the following definitions has a recipe attached, then: joe : fred ... (1) joe :: more ... (2) and joe :: fred ... (3) joe :: more ... (4) joe :: fred ... (5) joe : more ... (6) and joe : fred ... (7) joe : more ... (8) prerequisites is a possibly empty list of targets that must be brought up to date before making the current target. recipe is a short form and allows the user to specify short rule definitions on a single line. It is taken to be the first recipe line in a larger recipe if additional lines follow the rule definition. If the semi-colon is present but the recipe line is empty (ie. null string) then it is taken to be an empty rule. Any target so defined causes target to be treated as a virtual target, see VIRTUAL TARGETS below. RECIPESThe traditional format used by most versions of Make defines the recipe lines as arbitrary strings that may contain macro expansions. They follow a rule definition line and may be spaced apart by comment or blank lines. The list of recipe lines defining the recipe is terminated by a new target definition, a macro definition, or end-of-file. Each recipe line MUST begin with a <TAB> character (or spaces, see .NOTABS) which may optionally be followed with one or all the following recipe property characters '@%+-' which affect the recipe execution:
Each property is off by default (ie. by default, errors are significant, commands are echoed, no swapping is done and a shell is used only if the recipe line contains a character found in the value of the SHELLMETAS macro). Global settings activated via command line options or special attribute or target names may also affect these settings. An example recipe: target : first recipe line second recipe line, executed independent of first. @a recipe line that is not echoed -and one that has errors ignored %and one that causes dmake to swap out +and one that is executed using a shell. The second and new format of the recipe block begins the block with the character '[' (the open group character) in the last non-white space position of a line, and terminates the block with the character ']' (the close group character) in the first non-white space position of a line. In this form each recipe line need not have a leading TAB. This is called a recipe group. Groups so defined are fed intact as a single unit to a shell for execution whenever the corresponding target needs to be updated. If the open group character '[' is preceded by one or all of the recipe properties (-, %, @ and @@) then they apply to the entire group in the same way that they apply to single recipe lines. You may also specify '+' but it is redundant as a shell is already being used to run the recipe. See the MAKING TARGETS section for a description of how dmake invokes recipes. Here is an example of a group recipe: target : [ first recipe line second recipe line tall of these recipe lines are fed to a single copy of a shell for execution. ] BUILTIN COMMANDSdmake supports some builtin commands. An optional leading '+' describes that the builtin can be used also when being executed in a shell otherwise it is only implemented when used directly. Remember that if a character of the recipe is found in the SHELLMETAS macro the execution of the recipe in a shell is forced.
No special treatment of buildin commands for group recipes is implemented even though the <empty recipe> will most propably also not be evaluated by most shells that can be used to handle the recipe groups. TEXT DIVERSIONSdmake supports the notion of text diversions. If a recipe line contains the macro expression$(mktmp[,[file][,text]] data) data can be any text and must be separated from the 'mktmp' portion of the macro name by white-space. The only restriction on the data text is that it must contain a balanced number of parentheses of the same kind as are used to initiate the $(mktmp ...) expression. For example: $(mktmp $(XXX)) $(mktmp text (to dump to file) ${mktmp text (to dump to file} mytext:=this is a\ntest of the text diversion all: cat $(mktmp $(mytext:m)) cat /tmp/mk12294AA OBJ = fred.obj mary.obj joe.obj all : $(OBJ) link @$(mktmp $(^:t"+\n")) link @/tmp/mk02394AA fred.obj+ mary.obj+ joe.obj If the optional file specifier is present it can be used to specify the name of the temporary file to create. An example that would be useful for MSDOS users with a Turbo-C compiler $(mktmp,turboc.cfg $(CFLAGS)) Under MS-DOS text diversions may be a problem. Many DOS tools require that path names which contain directories use the \ character to delimit the directories. Some users however wish to use the '/' to delimit pathnames and use environments that allow them to do so. The macro USESHELL is set to "yes" if the current recipe is forced to use a shell via the .USESHELL or '+' directives, otherwise its value is "no". The dmake startup files define the macro DIVFILE whose value is either the value of TMPFILE or the value of TMPFILE edited to replace any '/' characters to the appropriate value based on the current shell and whether it will be used to execute the recipe. Previous versions of dmake defined text diversions using <+, +> strings, where <+ started a text diversion and +> terminated one. dmake is backward compatible with this construct only if the <+ and +> appear literally on the same recipe line or in the same macro value string. In such instances the expression: <+data+> is mapped to: $(mktmp data) which is fully output compatible with the earlier construct. <+, +> constructs whose text spans multiple lines must be converted by hand to use $(mktmp ...). If the environment variable TMPDIR is defined then the temporary file is placed into the directory specified by that variable. A makefile can modify the location of temporary files by defining a macro named TMPDIR and exporting it using the .EXPORT special target. VIRTUAL TARGETSDmake allows to define targets with the sole purpose to enforce a dependency chain that are unable to create the target, hence virtual targets. When dmake tries to make a target, but only finds a target definition without recipe lines, it would normally issues a "Don't know how to make ..." error message, but if a target rule is terminated by a semicolon and has no following recipe lines, or if it has no recipe lines, but defines prerequisites, or if the AUGMAKE mode is enabled (see the COMPATIBILITY section for details), the target is treated as a virtual target and the error is suppressed. In addition to this, if the default target does not have recipe lines it is also treated as a virtual target.Virtual targets should not have a corresponding file therefore they inherit the time of their newest prerequisite if they have prerequisites, otherwise they get the current time assigned when being made. If the virtual target has a corresponding file a warning is issued, but the time stamp of that file is taken into account. The virtual target uses the time stamp of the corresponding file if it is newer than the one determined by the previous rule. SPECIAL TARGETSThis section describes the special targets that are recognized by dmake. Some are affected by attributes and others are not.
There are a few targets that are "slightly" special: .INIT .DONE Please note that self defined targets shouldn't use the prefix `.' as they would be handled as .<suffix> meta targets and dmake most propably would complain about this. In addition to the special targets above, several other forms of targets are recognized and are considered special, their exact form and use is defined in the sections that follow. SPECIAL MACROSdmake defines a number of special macros. They are divided into three classes: control macros, run-time macros, and function macros. The control macros are used by dmake to configure its actions, and are the preferred method of doing so. In the case when a control macro has the same function as a special target or attribute they share the same name as the special target or attribute. The run-time macros are defined when dmake makes targets and may be used by the user inside recipes. The function macros provide higher level functions dealing with macro expansion and diversion file processing.CONTROL MACROSTo use the control macros simply assign them a value just like any other macro. The control macros are divided into three groups: string valued macros, character valued macros, and boolean valued macros.The following are all of the string valued macros. This list is divided into two groups. The first group gives the string valued macros that are defined internally and cannot be directly set by the user.
The second group of string valued macros control dmake behavior and may be set by the user.
There is only one character valued macro defined by dmake: SWITCHAR contains the switch character used to introduce options on command lines. For UNIX its value is `-', and for MSDOS its value may be `/' or `-'. The macro is internally defined and is not user setable. The MSDOS version of dmake attempts to first extract SWITCHAR from an environment variable of the same name. If that fails it then attempts to use the undocumented getswitchar system call, and returns the result of that. Under MSDOS version 4.0 you must set the value of the environment macro SWITCHAR to '/' to obtain predictable behavior. All boolean macros currently understood by dmake correspond directly to the previously defined attributes. These macros provide a second way to apply global attributes, and represent the preferred method of doing so. They are used by assigning them a value. If the value is not a NULL string then the boolean condition is set to on. If the value is a NULL string then the condition is set to off. There are five conditions defined and they correspond directly to the attributes of the same name. Their meanings are defined in the ATTRIBUTES section above. The macros are: .EPILOG, .IGNORE, .MKSARGS, .NOINFER, .PRECIOUS, .PROLOG, .SEQUENTIAL, .SILENT, .SWAP, and .USESHELL. Assigning any of these a non NULL value will globally set the corresponding attribute to on. RUNTIME MACROSThese macros are defined when dmake is making targets, and may take on different values for each target. $@ is defined to be the full target name, $? is the list of all out of date prerequisites, except for the ! ruleop, in which case it is set to the current build prerequisite instead. $& is the list of all prerequisites, $> is the name of the library if the current target is a library member, and $< is the list of prerequisites specified in the current rule. If the current target had a recipe inferred then $< is the name of the inferred prerequisite even if the target had a list of prerequisites supplied using an explicit rule that did not provide a recipe. In such situations $& gives the full list of prerequisites.$* is defined as $(@:db) when making targets with explicit recipes and is defined as the value of % when making targets whose recipe is the result of an inference. In the first case $* is the target name with no suffix, and in the second case, is the value of the matched % pattern from the associated %-rule. $^ expands to the set of out of date prerequisites taken from the current value of $<. In addition to these, $$ expands to $, {{ expands to {, }} expands to }, and the strings <+ and +> are recognized as respectively starting and terminating a text diversion when they appear literally together in the same input line. The difference between $? and $^ can best be illustrated by an example, consider: fred.out : joe amy hello rules for making fred fred.out : my.c your.h his.h her.h # more prerequisites
FUNCTION MACROSdmake supports a full set of functional macros. One of these, the $(mktmp ...) macro, is discussed in detail in the TEXT DIVERSION section and is not covered here. The names of function macros must appear literally after the opening $( or ${. They are not recognized if they are the result of a recursive expansion.Note that some of these macros take comma separated parameters but that these parameters must not contain literal whitespaces. Whitespaces in macros used in these parameters are allowed.
$(assign foo := fred) $(assign $(ind_macro_name) +:= $(morejunk))
list = a b c all :; echo [$(foreach,i,$(list) [$i])] [[a] [b] [c]] $(foreach,i,$(foreach,i,$(sort c a b) root/$i) [$i/f.h]) [root/a/f.h] [root/b/f.h] [root/c/f.h] $($(assign list=a b c)) $(sort d a b c) $(echo a b c) $(foreach,i,a b c [$i]) "b c [a]"
$(shell ls *.c) $(shell +ls *.c) Note that if the macro is part of a recipe it will be evaluated after all previous recipe lines have been executed. For obvious reasons it will be evaluated before the current recipe line or group recipe is executed.
$(subst,.o,.c $(OBJECTS)) $(OBJECTS:s/.o/.c/)
$(name something) CONDITIONAL MACROSdmake supports conditional macros. These allow the definition of target specific macro values. You can now say the following:target ?= MacroName MacroOp Value The new definition is associated with the most recent cell definition for target. If no prior definition exists then one is created. The implications of this are immediately evident in the following example: foo := hello all : cond;@echo "all done, foo=[$(foo)] bar=[$(bar)]" cond ?= bar := global decl cond .SETDIR=unix::;@echo $(foo) $(bar) cond ?= foo := hi cond .SETDIR=msdos::;@echo $(foo) $(bar) cond ?= foo := hihi The first conditional assignment creates a binding for 'bar' that is activated when 'cond' is made. The bindings following the :: definitions are activated when their respective recipe rules are used. Thus the first binding serves to provide a global value for 'bar' while any of the cond :: rules are processed, and the local bindings for 'foo' come into effect when their associated :: rule is processed. Conditionals for targets of .UPDATEALL are all activated before the target group is made. Assignments are processed in order. Note that the value of a conditional macro assignment is NOT AVAILABLE until the associated target is made, thus the construct mytarget ?= bar := hello mytarget ?= foo := $(bar) results in $(foo) expanding to "", if you want the result to be "hello" you must use: mytarget ?= bar := hello mytarget ?= foo = $(bar) Once a target is made any associated conditional macros are deactivated and their values are no longer available. Activation occurrs after all inference, and .SETDIR directives have been processed and after $@ is assigned, but before prerequisites are processed; thereby making the values of conditional macro definitions available during construction of prerequisites. If a %-meta rule target has associated conditional macro assignments, and the rule is chosen by the inference algorithm then the conditional macro assignments are inferred together with the associated recipe. DYNAMIC PREREQUISITESdmake looks for prerequisites whose names contain macro expansions during target processing. Any such prerequisites are expanded and the result of the expansion is used as the prerequisite name. As an example the line:fred : $$@.c causes the $$@ to be expanded when dmake is making fred, and it resolves to the target fred. This enables dynamic prerequisites to be generated. The value of @ may be modified by any of the valid macro modifiers. So you can say for example: fred.out : $$(@:b).c where the $$(@:b) expands to fred. Note the use of $$ instead of $ to indicate the dynamic expansion, this is due to the fact that the rule line is expanded when it is initially parsed, and $$ then returns $ which later triggers the dynamic prerequisite expansion. Dynamic macro expansion is performed in all user defined rules, and the special targets .SOURCE*, and .INCLUDEDIRS. NOTE: The use of a $ as part of a prerequisite or target name is strongly discouraged as the runtime macros (like $@) are expanded when used in a recipe line so that the $ is interpreted as a macro identifier and not as a character of the filename leading to invalid runtime macros. In addition to this no filename normalization is done for prerequisites and targets that contain $ characters. Nevertheless it is possible to use $ in prerequisites by using $$$$ but this is not recommended and can lead to surprising results. If dynamic macro expansion results in multiple white space separated tokens then these are inserted into the prerequisite list inplace of the dynamic prerequisite. Due to the recursive nature of macro expansion the prerequisite list is fully expanded even if the dynamic prerequisite contained other runtime macros. BINDING TARGETSThis operation takes a target name and binds it to an existing file, if possible. dmake makes a distinction between the internal target name of a target and its associated external file name. Thus it is possible for a target's internal name and its external file name to differ. To perform the binding, the following set of rules is used. Assume that we are trying to bind a target whose name is of the form X.suff, where .suff is the suffix and X is the stem portion (ie. that part which contains the directory and the basename). dmake takes this target name and performs a series of search operations that try to find a suitably named file in the external file system. The search operation is user controlled via the settings of the various .SOURCE targets.
There is potential here for a lot of search operations. The trick is to define .SOURCE.x special targets with short search lists and leave .SOURCE as short as possible. The search algorithm has the following useful side effect. When a target having the .LIBMEMBER (library member) attribute is searched for, it is first searched for as an ordinary file. When a number of library members require updating it is desirable to compile all of them first and to update the library at the end in a single operation. If one of the members does not compile and dmake stops, then the user may fix the error and make again. dmake will not remake any of the targets whose object files have already been generated as long as none of their prerequisite files have been modified as a result of the fix. When dmake constructs target (and prerequisite) pathnames they are normalized to the shortest (or most natural, see below for the cygwin case) representation. Substrings like './' or of the form 'baz/..' are removed and multiple slashes are collapsed to one unless they are at the beginning of the pathname. Leading slashes are normalized according to POSIX rules, i.e. more than two leading slashes are reduced to one slash and a leading '//' is kept as it might have a special meaning. For example "./foo", "bar/../foo" and foo are recognized as the same file. This may result in somewhat unexpected values of the macro expansion of runtime macros like $@, but is infact the corect result. NOTE: A cygwin dmake executable will accept DOS like pathnames with drive letters and cygwin POSIX pathnames and normalize them into its natural POSIX representation. This might result in even more surprising values of runtime macros. When defining .SOURCE and .SOURCE.x targets the construct .SOURCE :
.SOURCE :- fred gery dmake correctly handles the UNIX Make variable VPATH. By definition VPATH contains a list of ':' separated directories to search when looking for a target. dmake maps VPATH to the following special rule: .SOURCE :^ $(VPATH:s/:/ /) PERCENT(%) RULES AND MAKING INFERENCESWhen dmake makes a target, the target's set of prerequisites (if any) must exist and the target must have a recipe which dmake can use to make it. If the makefile does not specify an explicit recipe for the target then dmake uses special rules to try to infer a recipe which it can use to make the target. Previous versions of Make perform this task by using rules that are defined by targets of the form .<suffix>.<suffix> (this is still supported, see "AUGMAKE META RULES") or by using the not supported by dmake .SUFFIXES list of suffixes (see "SPECIAL TARGETS" for more details about .SUFFIXES). The exact workings of this mechanism were sometimes difficult to understand and often limiting in their usefulness. Instead, dmake supports the concept of %-meta rules. The syntax and semantics of these rules differ from standard rule lines as follows:<%-targets> [<attributes>] <ruleop> [<%-prereqs>] [;<recipe>] where %-targets are one or more targets containing exactly a single `%' sign, attributes is a list (possibly empty) of attributes, ruleop is the standard set of rule operators, %-prereqs , if present, is a list of prerequisites containing zero or more `%' signs, and recipe, if present, is the first line of the recipe. If more than one %-target is present this line is equivalent to a repetition of the whole [<attributes>] <ruleop> [<%-prereqs>] [;<recipe>] sequence for each %-target, i.e. it is possible to specify the same rule for multiple %-targets. Because of this following only speaks about <%-target> as %-targets are divided into multiple definitions with a single %-target. NOTE: As multiple %-targets didn't work reliably with dmake versions prior to 4.5 unless the rule operator `|:' was used we currently issue a warning stating that it now works. The %-target defines a pattern against which a target whose recipe is being inferred gets matched. The pattern match goes as follows: all chars are matched exactly from left to right up to but not including the % sign in the pattern, % then matches the longest string from the actual target name not ending in the suffix given after the % sign in the pattern. Consider the following examples:
Please note, that only the first, non-indirect, prerequisite of the list is used for the inference mechanism. If more than one non-indirect prerequisite is given a warning is issued and all but the first non-indirect prerequisites are ignored. See below for a description of indirect prerequisites. As an example the following %-meta rules describe the following: %.c : %.y ; recipe... foo%.o : fee%.k ; recipe... %.a :; recipe... %.c : %.y 'yaccsrc/%.y' ; recipe... % : RCS/%,v ; co $< % : s.% ; get $< The previous RCS example defines an infinite rule, because it says how to make anything from RCS/%,v, and anything also includes RCS/fred.c,v. To limit the size of the graph that results from such rules dmake uses the macro variable PREP (stands for % repetition). By default the value of this variable is 0, which says that no repetitions of a %-rule are to be generated. If it is set to something greater than 0, then that many repetitions of any infinite %-rule are allowed. If in the above example PREP was set to 1, then dmake would generate the dependency graph: % --> RCS/%,v --> RCS/RCS/%,v,v dmake supports dynamic prerequisite generation for prerequisites of %-meta rules. This is best illustrated by an example. The RCS rule shown above can infer how to check out a file from a corresponding RCS file only if the target is a simple file name with no directory information. That is, the above rule can infer how to find RCS/fred.c,v from the target fred.c, but cannot infer how to find srcdir/RCS/fred.c,v from srcdir/fred.c because the above rule will cause dmake to look for RCS/srcdir/fred.c,v; which does not exist (assume that srcdir has its own RCS directory as is the common case). A more versatile formulation of the above RCS check out rule is the following: % : $$(@:d)RCS/$$(@:f),v : co $@ dmake can also infer indirect prerequisites. An inferred target can have a list of prerequisites added that will not show up in the value of $< but will show up in the value of $? and $&. Indirect prerequisites are specified in an inference rule by quoting the prerequisite with single quotes. For example, if you had the explicit dependency: fred.o : fred.c ; rule to make fred.o fred.o : local.h %.o : %.c 'local.h' ; makes a .o from a .c %.o : %.c '$(INC)/%.h' ; rule to make a .o from a .c %.o :| %.c %.f 'local.h'; recipe %.o : %.c 'local.h' ; recipe %.o : %.f 'local.h' ; recipe If any of the attributes .EPILOG, .IGNORE, .LIBRARY, .NOSTATE, .PHONY, .PRECIOUS, .PROLOG, .SETDIR, .SILENT, .SWAP, .USESHELL and .WINPATH are given for a %-rule then when that rule is bound to a target as the result of an inference, the target's set of attributes is augmented by the attributes from the above set that are specified in the bound %-rule. Other attributes specified for %-meta rules are not inherited by the target. The .SETDIR attribute is treated in a special way. If the target already had a .SETDIR attribute set then dmake changes to that directory prior to performing the inference. During inference any .SETDIR attributes for the inferred prerequisite are honored. The directories must exist for a %-meta rule to be selected as a possible inference path. If the directories do not exist no error message is issued, instead the corresponding path in the inference graph is rejected. dmake bases all of its inferences on the inference graph constructed from the %-rules defined in the makefile. It knows exactly which targets can be made from which prerequisites by making queries on the inference graph. For a %-meta rule to be inferred as the rule whose recipe will be used to make a target, the target's name must match the %-target pattern, and any inferred %-prerequisite must already exist or have an explicit recipe so that the prerequisite can be made. Without transitive closure on the inference graph the above rule describes precisely when an inference match terminates the search. If transitive closure is enabled (the usual case), and a prerequisite does not exist or cannot be made, then dmake invokes the inference algorithm recursively on the prerequisite to see if there is some way the prerequisite can be manufactured. For, if the prerequisite can be made then the current target can also be made using the current %-meta rule. This means that there is no longer a need to give a rule for making a .o from a .y if you have already given a rule for making a .o from a .c and a .c from a .y. In such cases dmake can infer how to make the .o from the .y via the intermediary .c and will remove the .c when the .o is made. Transitive closure can be disabled by giving the -T switch on the command line. A word of caution. dmake bases its transitive closure on the %-meta rule targets. When it performs transitive closure it infers how to make a target from a prerequisite by performing a pattern match as if the potential prerequisite were a new target. The set of rules: %.o : %.c ; rule for making .o from .c %.c : %.y ; rule for making .c from .y % : RCS/%,v ; check out of RCS file .NOINFER : RCS/%,v dmake tries to remove intermediate files resulting from transitive closure if the file is not marked as being PRECIOUS, or the -u flag was not given on the command line, and if the inferred intermediate did not previously exist. Intermediate targets that existed prior to being made are never removed. This is in keeping with the philosophy that dmake should never remove things from the file system that it did not add. If the special target .REMOVE is defined and has a recipe then dmake constructs a list of the intermediate files to be removed and makes them prerequisites of .REMOVE. It then makes .REMOVE thereby removing the prerequisites if the recipe of .REMOVE says to. Typically .REMOVE is defined in the startup file as: .REMOVE :; $(RM) $< AUGMAKE META RULESAs a subclass of the meta targets that is actually mapped to %-meta rules dmake understands several SYSV AUGMAKE targets transformations. This .<suffix> special target construct transforms into the following %-meta rules:.suff :; recipe % : %.suff; recipe dmake also supports the old format special target .<suffix>.<suffix> by identifying any rules of this form and mapping them to the appropriate %-rule. So for example if an old makefile contains the construct: .c.o :; cc -c $< -o $@ %.o : %.c; cc -c $< -o $@ .c~.o :; recipe %.o : s.%.c ; recipe MAKING TARGETSIn order to update a target dmake must execute a recipe. When a recipe needs to be executed it is first expanded so that any macros in the recipe text are expanded, and it is then either executed directly or passed to a shell. dmake supports two types of recipes. The regular recipes and group recipes.When a regular recipe is invoked dmake executes each line of the recipe separately using a new copy of a shell if a shell is required. Thus effects of commands do not generally persist across recipe lines (e.g. cd requests in a recipe line do not carry over to the next recipe line). This is true even in environments such as MSDOS, where dmake internally sets the current working director to match the directory it was in before the command was executed. The decision on whether a shell is required to execute a command is based on the value of the macro SHELLMETAS or on the specification of '+' or .USESHELL for the current recipe or target respectively. If any character in the value of SHELLMETAS is found in the expanded recipe text-line or the use of a shell is requested explicitly via '+' or .USESHELL then the command is executed using a shell, otherwise the command is executed directly. The shell that is used for execution is given by the value of the macro SHELL. The flags that are passed to the shell are given by the value of SHELLFLAGS. Thus dmake constructs the command line: $(SHELL) $(SHELLFLAGS) $(expanded_recipe_command) If the $(SHELLCMDQUOTE) macro is set its value is inserted before and after the $(expanded_recipe_command) string. Normally dmake writes the command line that it is about to invoke to standard output. If the .SILENT attribute is set for the target or for the recipe line (via @), then the recipe line is not echoed. Group recipe processing is similar to that of regular recipes, except that a shell is always invoked. The shell that is invoked is given by the value of the macro GROUPSHELL, and its flags are taken from the value of the macro GROUPFLAGS. If a target has the .PROLOG attribute set then dmake prepends to the shell script the recipe associated with the special target .GROUPPROLOG, and if the attribute .EPILOG is set as well, then the recipe associated with the special target .GROUPEPILOG is appended to the script file. This facility can be used to always prepend a common header and common trailer to group recipes. Group recipes are echoed to standard output just like standard recipes, but are enclosed by lines beginning with [ and ]. The recipe flags [+,-,%,@] are recognized at the start of a recipe line even if they appear in a macro. For example: SH = + all: $(SH)echo hi SH = + all: +echo hi The last step performed by dmake prior to running a recipe is to set the macro CMNDNAME to the name of the command to execute (determined by finding the first white-space ending token in the command line). It then sets the macro CMNDARGS to be the remainder of the line. dmake then expands the macro COMMAND which by default is set to COMMAND = $(CMNDNAME) $(CMNDARGS) COMMAND = $(CMNDNAME) @$(mktmp $(CMNDARGS)) $(CMNDNAME) @/tmp/ASAD23043 MAKING LIBRARIESLibraries are easy to maintain using dmake. A library is a file containing a collection of object files. Thus to make a library you simply specify it as a target with the .LIBRARY attribute set and specify its list of prerequisites. The prerequisites should be the object members that are to go into the library. When dmake makes the library target it uses the .LIBRARY attribute to pass to the prerequisites the .LIBMEMBER attribute and the name of the library. This enables the file binding mechanism to look for the member in the library if an appropriate object file cannot be found. dmake now supports Elf libraries on systems that support Elf and hence supports, on those systems, long member file names. A small example best illustrates this.mylib.a .LIBRARY : mem1.o mem2.o mem3.o rules for making library... # remember to remove .o's when lib is made # equivalent to: '%.o : %.c ; ...' .c.o :; rules for making .o from .c say dmake tries to handle the old library construct format in a sensible way. The construct lib(member.o) is separated and the lib portion is declared as a library target. The new target is defined with the .LIBRARY attribute set and the member.o portion of the construct is declared as a prerequisite of the lib target. If the construct lib(member.o) appears as a prerequisite of a target in the makefile, that target has the new name of the lib assigned as its prerequisite. Thus the following example: a.out : ml.a(a.o) ml.a(b.o); $(CC) -o $@ $< .c.o :; $(CC) -c $(CFLAGS) -o $@ $< %.a: ar rv $@ $? ranlib $@ rm -rf $? a.out : ml.a; $(CC) -o $@ $< ml.a .LIBRARY : a.o b.o %.o : %.c ; $(CC) -c $(CFLAGS) -o $@ $< %.a : ar rv $@ $? ranlib $@ rm -rf $? The same thing happens for any target of the form lib((entry)). These targets have an additional feature in that the entry target has the .SYMBOL attribute set automatically. NOTE: If the notion of entry points is supported by the archive and by dmake (currently not the case) then dmake will search the archive for the entry point and return not only the modification time of the member which defines the entry but also the name of the member file. This name will then replace entry and will be used for making the member file. Once bound to an archive member the .SYMBOL attribute is removed from the target. This feature is presently disabled as there is little standardization among archive formats, and we have yet to find a makefile utilizing this feature (possibly due to the fact that it is unimplemented in most versions of UNIX Make). Finally, when dmake looks for a library member it must first locate the library file. It does so by first looking for the library relative to the current directory and if it is not found it then looks relative to the current value of $(TMD). This allows commonly used libraries to be kept near the root of a source tree and to be easily found by dmake. KEEP STATEdmake supports the keeping of state information for targets that it makes whenever the macro .KEEP_STATE is assigned a value. The value of the macro should be the name of a state file that will contain the state information. If state keeping is enabled then each target that does not poses the .NOSTATE attribute will have a record written into the state file indicating the target's name, the current directory, the command used to update the target, and which, if any, :: rule is being used. When you make this target again if any of this information does not match the previous settings and the target is not out dated it will still be re-made. The assumption is that one of the conditions above has changed and that we wish to remake the target. For example, state keeping is used in the maintenance of dmake to test compile different versions of the source using different compilers. Changing the compiler causes the compilation flags to be modified and hence all sources to be recompiled.The state file is an ascii file and is portable, however it is not in human readable form as the entries represent hash keys of the above information. The Sun Microsystem's Make construct .KEEP_STATE : MULTI PROCESSINGIf the architecture supports it then dmake is capable of making a target's prerequisites in parallel. dmake will make as much in parallel as it can and use a number of child processes up to the maximum specified by MAXPROCESS or by the value supplied to the -P command line flag. A parallel make is enabled by setting the value of MAXPROCESS (either directly or via -P option) to a value which is > 1. dmake guarantees that all dependencies as specified in the makefile are honored. A target will not be made until all of its prerequisites have been made. Note that when you specify -P 4 then four child processes are run concurrently but dmake actually displays the fifth command it will run immediately upon a child process becomming free. This is an artifact of the method used to traverse the dependency graph and cannot be removed. If a parallel make is being performed then the following restrictions on parallelism are enforced.
Note: If you specify a parallel make then the order of target update and the order in which the associated recipes are invoked will not correspond to that displayed by the -n flag. CONDITIONALSdmake supports a makefile construct called a conditional. It allows the user to conditionally select portions of makefile text for input processing and to discard other portions. This becomes useful for writing makefiles that are intended to function for more than one target host and environment. The conditional expression is specified as follows:.IF expression ... if text ... .ELIF expression ... if text ... .ELSE ... else text ... .END The .ELSE and .ELIF portions are optional, and the conditionals may be nested (ie. the text may contain another conditional). .IF, .ELSE, and .END may appear anywhere in the makefile, but a single conditional expression may not span multiple makefiles. expression can be one of the following forms: String evaluation
Numeric evaluation
Boolean evaluation
where text is either text or a macro expression. In any case, before the comparison is made, the expression is expanded. The text portions are then selected and compared. In the case of the numeric comparisons enclosing quotes are removed after expanding the expressions and the leading numerical parts are converted to an integer number. If no numerical part is found this results to 0 (zero). The string "12ab" for example evaluates to the number 12. Expressions can be nested with () and the use of || or &&. White space at the start and end of the text portion is discarded before the comparison. This means that a macro that evaluates to nothing but white space is considered a NULL value for the purpose of the comparison. In the first case the expression evaluates TRUE if the text is not NULL otherwise it evaluates FALSE. The remaining two cases both evaluate the expression on the basis of a string comparison. If a macro expression needs to be equated to a NULL string then compare it to the value of the macro $(NULL). You can use the $(shell ...) macro to construct more complex test expressions. EXAMPLES# A simple example showing how to use make # prgm : a.o b.o cc a.o b.o -o prgm a.o : a.c g.h cc a.c -o $@ b.o : b.c g.h cc b.c -o $@ In the previous example prgm is remade only if a.o and/or b.o is out of date with respect to prgm. These dependencies can be stated more concisely by using the inference rules defined in the standard startup file. The default rule for making .o's from .c's looks something like this: %.o : %.c; cc -c $(CFLAGS) -o $@ $< Since there exists a rule (defined in the startup file) for making .o's from .c's dmake will use that rule for manufacturing a .o from a .c and we can specify our dependencies more concisely. prgm : a.o b.o cc -o prgm $< a.o b.o : g.h A more general way to say the above using the new macro expansions would be: SRC = a b OBJ = {$(SRC)}.o prgm : $(OBJ) cc -o $@ $< $(OBJ) : g.h If we want to keep the objects in a separate directory, called objdir, then we would write something like this. SRC = a b OBJ = {$(SRC)}.o prgm : $(OBJ) cc $< -o $@ $(OBJ) : g.h %.o : %.c $(CC) -c $(CFLAGS) -o $(@:f) $< mv $(@:f) objdir .SOURCE.o : objdir # tell dmake to look here for .o's An example of building library members would go something like this: (NOTE: The same rules as above will be used to produce .o's from .c's) SRC= a b LIB= lib LIBm= { $(SRC) }.o prgm: $(LIB) cc -o $@ $(LIB) $(LIB) .LIBRARY : $(LIBm) ar rv $@ $< rm $< Finally, suppose that each of the source files in the previous example had the `:' character in their target name. Then we would write the above example as: SRC= f:a f:b LIB= lib LIBm= "{ $(SRC) }.o" # put quotes around each token prgm: $(LIB) cc -o $@ $(LIB) $(LIB) .LIBRARY : $(LIBm) ar rv $@ $< rm $< COMPATIBILITYThere are two notable differences between dmake and the standard version of BSD UNIX 4.2/4.3 Make.
dmake is not compatible with GNU Make. In particular it does not understand GNU Make's macro expansions that query the file system. dmake is fully compatible with SYSV AUGMAKE, and supports the following AUGMAKE features:
LIMITSIn some environments the length of an argument string is restricted. (e.g. MSDOS command line arguments cannot be longer than 128 bytes if you are using the standard command.com command interpreter as your shell, dmake text diversions may help in these situations.)PORTABILITYTo write makefiles that can be moved from one environment to another requires some forethought. In particular you must define as macros all those things that may be different in the new environment. dmake has two facilities that help to support writing portable makefiles, recursive macros and conditional expressions. The recursive macros, allow one to define environment configurations that allow different environments for similar types of operating systems. For example the same make script can be used for SYSV and BSD but with different macro definitions.To write a makefile that is portable between UNIX and MSDOS requires both features since in almost all cases you will need to define new recipes for making targets. The recipes will probably be quite different since the capabilities of the tools on each machine are different. Different macros will be needed to help handle the smaller differences in the two environments. FILESMakefile, makefile, startup.mk (use dmake -V to tell you where the startup file is)SEE ALSOsh(1), csh(1), touch(1), f77(1), pc(1), cc(1)S.I. Feldman Make - A Program for Maintaining Computer Programs AUTHORDennis Vadura, dvadura@wticorp.comMany thanks to Carl Seger for his helpful suggestions, and to Trevor John Thompson for his many excellent ideas and informative bug reports. Many thanks also go to those on the NET that have helped in making dmake one of the best Make tools available. BUGSSome system commands return non-zero status inappropriately. Use -i (`-' within the makefile) to overcome the difficulty.Some systems do not have easily accessible time stamps for library members (MSDOS, AMIGA, etc) for these dmake uses the time stamp of the library instead and prints a warning the first time it does so. This is almost always ok, except when multiple makefiles update a single library file. In these instances it is possible to miss an update if one is not careful. This man page is way too long. WARNINGSRules supported by make(1) may not work if transitive closure is turned off (-T, .NOINFER).PWD from csh/ksh will cause problems if a cd operation is performed and -e or -E option is used. Using internal macros such as COMMAND, may wreak havoc if you don't understand their functionality.
Visit the GSP FreeBSD Man Page Interface. |