dmake Version 4.0
=================
FULL RELEASE OF DMAKE, REPLACES VERSIONS 3.8, and 3.9 (never posted)

Nature: This distribution advances dmake to Version 4.0, patch level 0.
------- The release is an attempt at addressing obscure faults in dmake
	and at providing some much needed new functionality.  See below
	for details of enhancements and bug fixes.

	NOTE:  There is one minor syntactic change to the makefile format
	       See the Section "FUTURE FEATURES" below and insure that you do
	       not rely on the previous semantic meaning of the construct
	       whose meaning has changed.

Availability:
-------------
	dmake is available via anonymous ftp from plg.uwaterloo.ca as:

	      pub/dmake/dmake38.tar.gz		- compressed tar archive
	      pub/dmake/dmake38.zip		- zip archive
	      pub/dmake/dmake38-msdos-exe.zip	- MSDOS executable zip archive
	      pub/dmake/dmake38.shar01		- xx part shar archive
	      ...				  (get all parts)
	      pub/dmake/dmake38.sharxx

	and comes in several archive formats.  Choose the one that best
	suits your needs.


DONATIONS TOWARDS REFERENCE MANUAL:
-----------------------------------
	I'm happy to announce that a new project has begun to create a
	dmake reference manual and user guide.  This is being done using the
	services of a technical writer.  The project's success depends to a
	large degree on support that I receive from the NET community.  I have
	carefuly considered how to approach this issue and have decided to
	NOT change the status of dmake to 'shareware', but have rather decided
	to ask for voluntary donations.

	If you find dmake useful to your endeavours then I would appreciate
	a donation in support of the documentation project.  The suggested
	donations are:

		$20	- if you are a private non-commercial user.
		$50	- if you are a commercial or corporate user and
			  use dmake in support of your software development
			  efforts.

	I promise to accurately track donors and will insure them first
	access to the reference manual when it is ready, which at this time
	is estimated to be the start of the second quarter in 95.

	If you want to support this effort then please send a cheque or money
        order in a suitable (to you), amount made out to:

		Dennis Vadura
		Dept. of Computer Science
		University of Waterloo
		Waterloo, Ont.
		Canada, N2L 3G1

	Your support will be greatly appreciated.



DETAILS OF ENHANCEMENTS/TWEAKS:
===============================

BUG FIXES:
----------
- cleaned up the code to fully remove the notion of an initial .SETDIR target
  and macro, had some remnants still present.

- If the first target in a file was a multi :: recipe then if any of the
  :: rules had no recipes an erroneous error was issued.  This is now fixed and
  all of the :: targets behave in a manner consistent with non-:: targets that
  appear as the first target in the makefile.

- Fixed a bug with not properly setting the value of MAKESTARTUP if it was
  given on the command line.

- Specifying -u would not remove inferred prerequisites, they are now forcefully
  rebuilt and then removed if appropriate.

- $ (xx) now expands to just (xx), the $ is eaten.

- fixed a bug with erroneously freeing a directory string for a target.

- Under MSDOS the value of DirSepStr is now used to construct temporary file
  names when $(mktmp ...) is called.  TMPDIR is still taken from the
  environment only since this is what the standard UNIX versions of tempnam do.

- Cleaned up -k processing in conjuction with -P#, it now behaves as expected.

- under MSDOS/and related OS's surrounded the call to exec in spawn.c with
  a getcwd/setcwd pair, this way we will be cd'ed to the same place we were
  at before we ran the command.  DOS is broken this way.  This makes DOS scripts
  behave more like UNIX scripts.  If you really want to say:

	cd foo
	commands...

  Then you will have to use a group recipe, you can do that easier by specifying
  the new .GROUP attribute.

- Fixed incompatibility with Augmake special target mapping, causing

     $(foo:suff1=suff2)

  to behave oddly.  It now behaves as Sun and GNU Make do.  Also suff1,
  and suff2 can now be arbitrary strings not containing an '=' character.
  Both are expanded before the substitution is performed.

- Macro expansion treated ':' as a modifier flag even in function macros.

- Fixed a small bug when parsing makefiles containing #'s in their recipe
  texts and when -B was specified, things now work as expected.

- The inference engine was incorrectly using the value of PREP, fixed.

- Fixed the expansion of $(foo)/{x y z}.o to produce 
	a/x.o a/y.o a/z.o
  if foo = a, and
	a b/x.o a b/y.o a b/z.o
  if foo = a b and
	a/x.o b/x.o a/y.o b/y.o a/z.o b/z.o
  if the specified expansion is stated as:
	{$(foo)}/{x y z}.o

- Fixed a nasty bug in stat.c where the result of Build_path was not dupped
  when computing a new library path name.

- Modified COMMAND macro expansion to properly handle the expansion of
  commands that result in new recipe line attributes.

- Fixed a "feature" that prevented the correct handling of :: recipes.

	a.o :: a.c b.h
	   echo "first recipe..."
	   touch a.o
 
	a.o :: a.y b.h
	   echo "second recipe..."

  now runs both recipes if b.h is newer than a.o.  It used to run only the
  recipe for a.c.  This was contrary to the documentation, and is probably
  not correct in general, in that by definition :: promisses to run all
  recipes that are out of date not just those that are out of date while the
  build continues.

- Fixed a bug with improper output on -n.  It now reports work
  that it thinks should get done.  The actual make may however do less,
  depending on how timestamps are actually modified during the run.

- Fixed a bug in detecting function macros, the following now works:
  (caused a core dump before)...

     bar = a b c
     foo = $(!null,$(bar:s/ /) -Lhithere)

     all:; echo $(foo)

  Thanks to "Brett M. Bergquist, brett.bergquist@corp.gdc.com" for pointing
  it out, and for providing the inspiration for the fix..


NEW EXTENSIONS:
---------------
- added .EXIT special target to exit from parsing a makefile and ignore
  the remainder to the end.  If verbose is set then a message is issued.

- Made the macros DIRSEPSTR, and DIRBRKSTR user settable.  The default setting
  for the MSDOS version of DIRSEPSTR is now \\, this allows it to correctly
  work for $(mktmp ...) diversions.

- Added two new attributes, and a command line option.
	.GROUP when specified with a target says execute this targets recipe
	as if it were a group recipe specified in [ ... ] notation.

	.IGNOREGROUP is an attribute variable that when set to "yes" says
	don't assume that a recipe line beginning with '[' is a group recipe.
	This in effect turns off group recipe parsing at the granularity of
	a single target or globally if specified alone in the makefile.

	-g is equivalent to saying .IGNOREGROUP:=yes at the start of startup.mk
	file.

- Path name construction for stat'ed targets has been modified to ignore './'
  entries and to reduce 'foo/..' sequences to NULL.  That is, it makes little
  sense to have a path that cd's to a directory and then back up.  This may
  result in having the value of $@ be somewhat unexpected depending on
  settings of .SOURCE and their friends.  However this is infact the correct
  behaviour since the resolved pathname and the target name (as used internally)
  are not the same.  dmake treats the resolved pathname as an attribute of the
  target that may infact be different from the target name itself.

- dmake attempts to make targets of .INCLUDE if the name cannot be found in
  any of the subdirectories specified in .INCLUDEDIRS.  Specifying .INCLUDE
  .IGNORE causes dmake to not terminate if a prerequisite of .INCLUDE cannot
  be made.

- Added a .FIRST attribute for .INCLUDE special targets.  Specifying .FIRST
  on a .INCLUDE line will attempt to include each named prerequisite and will
  halt after finding the first prerequisite that exists.  If no prerequisite
  is successfully included and .IGNORE was not specified then an error is
  issued.

- Created new variable .NAMEMAX which when set to an integer value bounds the
  maximum length of a file name component.  By default it is set to the
  compiled value NAME_MAX.

- $(shell,expand stuff) is a modification to $(shell ...) that causes the
  result to be expanded before it is returned.  if ',expand' is not specified
  then the result is not expanded.  The addition of expansion together with
  the new $(assign ...) macro allows external files to be read and to have them
  define macros as a result of the $(shell ...) execution.


NEW FEATURES:
-------------
- Generalized the expansion of Dynamic prerequisites.  Specification of
  $$(foo) as a prerequisite is recursively expanded until the current cell
  contains no $ signs.  If the expansion results in multiple white space
  separated tokens they are inserted into the prerequisite list in place of
  the initial dynamic prerequisite.  If the new list contains additional
  dynamic prerequisites then they will be expanded when they are processed.
  NOTE:  there is a limit on the number of times the same prerequisite can be
  recursively dynamically expanded, it is controlled by the setting of the
  macro DYNAMICNESTINGLEVEL, and is set to 100 by default.  Thus the same
  prerequisite can be expanded dynamically a 100 times before dmake gives
  up with an error.

- Added -w and -W (whatif command line flags) and also significantly fixed up
  the processing for -n, to actually produce sensible output.

- Added '!' macro prefix indicating that the macro assignment is to be forced.
  That is, don't complain if the macro has been previously expanded.  This can
  be used for single macro assignments:

	foo := stuff
	foo !:= silently blow away stuff in foo
	foo !+:= add this silently to previous value of foo

  or in conjunction with .SILENT as in:

	__.SILENT !:= $(.SILENT)
	change stuff to your hearts content...
	.SILENT !:= $(__.SILENT)

- Added a $(macro:e) extension for returning the suffixes of a file list
  in the macro.

- Added a $(macro:u) and $(macro:l) modifiers for converting the macro value
  to all upper case and lower case respectively.

- Added a $(macro:i) modifier.  It returns the inferred names for targets as
  given in a $< macro.  For example:

	.SOURCE : objs
	OBJS = x.o y.o

	all:$(OBJS); echo $(OBJS:i)

   will produce

	objs/x.o y.o

   if x.o is found in the subdirectory 'objs'.  The 'i' modifier can be
   mixed with all other modifiers.


- Added the .ROOT special target, it is the top level target that dmake builds
  when it starts to build targets.  Also all user specified targets, either
  through the command line or by default in the makefile, are made prerequisites
  of the special target .TARGETS.  By default dmake sets up the relationship
  that .ROOT depends on .TARGETS, and the world gets made.  This allows you
  to customize within the makefile the order of building targets as well as
  which target is made 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 :;

  which nicely emulates the behaviour of Sun's make extensions.  The building
  of .ROOT's prerequisites is internally always forced to be sequential.

- Added dynamic macro assignment for use in recipes and otherwise.
  $(assign string) parses string as if it were a macro assignment string.
  string must contain a valid macro assignment, otherwise an error is issued.

	eg. $(assign foo := fred)
	    $(assign $(indirect_macro_name) +:= $(morejunk))

  The result of this macro assignment is the name of the macro that was
  assigned, and NULL if the expression is not a valid assignment.

- Added a new macro modifier $(foo:^prefix) where prefix is either a quoted
  string "string" that is prepended to each token found in
  the value of $(foo) or prefix is a macro expression beginning with $, in
  which case prefix is expanded and the result is prepended to each token
  found in $(foo).

- Added a new macro modifier $(foo:+suffix) where suffix is either a quoted
  string "string" that is appended to each token found in
  the value of $(foo) or suffix is a macro expression beginning with $, in
  which case suffix is expanded and the result is appended to each token
  found in $(foo).

- You can now put $$@ into .SETDIR attribute strings, and the name of the
  target to be built is used for the attempted CD.  Note that the final
  value of $@ will depend on the result of the stat search which is done
  after the change directory call forced by the .SETDIR attribute.

- Added a new function macro $(nil args) that always returns "", no matter what
  its arguments are.

- Added directory caching.  It is enabled by default and causes dmake to
  cache the timestamps of entries in a directory the first time the directory
  is visited.  Dmake tracks entries and performs actual stats as required
  to collect new timestamps, but does not perform stats on potential targets
  during inference after reading the directory contents the first time.

  setting .DIRCACHE=yes enables directory cache, and setting .DIRCACHE=no
  disbles it.  It is on by default.

- Added conditional macros.

     You can now say the following:

	target ?= MacroName MacroOp Value

     This creates a definition for MacroName whose value is Value
     only when target is being made.  You may use a conditional macro
     assignment anywhere that a regular macro assignment may appear, including
     as the value of a $(assign ...) macro.

     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 built.  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 set
     conditional macro values 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.

- Enhanced the processing of .UPDATEALL, the following constructs are now
  allowed:

	a b .UPDATEALL : c

	a b .UPDATEALL :: d

  A .UPDATEALL causes all targets on the left to be treated as a single target
  all are updated whenever any one of them is made.  As a sideffect, such
  targets are sorted in ascending alphabetical order, when any one of the
  group is constructed the value of $@ is the one that is first in the sorted
  set.


FUTURE FEATURES:
----------------
In the future the functionality of .UPDATEALL will be extended to %-meta
rules as will the ability to infer multiple prerequisites.  Thereby allowing
inference of multiple targets from multiple prerequisites.  In preparation
for this functionality the following change was made to the parser.

	%.o : %.c %.f ; recipe

  used to be equivalent to:

	%.o : %.c ; recipe
	%.o : %.f ; recipe

  It now means defaults to:

	%.o : %.c ; recipe

  you must specify:

	%.o :| %.c %.f ; recipe

  to get the old behaviour.  This is due to the fact that construction of
  the internal target graph has been been altered but the inference engine
  has not yet been updated to utilize the new functionality (I ran out of
  time).


ACKNOWLEDGEMENTS:
=================
	Thanks to all who submitted code for new features, suggestions for
	improvements, and bug fixes.  I have tried to make sure no gotchas
	remain, if you encounter problems installing or running dmake please
	let me know.  As always, I am always happy to receive e-mail.

	Many have contributed suggestions and bug fixes that make this
	release possible.  The NET thanks you.
