1#
2# /+\
3# +\		Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
4# \+/
5#
6# This file is part of Jam - see jam.c for Copyright information.
7#
8
9# The Copyright information in jam.c reads:
10#
11#/*
12# * /+\
13# * +\   Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
14# * \+/
15# *
16# * This file is part of jam.
17# *
18# * License is hereby granted to use this software and distribute it
19# * freely, as long as this copyright notice is retained and modifications
20# * are clearly marked.
21# *
22# * ALL WARRANTIES ARE HEREBY DISCLAIMED.
23# */
24
25# MODIFIDED version of jam 2.5 Jambase, for the ArgyllCMS project by Graeme W. Gill.
26#           These modifications are herebye licensed under the same conditions
27#           as as the rest of Jam, as detailed above.
28#           Moved to a "Normalized" scheme, where Jamfile UNIX style target paths
29#			are converted to platform specific, Jamfile relative, Gristed/SEARCH/LOCATE
30#			form internally. Creating the tree is simplified by eliminating the SubDir
31#           rule. Better support for MingW, OS X. More comprehensive ruleset.
32#           Renamed Jamrules to Jamtop.
33#
34# JAMBASE - jam 2.5 ruleset providing make(1)-like functionality
35#
36# Supports UNIX, NT, and VMS.
37#
38# Special targets defined in this file:
39#
40# all				- parent of first, shell, files, lib, exe
41# first				- first dependent of 'all', for potential initialization
42# shell				- parent of all Shell targets
43# files				- parent of all File targets
44# lib				- parent of all Library targets
45# exe				- parent of all Main targets
46# dirs				- parent of all MkDir targets
47# install			- parent of all Install targets
48# clean				- removes all Shell, File, Library, and Main targets
49# uninstall			- removes all Install targets
50#
51
52# Rules defined by this file:
53#
54# As obj : source.s ;					.s -> .o
55# Bulk dir : files ;					populate directory with many files
56# Cc obj : src.c : flags : defines : hdrpaths
57#										.c -> .o
58# C++ obj : src.cc : flags : defines : hdrpaths
59#										.cc -> .o
60# Clean clean : sources ;				remove sources with 'jam clean'
61# File dest : source ;					copy file
62# FileNoClean dest : source ;			copy file, but don't delete dest during clean
63# FakeFile dest : source ;				Fudge to say dest is created with source
64# Fortran obj.o : source.f ;			.f -> .o
65# GenFile target : program args ;		make custom file
66# GenFileND target : program args : extra_dependecies ;
67#										make custom file, program dependent & args not
68# GenFileNND target : program args : extra_dependecies ;
69#                                       make custom file, program & args not dependent
70# GenFileNNDnc target : program args : extra_dependecies ;
71#                                       Same as GenFileNND but don't clean the target.
72# CatToFile dest : strings ;			save the arguments to the file
73# GuiBin image ;						Mark executable as GUI applications
74#                                       (Needs to go before other declarations of image)
75# HardLink target : source ;			make link from source to target
76# HdrRule source : headers ;			handle #includes
77# InstallInto dir : sources ;			install any files
78# InstallBin dir : sources ;			install binaries
79# InstallLib dir : sources ;			install files
80# InstallShLib dir : sources ;			install files
81# InstallFile dir : sources ;			install files
82# InstallMan dir : sources ;			install man pages
83# InstallShell dir : sources ;			install shell scripts
84# Lex source.c : source.l ;				.l -> .c
85# Library library : sources : flags : defines : hdrpaths : objects
86#										static library from compiled sources
87# LibraryFromLibraries lib : libs ;		static library from static libraries
88# LibraryFromObjects lib : objects ;	static library from objects
89# LinkLibraries images : libraries ;	add static libraries onto Mains
90# LinkObjects images : objects ;		add objects onto Mains
91# LinkShLibraries images : shlibraries ;	add shared libraries onto Mains
92# Main image : sources : flags : defines : hdrpaths : objects : libs : shlibs ;
93# 										create exe from compiled sources
94# MainsFromSources sources ;			create exes each from their source
95# MainFromObjects image : objects : libs : shlibs ;
96#										create executable from objects
97# MainVariant image : sources : flags : defines : hdrpaths : objects : libs : shlibs ;
98# 										create exe from compiled sources with separate named objs
99# MainLinkFlags mains : flags ;			add linker flags for object
100# MkDir dir ;							make a directory, if not there
101# Mod target : mode ;					sets mode of file
102# NDepends dest : source ;				make Normalized dependency
103# NNoUpdate targ ;						create Normalized target if needed but never update it
104# NIncludes dest : source ;				make Normalized co-dependency
105# Object object : sources : flags : defines : hdrpaths ; 	compile object from source
106# ObjectCcFlags objects : flags ;		add compiler flags for object
107# ObjectPrefCcFlags objects : flags ;	add preference compiler flags for object (overridable)
108# ObjectC++Flags objects : flags ;		add compiler flags for object
109# ObjectPrefC++Flags objects : flags ;	add preference compiler flags for object (overridable)
110# ObjectDefines objects : defines ;		add defines for object
111# ObjectHdrs objects : dirs ;			add include directories for object
112# ObjectKeep objects ;					mark objects to be kept after library build
113# Objects sources : flags : defines : hdrpaths 		compile sources
114# PeerInclude dir ;						include peer Jamfile
115# FindTop ; 							Set TOP by locating JAMTOP file above SUBDIR
116# ProjTop d1 d2 .. ;					Set project TOP
117# RmTemps target : sources ;			remove temp sources after target made
118# Setuid images ;						mark executables Setuid
119#	set SHLINKDEFFILE on for Windows to define exports using .def file.
120#	set SHLINKSEARCHEXEPATH true on UNIX/OSX to have applications search exeutable location for it
121# ShLibrary shlib : source ;				link shared library from compiled sources
122# ShLibraryFromObjects shlib : objects ;	link shared library from objects
123# ShLibraryLibraries shlib : libraries ;	add static libraries onto shared libraries link
124# ShLibraryObjects shlib : objects ;		add objects onto shared libraries link
125# ShLibraryShLibraries shlib : shlibraries ;	add shared libraries onto shared libraries link
126# SoftLink target : source ;			make symlink from source to target
127# SubInclude dir ;						include sub Jamfile
128# Shell exe : source ;					make a shell executable
129# Undefines images : symbols ;			save undef's for linking
130# UserObject object : source ;			handle unknown suffixes for Object
131# Yacc source.c : source.y ;			.y -> .c
132# Aswig : source.i ;					.i -> .h _i.c .hpp
133#
134# Utility rules
135#
136# val = geton var : varname ;				return the value of varname on var
137# paths = NormPaths paths [ : dir ] ;		normalize a set of paths relative to SUBDIR or dir
138# paths = NormSrcPaths paths [ : dir ] ;	NormPaths with SRCDIR
139# paths = NormDstPaths paths [ : dir ] ;	NormPaths with DSTDIR
140# paths = NormSrcTargets paths [ : dir ] ;	normalize source targets, set Grist NOMLOC SEARCH
141# paths = NormDstTargets paths [ : dir ] ;	normalize destination targets, set Grist NOMLOC LOCATE
142# paths = NormISrcTargets paths [ : dir ] ;	Same as NormSrcTargets but ignore SRCDIR
143# paths = NormIDstTargets paths [ : dir ] ;	Same as NormDstTargets but ignore DSTDIR
144#
145# More utility rules that have no side effects :
146#
147# FAppendSuffix f1 f2 ... : $(SUF) ;	return $(<) with suffixes if no current suffixes
148# FStripCommon v1 : v2 ;				strip common initial parts of v1 v2
149# FReverse a1 a2 ... ;					return ... a2 a1
150# FDelEmpty a1 a2 ... ;					return a1 a2 ... with any empty elements deleted
151#
152# Variables:
153#
154# Sub-Jamfile build variables, optionaly set in each Sub-Jamfile. They will
155# be picked up by subsequent rules that set target relationships and
156# creation rules. They are added to any Parent-Jamfile variables,
157# and become the Parent-Jamfile variables of any SubIncludes.
158# Relative file/path variables are anchored by the Jamfile location.
159#
160# ASFLAGS      - Flags for the assembler.
161# CCFLAGS      - Flags for the C compiler.
162# C++FLAGS     - Flags for the C++ compiler.
163# LINKFLAGS    - Flags for the executable linker.
164# SHLINKFLAGS  - Flags for the shared library linker.
165# HDRS         - Complile header search directories
166# DEFINES      - Compile defines
167# LINKOBJS     - Link extra objects
168# LINKLIBS     - Link extra libraries
169# LINKSHLIBS   - Link extra shared libraries
170# SHLINKOBJS     - ShLibrary Linker extra objects
171# SHLINKLIBS     - ShLibrary Linker extra libraries
172# SHLINKSHLIBS   - ShLibrary Linker extra shared libraries
173#
174# Sub-directory preferred build flags, e.g. optimizations etc.  These will only
175# have effect if not set by a parent Jamfile (ie. involked from a leaf Jamfile).
176#
177# PREF_ASFLAGS
178# PREF_CCFLAGS
179# PREF_C++FLAGS
180# PREF_LINKFLAGS
181# PREF_SHLINKFLAGS
182#
183# Parent-Jamfile build variables. These are the accumulated
184# values from any Parent Jamfiles, and will be added to any
185# Sub-Jamfile variables when a rule picks them up.
186# File/path variables will have been normalized.
187#
188# P_ASFLAGS      - Flags for the assembler.
189# P_CCFLAGS      - Flags for the C compiler.
190# P_C++FLAGS     - Flags for the C++ compiler.
191# P_LINKFLAGS    - Flags for the executable linker.
192# P_SHLINKFLAGS  - Flags for the shared library linker.
193# P_HDRS         - Complile header search directories
194# P_DEFINES      - Compile defines
195# P_LINKOBJS     - Link extra objects
196# P_LINKLIBS     - Link extra libraries
197# P_LINKSHLIBS   - Link extra shared libraries
198# P_SHLINKOBJS     - ShLibrary Linker extra objects
199# P_SHLINKLIBS     - ShLibrary Linker extra libraries
200# P_SHLINKSHLIBS   - ShLibrary Linker extra shared libraries
201#
202# Pre-defined values
203#
204# Pre-packaged flags that conceal platform dependence,
205# and are used to set CCFLAGS/C++FLAGS/LINKFLAGS/SHLINLFLAGS etc.
206#
207#	CCOPTFLAG       - CC/C++ flag for optimization
208#	CCDEBUGFLAG     - CC/C++ flag for debug
209#	CCPROFFLAG	    - CC/C++ flag for performance profiling
210#	CCSHOBJFLAG     - CC/C++ flag for compiling for a shared library (UNIX)
211#
212#	LINKOPTFLAG		- LINK flag for optimization of the binary/shared library
213#	LINKDEBUGFLAG	- LINK flag to support debugging
214#	LINKPROFFLAG	- LINK flag to support performance profiling
215#	LINKSTRIPFLAG	- LINK flag to strip binary of any symbols
216#
217# Location variables:
218#
219# DSTDIR	- puts all products in a subdirectory of their nominated location.
220#             Useful for storing variants in their own areas.
221#
222# SRCDIR    - Looks for all sources and Jamfiles in an alternate top level source
223#             location. Useful for accessing a read only source repository, or
224#             building a variant without copying all the sources.
225#             Note that at least the project Jamtop must be in the location
226#             that is the target for the build, and will most likely be where
227#             SRCDIR is set. SRCDIR is the location of the sources relative
228#             to where it is declared.
229#             (Not currently useful for a shadow build repository where the source
230#              is spread between the SRCDIR and the build dir, because Jam 2.5 fails
231#              to look at SEARCH if LOCATE is set).
232#
233# =========================================================================
234# ArgyllCMS Normalize mods:
235#
236# The main change is to locate and identify targets using their nominated location in the
237# filesystem. This eliminates the need to create Grist, or manipulate SEARCH, LOCATE etc.
238# when setting up a herachy of Jamfiles.
239#
240# Whenever a path is provided as an argument to one of the public rules, its path is assumed
241# to be relative to the Jamfile that it is declared in. [ The NormPaths/NormTargets rules do this. ]
242# Naturally absolute paths are not affected by this.
243# During execution this means that all files are translated to paths that are
244# in a normalized form, with either an absolute path or one that is relative to
245# the directory that Jam was involked in. For simplicity it is assumed that
246# the Jamfile contains UNIX style paths, and these are converted to the
247# platform specific form on normalization.
248#
249# For a target, the normalized directory is then stripped from the name and
250# set as the Grist (path elements separated by !), and also set in the NOMLOC,
251# LOCATE and SEARCH variables "on" the target.  This gives a target a unique
252# identity for the whole of the build, determined by its nominated file system location.
253# The NOMLOC variable is a way of recovering it's location without having the reverse
254# the Grist strings.  The actual location of the target can then be varied by
255# augmenting it's LOCATE and/or SEARCH variables.
256#
257# Any include file discovered by header scanning is searched for using the
258# search path that is expected to be used during compilation, and
259# its nominated location resolved this way. Any headers that are not
260# located this way or who's location isn't declared by another rule (the
261# latter being typical when headers are being generated) will be marked as
262# being in an __unknown__ directory and will not be scaned. Normally any
263# header files located in the STDHDRS directories will not be scanned either.
264#
265# [ Typically headers will be __unknown__ if the STDHDRS directories do
266#   not reflect the default paths actually searched by the compiler, or if a
267#   header is not actually going to be #included because it is protected
268#   by an #ifdef. ]
269
270# Argyll Jambase internal implementation rules:
271
272# IDs = _TargetIDs targpaths ;				return target ID's (gristed) from normalized paths
273# path = DeNormTargs target ;				return the original path
274# CopyTarget dest : source ; 				duplicate a targets on NOMLOC LOCATE SEARCH variables.
275# NotTargets vars ;							ensure variables aren't treated as LOCATE etc targets
276
277# d1 d2 ... file = _SepPath path ;			separate a path into its components
278# path = _DirName d1 d2 ... ;				combine components into a path
279# d1 d2 .. = _RatPath d1 d2 .. 				rationalize a path
280# d1 d2 .. = _RootPath d1 d2 .. : p1 p2 ... re-root a path
281# paths = RatPaths paths ;					rationalize a set of paths
282# paths = RootPaths dir : paths ;			re-root a set of paths
283# targs = CreateIDstTargets targs : dir ;	create dest targets by locating targets in dir
284# paths1/paths = CatPaths path1 : paths ; 	concatenate paths separated by a /
285# found = FindToRoot starting_dir : file ;	Try and locate file from directory up to root.
286
287# FindTop ;		# Look for a default project file
288
289# DoInit ;									Do subdir initialization (done by JAMBASE)
290
291# public write/read Variables:
292#
293# TRACESTDHDRS				# Normally false, set to true to trace system path #include file dependenicies
294
295# public read only Variables:
296#
297# SUBDIR d1/d2/d3			# Current path from PWD to Jamfile
298# TOP d1/d2/d3				# Current path from PWD to the project Jamtop
299
300# internal variables
301#
302# _SUBDIR d1 d2 d3 ...		# Current path from PWD to Jamfile
303# _TOP d1 d2 d3				# Current path from PWD to the project Jamtop
304
305# - - - - - - - - - - - - - - -
306
307# NOTE:	Cross compiling support :-
308#	To fix this to support cross compilation, the setup needs to be
309#	modularised into 3 parts, making them all rules that can be re-involked:
310#	1) OS/Platform setup. System tools like copy, delete etc.
311#	2) Compiler setup. Basic compiler syntax etc.
312#	3) Target setup. Make this a rule, and allow switching
313#	   target by involking the rule. This will be simpler to
314#	   get working that per target 'on' variable (some
315#	   things are currently broken for 'on' variables, such
316#	   as library members, and it will be easier to do
317#	   things such as switch compilers.
318
319# - - - - - - - - - - - - - - -
320
321
322# Brief review of the jam language:
323#
324# Statements:
325#		rule RULE - statements to process a rule
326#		actions RULE - system commands to carry out target update
327#
328# Modifiers on actions:
329#		together - multiple instances of same rule on target get executed
330#				   once with their sources ($(>)) concatenated
331#		updated - refers to updated sources ($(>)) only
332#		ignore - ignore return status of command
333#		quietly - don't trace its execution unless verbose
334#		piecemeal - iterate command each time with a small subset of $(>)
335#		existing - refers to currently existing sources ($(>)) only
336#		bind vars - subject to binding before expanding in actions
337#
338# Special rules:
339#		Always - always build a target
340#		Depends - builds the dependency graph
341#                 NOTE: can have only one $(<), or parallel builds stuff up!!
342#                       Use FakeFile to work around the problem.
343#		Echo - blurt out targets on stdout
344#		Exit - blurt out targets and exit
345#		Includes - marks sources as headers for target (a codependency)
346#		NoCare - don't panic if the target can't be built
347#		NoUpdate - create the target if needed but never update it
348#		NotFile - ignore the timestamp of the target (it's not a file)
349#		Temporary - target need not be present if sources haven't changed
350#
351# Special variables set by jam:
352#		$(<) - targets of a rule (to the left of the :)
353#		$(>) - sources of a rule (to the right of the :)
354#		$(xxx) - true on xxx (UNIX, VMS, NT, OS2, MAC)
355#		$(OS) - name of OS - varies wildly
356#		$(JAMVERSION) - version number (2.5)
357#
358# Special variables used by jam:
359#		SEARCH - where to find something (used during binding and actions)
360#		LOCATE - where to plop something not found with SEARCH
361#		HDRRULE - rule to call to handle include files
362#		HDRSCAN - egrep regex to extract include files
363#
364# Special targets:
365#		all - default if none given on command line
366#
367
368# for perforce use -- jambase version
369
370JAMBASEDATE = 2008.03.26 ;
371
372# Initialize variables
373#
374
375# ===========================================================
376#
377# OS specific variable settings
378#
379
380if $(NT)
381{
382	MV				?= move /y ;
383	CP				?= copy ;
384	RM				?= del /f/q ;
385	RMDIR			?= rmdir /s/q ;
386	SLASH			?= \\ ;
387	SUFLIB			?= .lib ;
388	SUFSHLIB		?= .dll ;
389	SUFIMPLIB		?= .lib ;
390	SUFOBJ			?= .obj ;
391	SUFEXE			?= .exe ;
392	SUFSH			?= .bat ;
393	CCSHOBJFLAG		?= ;
394
395	if $(BCCROOT)
396	{
397		AR				?= tlib /C /P64 ;
398		CC				?= bcc32 ;
399		CCFLAGS			?= -v -w- -q -DWIN -tWR -tWM -tWC ;
400		C++				?= $(CC) ;
401		C++FLAGS		?= $(CCFLAGS) -P ;
402		LINK			?= $(CC) ;
403		LINKFLAGS		?= ;
404		STDLIBPATH		?= $(BCCROOT)\\lib ;
405		STDHDRS			?= $(BCCROOT)\\include ;
406		NOARSCAN		?= true ;
407	}
408	else if $(MingW) || $(MINGW)
409	{
410		# We need to do something about adding -Wl,-subsystem,windows
411		# if WinMain is being used ? (it defaults to console)
412
413		MINGW           ?= $(MingW) ;
414		TPFX             = "" ;
415
416		if [ GLOB $(MINGW)/bin : x86_64-w64-mingw32-gcc.exe ] {
417			MINGW64 = $(MINGW) ;
418        }
419
420		# This doesn't work on a 32 bit system because we're cross
421		# compiling and need to create build system exe's
422		# (tiff/mkversion.exe, imdi/imdi_make.exe
423		# Will using -m32 for local exe's fix this ?
424		# What is multi-lib option ???
425		if $(MINGW64) {
426			ECHO "Compiler is MingW for 64 bit target" ;
427			TARGET64     = true ;
428			TPFX         = x86_64-w64-mingw32- ;
429			MINGW64_LIB32 = $(MINGW)/mingw/lib32 ;
430		} else {
431			ECHO "Compiler is MingW for 32 bit target" ;
432		}
433
434
435		# Basic C/C++ tools
436		AR				?= $(TPFX)ar rusc ;
437		AS				?= $(TPFX)as ;
438		CC				?= $(TPFX)gcc ;
439		CCFLAGS			?= -DNT -mwin32 -pipe ;
440		C++				?= $(CC) ;
441		C++FLAGS		?= $(CCFLAGS) ;
442
443		OLELIBS			?= -loleaut32 -luuid ;
444		BASELIBS		?= -lstdc++ -lgcc -lodbc32 -lwsock32 ;
445#		WINLIBS			?= -lwinspool -lwinmm -lshell32 -lcomctl32 -lctl3d32
446#						   -lodbc32 -ladvapi32 -lodbc32 -lwsock32 -lopengl32
447#		                   -lglu32 -lshlwapi -lsetupapi ;
448		WINLIBS			?= -lshlwapi -lsetupapi -lole32 -lws2_32 -lpsapi -lversion ;
449		GUILIBS			?= -lgdi32 -lmscms ;
450
451		LINK			?= $(TPFX)g++ ;		# In case we link to C++ files
452		LINKFLAGS		?= -static ;
453		SHLINKFLAGS		?= ;
454		STDLIBS			?= -lm $(OLELIBS) $(WINLIBS) $(GUILIBS) ;
455		SHSTDLIBS		?= $(STDLIBS) ;
456
457		STDHDRS			?= $(MINGW)\\include ;
458
459		# Not sure whether linker -mconsole or -mwindow are needed ??
460
461		# Allow setting of flags, independent of compiler
462		DEFFLAG			?= -D ;
463		UNDEFFLAG		?= -U ;
464		CCOPTFLAG		?= -O3 ;
465		if $(PROCESSOR_LEVEL) = 15
466		{	# -mtune seems faster than -march !!!
467#			CCOPTFLAG	+= -mtune=pentium4 ;
468#			CCOPTFLAG	+= -mtune=prescott ;
469			CCOPTFLAG	+= -mtune=nocona ;	# portable code for Pentium4 640
470#			CCOPTFLAG	+= -march=nocona -mfpmath=sse -msse3 ; # non-portable
471
472		}
473
474		CCDEBUGFLAG		?= -g ;				# default (TABS? DWARF2 ?) format
475		CCPROFFLAG		?= -pg ;
476		LINKDEBUGFLAG	?= -g ;
477		LINKPROFFLAG	?= -pg ;
478		LINKOPTFLAG		?= -s -O ;			# Affects creating .so's ??
479		LINKSTRIPFLAG	?= -s ;
480
481		# Other tools
482		AWK				?= awk ;
483		SED				?= sed ;
484
485#		YACC			?= yacc ;
486#		YACCFLAGS		?= -d ;
487#		YACCFILES		?= y.tab ;
488
489		YACC			?= bison -y ;
490		YACCGEN			?= .c ;
491		YACCFILES		?= y.tab ;
492		YACCFLAGS		?= -d ;
493	}
494	else if $(MSVC)		#
495	{
496		ECHO "Compiler is VC++ 16 bit" ;
497		AR				?= lib /nologo ;
498		CC				?= cl /nologo ;
499		CCFLAGS			?= /D \"WIN\" ;
500		C++				?= $(CC) ;
501		C++FLAGS		?= $(CCFLAGS) ;
502		LINK			?= $(CC) ;
503		LINKFLAGS		?= ;
504		STDLIBS			?=
505							$(MSVC)\\lib\\mlibce.lib
506							$(MSVC)\\lib\\oldnames.lib
507							;
508		NOARSCAN		?= true ;
509		STDHDRS			?= $(MSVC)\\include ;
510		DEFFLAG		 	?= /D ;
511		UNDEFFLAG		?= "/u _" ;
512	}
513	else if $(TARGET_ARCH)
514	{
515		# Intel C++ compiler (ICL)
516
517		# No IA64 dir
518		local I ; I = "" ;
519
520		AR				?= lib /NOLOGO ;
521		AS				?= masm386 ;
522		CC              ?= icl /nologo ;
523		CCFLAGS			?= /DNT /MD ;		# DLL compatible build by default
524
525		C++				?= $(CC) ;
526		C++FLAGS		?= $(CCFLAGS) /GX ;		# GX enables syncronous exception handling
527		LINK			?= xilink /nologo ;
528		LINKOUTFLAG		?= /out: ;
529		LINKFLAGS       ?= ; 		# iclvars.bat [arch] sets this up
530
531		SHLINKFLAGS		?= ;
532
533		STDLIBS			?=
534						oldnames.lib
535						kernel32.lib
536						advapi32.lib
537						user32.lib
538						mscms.lib
539						gdi32.lib
540						shlwapi.lib
541						shell32.lib
542						setupapi.lib
543						ole32.lib
544						oleaut32.lib
545						ws2_32.lib
546						Wbemuuid.lib
547						;
548		SHSTDLIBS		?= $(STDLIBS) ;
549		LINKFLAG		?= ;
550		STDHDRS			?= $(ICPP_COMPILER14)\\Include ;
551		DEFFLAG		 	?= /D ;
552		UNDEFFLAG		?= /U ;
553		CCOPTFLAG		?= /O3 ;
554
555		if $(MSVCVER) = 6 {
556			CCDEBUGFLAG		?= /Od /Z7 ;		# Include debugging into in each object
557			CCPROFFLAG		?= /Od /Z7 ;
558			LINKDEBUGFLAG	?= /DEBUGTYPE:BOTH /DEBUG /PDB:NONE ;
559		} else {
560			CCDEBUGFLAG		?= /Od /Zi ;		# /Zi creates debugging database
561			CCPROFFLAG		?= /Od /Zi ;
562			LINKDEBUGFLAG	?= /DEBUG ;
563		}
564		LINKPROFFLAG	?= /PROFILE $(LINKDEBUGFLAG) ;
565		LINKOPTFLAG		?= /OPT:REF ;
566		LINKSTRIPFLAG	?= ;
567		YACC			?= bison -y ;
568		YACCGEN			?= .c ;
569		YACCFILES		?= y.tab ;
570		YACCFLAGS		?= -d ;
571	}
572	else if $(MSVCNT) || $(MSVCDIR) || $(MSVCDir) || $(VCINSTALLDIR)
573	{
574		# Visual C++ 8.0/9.0/10.0/11.0/12.0 uses VCINSTALLDIR
575		# We assume VC++ Express + XP32 SDK has been setup
576
577		if $(VCINSTALLDIR) {
578			MSVCNT		?= $(VCINSTALLDIR) ;
579		} else if $(MSVCDir) {
580			MSVCNT		?= $(MSVCDir) ;
581		} else {			# Visual C++ 6.0 uses MSVCDIR
582			MSVCNT		?= $(MSVCDIR) ;
583		}
584
585		if [ MATCH 12\\.(.*) : $(VisualStudioVersion) ] {
586			ECHO "Compiler is VC++12 32 bit" ;
587			MSVCVER     = 12 ;
588		} else if [ MATCH 11\\.(.*) : $(VisualStudioVersion) ] {
589			ECHO "Compiler is VC++11 32 bit" ;
590			MSVCVER     = 11 ;
591		} else if [ MATCH (.*)VC\\+\\+10(.*) : $(MSVCNT) ] {
592			ECHO "Compiler is VC++10 32 bit" ;
593			MSVCVER     = 10 ;
594		} else if [ MATCH (.*)VC\\+\\+9(.*) : $(MSVCNT) ] {
595			ECHO "Compiler is VC++9 32 bit" ;
596			MSVCVER     = 9 ;
597		} else if [ MATCH (.*)VC\\+\\+8(.*) : $(MSVCNT) ] {
598			ECHO "Compiler is VC++8 32 bit" ;
599			MSVCVER     = 8 ;
600		} else {
601			ECHO "Compiler is VC++6 32 bit" ;
602			MSVCVER     = 6 ;
603		}
604
605		# Add the SDK include and lib if it is present
606		if $(MSSdk) {
607			MSNTSDK ?= $(MSSdk) ;
608		} else if $(MSSDK) {
609			MSNTSDK ?= $(MSSDK) ;
610		} else if $(MSVCNT) {
611			MSNTSDK ?= $(MSVCNT) ;
612		}
613
614		# bury IA64 in the path for the SDK ???
615		# (but MSSDK already has this ?
616#		local I ; if $(CPU) = "IA64" { I = ia64\\ ; } else { I = "" ; }
617		local I ; I = "" ;
618
619		AR				?= lib /NOLOGO ;
620		AS				?= masm386 ;
621		CC				?= cl /nologo ;
622		CCFLAGS			?= /DNT /MD ;		# DLL compatible build by default
623		if $(MSVCVER) >= 8 {
624			CCFLAGS		+= /D_CRT_SECURE_NO_DEPRECATE=1
625                           /D_CRT_NONSTDC_NO_DEPRECATE=1 ;
626		}
627		C++				?= $(CC) ;
628		C++FLAGS		?= $(CCFLAGS) /GX ;		# GX enables syncronous exception handling
629		LINK			?= link /nologo ;
630		LINKOUTFLAG		?= /out: ;
631		LINKFLAGS		?= /INCREMENTAL:NO /LIBPATH:$(MSNTSDK)\\lib\\$(I) ;
632		SHLINKFLAGS		?= ;
633
634		STDLIBS			?=
635						oldnames.lib
636						kernel32.lib
637						advapi32.lib
638						user32.lib
639						mscms.lib
640						gdi32.lib
641						shlwapi.lib
642						shell32.lib
643						setupapi.lib
644						ole32.lib
645						oleaut32.lib
646						ws2_32.lib
647						Wbemuuid.lib
648						Version.lib
649						;
650		SHSTDLIBS		?= $(STDLIBS) ;
651		LINKFLAG		?= ;
652		STDHDRS			?= $(MSNTSDK)\\Include ;
653		DEFFLAG		 	?= /D ;
654		UNDEFFLAG		?= /U ;
655		CCOPTFLAG		?= /Ox ;		# MSVC9 doesn't understamd GB, G6 ?
656		if $(MSVCVER) = 6 {
657			CCDEBUGFLAG		?= /Od /Z7 ;		# Include debugging into in each object
658			CCPROFFLAG		?= /Od /Z7 ;
659			LINKDEBUGFLAG	?= /DEBUGTYPE:BOTH /DEBUG /PDB:NONE ;
660		} else {
661			CCDEBUGFLAG		?= /Od /Zi ;		# /Zi creates debugging database
662			CCPROFFLAG		?= /Od /Zi ;
663			LINKDEBUGFLAG	?= /DEBUG ;
664		}
665		LINKPROFFLAG	?= /PROFILE $(LINKDEBUGFLAG) ;
666		LINKOPTFLAG		?= /OPT:REF ;
667		LINKSTRIPFLAG	?= ;
668		YACC			?= bison -y ;
669		YACCGEN			?= .c ;
670		YACCFILES		?= y.tab ;
671		YACCFLAGS		?= -d ;
672	}
673	else
674	{
675		EXIT On NT, set BCCROOT, MINGW, MSVCDIR, MSVCNT, MSVC or VCINSTALLDIR to the root
676				of the Borland, GCC or Microsoft directories. ;
677	}
678}
679else if $(OS2)
680{
681	WATCOM			?= $(watcom) ;
682
683	if ! $(WATCOM)
684	{
685		Exit On OS2, set WATCOM to the root of the Watcom directory. ;
686	}
687
688	AR				?= wlib ;
689	BINDIR			?= \\os2\\apps ;
690	CC				?= wcc386 ;
691	CCFLAGS			?= /zq /DOS2 /I$(WATCOM)\\h ; # zq=quiet
692	C++				?= wpp386 ;
693	C++FLAGS		?= $(CCFLAGS) ;
694	CP				?= copy ;
695	DOT				?= . ;
696	DOTDOT			?= .. ;
697	LINK			?= wcl386 ;
698	LINKFLAGS		?= /zq ; # zq=quiet
699	STDLIBS			?= ;
700	MV				?= move ;
701	NOARSCAN		?= true ;
702	RM				?= del /f ;
703	SLASH			?= \\ ;
704	STDHDRS			?= $(WATCOM)\\h ;
705	SUFEXE			?= .exe ;
706	SUFSH			?= .bat ;
707	SUFLIB			?= .lib ;
708	SUFOBJ			?= .obj ;
709	DEFFLAG		 	?= /D ;
710	UNDEFFLAG		?= "/u _" ;
711
712}
713else if $(VMS)
714{
715	C++				?= cxx ;
716	C++FLAGS		?= ;
717	CC				?= cc ;
718	CCFLAGS			?= ;
719	CHMOD			?= set file/prot= ;
720	CP				?= copy/replace ;
721	CRELIB			?= true ;
722	DOT				?= [] ;
723	DOTDOT			?= [-] ;
724	EXEMODE			?= (w:e) ;
725	FILEMODE		?= (w:r) ;
726	HDRS			?= ;
727	LINK			?= link ;
728	LINKFLAGS		?= "" ;
729	STDLIBS			?= ;
730	MKDIR			?= create/dir ;
731	MV				?= rename ;
732	RM				?= delete ;
733	RUNVMS			?= mcr ;
734	SHELLMODE		?= (w:er) ;
735	SLASH			?= . ;
736	STDHDRS			?= decc$library_include ;
737	SUFEXE			?= .exe ;
738	SUFSH			?= .bat ;
739	SUFLIB			?= .olb ;
740	SUFOBJ			?= .obj ;
741
742	switch $(OS)
743	{
744		case OPENVMS : CCFLAGS ?= /stand=vaxc ;
745		case VMS	 : STDLIBS ?= sys$library:vaxcrtl.olb/lib ;
746	}
747}
748else if $(MAC)
749{
750	local OPT ;
751
752	CW		?= "{CW}" ;
753
754	MACHDRS ?=
755			"$(UMACHDRS):Universal:Interfaces:CIncludes"
756			"$(CW):MSL:MSL_C:MSL_Common:Include"
757			"$(CW):MSL:MSL_C:MSL_MacOS:Include" ;
758
759	MACLIBS ?=
760			"$(CW):MacOS Support:Universal:Libraries:StubLibraries:Interfacelib"
761			"$(CW):MacOS Support:Universal:Libraries:StubLibraries:Mathlib" ;
762
763	MPWLIBS ?=
764			"$(CW):MacOS Support:Libraries:Runtime:Libs:MSL_MPWCRuntime_PPC.lib"
765			"$(CW):MSL:MSL_C:MSL_MacOS:Lib:PPC:MSL_C_PPC_MPW.Lib" ;
766
767	MPWNLLIBS ?=
768			"$(CW):MacOS Support:Libraries:Runtime:Libs:MSL_MPWCRuntime_PPC.lib"
769			"$(CW):MSL:MSL_C:MSL_MacOS:Lib:PPC:MSL_C_PPC_MPW(NL).Lib" ;
770
771	SIOUXHDRS ?= ;
772
773	SIOUXLIBS ?=
774			"$(CW):MacOS Support:Libraries:Runtime:Libs:MSL_Runtime_PPC.lib"
775			"$(CW):MSL:MSL_C:MSL_MacOS:Lib:PPC:MSL_SIOUX_PPC.Lib"
776			"$(CW):MSL:MSL_C:MSL_MacOS:Lib:PPC:MSL_C_PPC.Lib" ;
777
778	C++				?= mwcppc ;
779	C++FLAGS		?= -w off ;
780	CC				?= mwcppc ;
781	CCFLAGS			?= -w off ;
782	CP				?= duplicate -y ;
783	DOT				?= ":" ;
784	DOTDOT			?= "::" ;
785	HDRS			?= $(MACHDRS) $(MPWHDRS) ;
786	LINK			?= mwlinkppc ;
787	LINKFLAGS		?= -mpwtool -warn ;
788	STDLIBS			?= $(MACLIBS) $(MPWLIBS) ;
789	SHSTDLIBS		?= $(STDLIBS) ;
790	MKDIR			?= newfolder ;
791	MV				?= rename -y ;
792	NOARSCAN		?= true ;
793	RM				?= delete -y ;
794	SLASH			?= ":" ;
795	STDHDRS			?= ;
796	SUFLIB			?= .lib ;
797	SUFOBJ			?= .o ;
798}
799else if $(OS) = BEOS && $(OSPLAT) = PPC
800{
801	AR				?= mwld -xml -o ;
802	BINDIR			?= /boot/home/config/bin ;
803	CC				?= mwcc ;
804	CCFLAGS			?= -nosyspath ;
805	C++				?= $(CC) ;
806	C++FLAGS		?= -nosyspath ;
807	CHMOD			?= chmod ;
808	CHGRP			?= chgrp ;
809	CHOWN			?= chown ;
810	FORTRAN			?= "" ;
811	LEX				?= flex ;
812	LIBDIR			?= /boot/home/config/lib ;
813	LINK			?= mwld ;
814	LINKFLAGS		?= "" ;
815	MANDIR			?= /boot/home/config/man ;
816	NOARSCAN		?= true ;
817	RANLIB			?= ranlib ;
818	STDHDRS			?= /boot/develop/headers/posix ;
819	YACC			?= bison -y ;
820	YACCGEN			?= .c ;
821	YACCFILES		?= y.tab ;
822	YACCFLAGS		?= -d ;
823}
824else if $(OS) = BEOS
825{
826	BINDIR			?= /boot/home/config/bin ;
827	CC				?= gcc ;
828	C++				?= $(CC) ;
829	CHMOD			?= chmod ;
830	CHGRP			?= chgrp ;
831	CHOWN			?= chown ;
832	FORTRAN			?= "" ;
833	LEX				?= flex ;
834	LIBDIR			?= /boot/home/config/lib ;
835	LINK			?= gcc ;
836	MANDIR			?= /boot/home/config/man ;
837	NOARSCAN		?= true ;
838	RANLIB			?= ranlib ;
839	STDHDRS			?= /boot/develop/headers/posix ;
840	YACC			?= bison -y ;
841	YACCGEN			?= .c ;
842	YACCFILES		?= y.tab ;
843	YACCFLAGS		?= -d ;
844}
845else if $(UNIX)
846{
847	switch $(OS)
848	{
849	case AIX :
850		STDLIBS			?= -lbsd ;
851
852	case AMIGA :
853		CC				?= gcc ;
854		YACC			?= bison -y ;
855
856	case CYGWIN :
857		CC				?= gcc ;
858		CCFLAGS			+= -D__cygwin__ ;
859		LEX				?= flex ;
860		JAMSHELL		?= sh -c ;
861		RANLIB			?= "" ;
862		SUFEXE			?= .exe ;
863		YACC			?= bison -y ;
864
865	case DGUX :
866		RANLIB			?= "" ;
867		RELOCATE		?= true ;
868
869	case HPUX :
870		RANLIB			?= "" ;
871
872	case INTERIX :
873		CC				?= gcc ;
874		JAMSHELL		?= sh -c ;
875		RANLIB			?= "" ;
876
877	case IRIX :
878		RANLIB			?= "" ;
879
880	case MPEIX :
881		CC				?= gcc ;
882		C++				?= gcc ;
883		CCFLAGS			+= -D_POSIX_SOURCE ;
884		HDRS			+= /usr/include ;
885		RANLIB			?= "" ;
886		NOARSCAN		?= true ;
887		NOARUPDATE		?= true ;
888
889	case MVS :
890		RANLIB			?= "" ;
891
892	case NEXT :
893		AR				?= libtool -o ;
894		RANLIB			?= "" ;
895
896	case MACOSX :
897#		AR			  	?= libtool -o ;
898		AR			  	?= ar rusc ;
899		C++				?= c++ ;
900		MANDIR			?= /usr/local/share/man ;
901		RANLIB		  	?= "" ;
902		SUFSHLIB		?= .dylib ;
903		SUFIMPLIB		?= .dylib ;
904
905	case NCR :
906		RANLIB			?= "" ;
907
908	case PTX :
909		RANLIB			?= "" ;
910
911	case QNX :
912		AR				?= wlib ;
913		CC				?= cc ;
914		CCFLAGS			?= -Q ;		# quiet
915		C++				?= $(CC) ;
916		C++FLAGS		?= -Q ;		# quiet
917		LINK			?= $(CC) ;
918		LINKFLAGS		?= -Q ;		# quiet
919		NOARSCAN		?= true ;
920		RANLIB			?= "" ;
921
922	case SCO :
923		RANLIB			?= "" ;
924		RELOCATE		?= true ;
925
926	case SINIX :
927		RANLIB			?= "" ;
928
929	case SOLARIS :
930		RANLIB			?= "" ;
931		AR				?= "/usr/ccs/bin/ar ru" ;
932
933	case UNICOS :
934		NOARSCAN		?= true ;
935		CCOPTFLAG		?= -O0 ;
936
937	case UNIXWARE :
938		RANLIB			?= "" ;
939		RELOCATE		?= true ;
940	}
941
942	# UNIX defaults
943
944	CCFLAGS			?= -DUNIX -D__FreeBSD__ -D_THREAD_SAFE -pipe -DZ_HAVE_UNISTD_H ;
945	CCOPTFLAG		?= -O2 ;
946	CCDEBUGFLAG		?= -g ;
947	CCPROFFLAG		?= ;
948	CCSHOBJFLAG		?= -fPIC ;			# Position independent is better for ShLibrary
949	C++FLAGS		?= $(CCFLAGS) ;
950	CHMOD			?= chmod ;
951	CHGRP			?= chgrp ;
952	CHOWN			?= chown ;
953	LEX				?= lex ;
954	LINKFLAGS		?= ;
955	LINKOPTFLAG		?= -O ;				# Affects creating .so's
956	LINKSTRIPFLAG	?= -s ;
957	LINKDEBUGFLAG	?= ;
958	LINKPROFFLAG	?= ;
959	SHLINKFLAGS		?= ;					# Flags for creation of shared library
960	STDLIBS			?= -lm -lpthread ;
961	SHSTDLIBS		?= $(STDLIBS) ;
962	LINKFLAG		?= -l ;
963	RANLIB			?= "" ;
964	YACC			?= yacc ;
965	YACCGEN			?= .c ;
966	YACCFILES		?= y.tab ;
967	YACCFLAGS		?= -d ;
968
969	HDRS			?= $(LOCALBASE)/include ;
970
971	# Add some good defaults for OS X
972	if $(OS) = MACOSX {
973		CCFLAGS   		+= -Wno-sign-compare ;		# supress new gcc4 warnings ?
974		CCFLAGS   		+= -fpascal-strings ;		# for compatibility with the OSX API
975		LINKFLAGS 		+= -framework Carbon ;		# default for .c
976		LINKFLAGS       += -framework Cocoa ;		# default for .m
977	}
978
979	# Make things work on 64 bit Linux
980	# Because HOSTTYPE is not normally exported, check the uname() result
981	if ! $(HOSTTYPE) {
982		HOSTTYPE = $(JAMUNAME[1]) ;
983	}
984
985	if $(HOSTTYPE) = x86_64
986	 || $(HOSTTYPE) = x86_64-linux
987	 || $(HOSTTYPE) = amd64 {
988		ECHO "We're on a 64 bit host" ;
989		HOST64     = true ;
990		CCFLAGS	   += -m64 ;
991		C++FLAGS   += -m64 ;
992	}
993
994	# Adding --hash-style=sysv to the compiler options
995	# might improve Linux compatibility with FC5 ?
996}
997
998#
999# General defaults; a lot like UNIX
1000#
1001
1002	if ! $(AR) {
1003		AR		= ar rusc ;
1004	} else {
1005		AR		+= rusc ;
1006	}
1007	AS				?= as ;
1008	ASFLAGS			?= ;
1009	AWK				?= awk ;
1010	BINDIR			?= /usr/local/bin ;
1011	C++				?= cc ;
1012	C++FLAGS		?= ;
1013	CC				?= cc ;
1014	CCFLAGS			?= ;
1015	CP				?= cp -f ;
1016	CRELIB			?= ;
1017	DOT				?= . ;
1018	DOTDOT			?= .. ;
1019	EXEMODE			?= 755 ;
1020	FILEMODE		?= 644 ;
1021	FORTRAN			?= f77 ;
1022	FORTRANFLAGS	?= ;
1023	HDRS			?= ;
1024	INSTALLGRIST	?= installed ;
1025	JAMFILE			?= Jamfile ;
1026	JAMTOP			?= Jamtop ;
1027	LEX				?= ;
1028	LIBDIR			?= /usr/local/lib ;
1029	LINK			?= $(CC) ;
1030	LINKFLAGS		?= ;
1031	SHLINKFLAGS		?= ;
1032	STDLIBS			?= ;
1033	SHSTDLIBS		?= $(STDLIBS) ;
1034	LINKOUTFLAG	 	?= "-o " ;
1035	LN				?= ln ;
1036	MANDIR			?= /usr/local/man ;
1037	MKDIR			?= mkdir ;
1038	MV				?= mv -f ;
1039	RCP				?= rcp ;
1040	RM				?= rm -f ;
1041	RMDIR			?= $(RM) ;
1042	RSH				?= rsh ;
1043	SED				?= sed ;
1044	SHELLHEADER		?= "#!/bin/sh" ;
1045	SHELLMODE		?= 755 ;
1046	SLASH			?= / ;
1047	STDHDRS			?= /usr/include ;
1048	SUFEXE			?= "" ;
1049	SUFSH			?= .sh ;
1050	SUFLIB			?= .a ;
1051	SUFSHLIB		?= .so ;
1052	SUFIMPLIB		?= .so ;
1053	SUFOBJ			?= .o ;
1054
1055	DEFFLAG		 	?= -D ;
1056	UNDEFFLAG		?= -U ;
1057	YACC			?= ;
1058	YACCGEN			?= ;
1059	YACCFILES		?= ;
1060	YACCFLAGS		?= ;
1061
1062	HDRPATTERN =
1063				"^[		 ]*#[		 ]*include[		 ]*[<\"]([^\">]*)[\">].*$" ;
1064
1065	OSFULL = $(OS)$(OSVER)$(OSPLAT) $(OS)$(OSPLAT) $(OS)$(OSVER) $(OS) ;
1066
1067
1068# ===========================================================
1069
1070#
1071# Base dependencies - first for "bootstrap" kinds of rules
1072#
1073
1074Depends all : shell files lib exe obj ;
1075Depends all shell files lib exe obj install : first ;
1076NotFile all first shell files lib exe obj dirs clean install uninstall ;
1077Always clean uninstall ;
1078
1079# ===========================================================
1080# ArgyllCMS Jambase building blocks:
1081
1082# Allow returning of a targets "on" variable
1083# Only the first variable in the list "on" variable is retrieved
1084# ret = geton target : variable ;
1085rule noop { return $(<) ; }
1086rule geton {
1087	local _rv ;
1088	_rv = [ on $(<[1]) noop $($(>)) ] ;
1089	return $(_rv) ;
1090}
1091
1092# Separate a single path into it's components, irrespective of
1093# whether a MSWindows or UNIX path separator is used.
1094# d1 d2 ... file = _SepPath path ;
1095rule _SepPath
1096{
1097#Echo "_SepPath called with = '" $(<[1]) "'" ;
1098
1099	local _in = /$(<[1]) ;		# leading / is to detect absolute path
1100	local split  = true ;
1101	local _out = ;
1102
1103	if ! $(<) {
1104#Echo "_SepPath returning '" "" "'" ;
1105		return $(<) ;
1106	}
1107
1108	split = [ MATCH (.*)[/\\](.*) : $(_in) ] ;
1109	while $(split) {
1110#Echo "Split = '" $(split[1]) "' and '" $(split[2]) "'" ;
1111		_out = $(split[2]) $(_out) ;
1112		_in = $(split[1]) ;
1113		split = [ MATCH (.*)[/\\](.*) : $(_in) ] ;
1114	}
1115#Echo "After slplitting got '" $(_in) "' out '" $(_out) "'" ;
1116
1117	if $(_in) != ""  {		# No leading /
1118#Echo "Setting _out to '" $(_in) "' plus '" $(_out) "'" ;
1119		_out = $(_in) $(_out) ;
1120	}
1121
1122#Echo "_SepPath initial sep =" $(_out) ;
1123
1124	# Deal with DOS drive letters
1125	if $(NT) {
1126		switch $(_out[1]) {
1127			case *:* : {
1128				split = [ MATCH (.*)[:](.*) : $(_out[1]) ] ;
1129				if $(split[2]) != "" {
1130					_out = $(split[1]): $(split[2]) $(_out[2-]) ;
1131				} else {
1132					_out = $(split[1]): $(SLASH) $(_out[2-]) ;
1133				}
1134			}
1135		}
1136#Echo "_SepPath after DOS letters _out =" $(_out) ;
1137	}
1138
1139	# Make sure leading / is in the correct form
1140	if $(_out[1]) = "/" || $(_out[1]) = "\\" {
1141		_out = $(SLASH) $(_out[2-]) ;
1142	}
1143
1144#Echo "_SepPath returning _out =" $(_out) ;
1145
1146	return $(_out) ;
1147}
1148
1149# Turn a sequence of directories into a directory path.
1150# Opposite of _SepPath
1151# path = _DirName d1 d2 ... ;
1152rule _DirName
1153{
1154	local _in = $(<) ;
1155	local _out = "" ;
1156
1157#Echo "_DirName got '" $(_in) "'" ;
1158
1159	# Deal with DOS drive letters
1160	if $(NT) {
1161		switch $(_in[1]) {
1162			case *:* : {
1163#Echo "_DirName match x:" ;
1164				_out = $(_in[1]) ;
1165				_in = $(_in[2-]) ;
1166			}
1167		}
1168#Echo "_DirName _in = '" $(_in) "' out = '" $(_out) "'" ;
1169	}
1170
1171	# Deal with absolute path
1172	if $(_in[1]) = "/" || $(_in[1]) = "\\" {
1173		_out = $(_out)$(SLASH) ;
1174		_in = $(_in[2-]) ;
1175#Echo "_DirName abs in = '" $(_in) "' out = '" $(_out) "'" ;
1176	}
1177
1178	while $(_in) {
1179		_out = $(_out)$(_in[1]) ;
1180		_in = $(_in[2-]) ;
1181#Echo "_DirName in = '" $(_in) "' out = '" $(_out) "'" ;
1182		if $(_in) {
1183			_out = $(_out)$(SLASH) ;
1184		}
1185#Echo "_DirName sep in = '" $(_in) "' out = '" $(_out) "'" ;
1186	}
1187
1188#Echo "_DirName returning '" $(_out) "'" ;
1189	return $(_out) ;
1190}
1191
1192# Rationalize a path (ie. cancell dirs & .. )
1193# Currently paths that cancel out return " ".
1194# d1 d2 .. file = _RatPath d1 d2 .. file ;
1195rule _RatPath
1196{
1197	local _in = $(<) ;
1198	local _rio = ;		# reversed intermediate output
1199	local _out = ;
1200	local _gotdot = ;	# There was a dot in the input path
1201	local _first = ;	# Fixed first elements
1202
1203#Echo "_RatPath called with '" $(_in) "'" ;
1204
1205	# Deal with DOS drive letters
1206	if $(NT) {
1207		switch $(_in[1]) {
1208			case *:* : {
1209				_first = $(_first) $(_in[1]) ;
1210				_in = $(_in[2-]) ;
1211			}
1212		}
1213#Echo "_RatPath got first '" $(_first) "' in = '" $(_in) "'" ;
1214	}
1215
1216	# Deal with absolute path or single dot
1217	if $(_in[1]) = / || $(_in[1]) = \\ {
1218		_first = $(_first) $(SLASH) ;
1219		_in = $(_in[2-]) ;
1220#Echo "_RatPath got first '" $(_first) "' in = '" $(_in) "'" ;
1221	} else {
1222		if $(_in[1]) = $(DOT) && ! $(_in[2-]) {
1223			_first = $(_first) $(DOT) ;
1224			_in = $(_in[2-]) ;
1225#Echo "_RatPath got first '" $(_first) "' in = '" $(_in) "'" ;
1226		}
1227	}
1228	while $(_in) {
1229#Echo "Next = " $(_in[1]) " and last = " $(_rio[1]) ;
1230		if $(_in[1]) = $(DOT) {
1231			_gotdot = true ;
1232		}
1233		# if the .. will cancel out the previous directory
1234		if $(_in[1]) = $(DOTDOT) && $(_rio[1]) && $(_rio[1] != $(DOTDOT)  {
1235			_rio = $(_rio[2-]) ;		# Remove previous
1236#Echo "Found .. so removed previous and got _rio = " $(_rio) ;
1237		} else {						# Add next
1238			# If we're decending with a directory
1239			if $(_in[1]) != $(DOT) {
1240				_rio = $(_in[1]) $(_rio) ;
1241#Echo "Adding so _rio = " $(_rio) ;
1242			} else {
1243#Echo "Found . so ignoring got _rio = " $(_rio) ;
1244			}
1245		}
1246		_in = $(_in[2-]) ;
1247	}
1248	# Make sure that a single dot is preserved
1249	if $(_gotdot) && ! $(_rio) {
1250		_rio = $(DOT) ;
1251	}
1252#Echo "Final _rio = " $(_rio) ;
1253	# Reverse it
1254	for _i in $(_rio) {
1255		_out = $(_i) $(_out) ;
1256	}
1257
1258	# Preprent with first */
1259	_out = $(_first) $(_out) ;
1260
1261#Echo "_RatPath rationalized to '" $(_out) "'" ;
1262#Echo ;
1263
1264	return $(_out) ;
1265}
1266
1267# Re-root a directory path by pre-pending the given path.
1268# Don't do this if the path is absolute
1269# Don't return anything if the path is empty.
1270# p1 p2 .. file = _RootPath d1 d2 .. : p1 p2 ... file ;
1271rule _RootPath
1272{
1273	local _i _out = ;
1274
1275#Echo "_RootPath called with '" $(<) "' and '" $(>) "'" ;
1276
1277	if ! $(>[1]) {
1278#Echo "_RootPath no RHS returning '" $(<) "'" ;
1279		return $(<) ;
1280	}
1281
1282	if $(>[1]) = "/" || $(>[1]) = "\\" {
1283#Echo "_RootPath RHS = / returning '" $(<) "'" ;
1284		return $(>) ;
1285	}
1286	if $(NT) {
1287		switch $(>[1]) {
1288			case *:* : {
1289#Echo "_RootPath RHS = drive: returning '" $(<) "'" ;
1290				return $(>) ;
1291			}
1292		}
1293	}
1294
1295#Echo "_RootPath returning '" $(<) $(>) "'" ;
1296	return $(<) $(>) ;
1297
1298}
1299
1300# Re-root a set of directory paths by pre-pending the given path.
1301# Don't do this if the path is absolute
1302# Don't return anything if the path is empty.
1303# paths = RootPaths dir : paths ;
1304rule RootPaths
1305{
1306	local _d = [ _SepPath $(<[1]) ] ;
1307	local _i _t ;
1308	local _out = ;
1309
1310#Echo "RootPaths got dir '" $(<[1]) "' and paths '" $(>) "'" ;
1311	for _i in $(>)
1312	{
1313		_t =    [ _SepPath $(_i) ] ;
1314		_t =    [ _RootPath $(_d) : $(_t) ] ;
1315		_t =    [ _RatPath $(_t) ] ;
1316		_out += [ _DirName $(_t) ] ;
1317	}
1318
1319#Echo "RootPaths returns to '" $(_out) "'" ;
1320
1321	return $(_out) ;
1322}
1323
1324# - - - - - - - - - - - - - -
1325
1326# Rationalize a set of paths (ie. cancell dirs & .. )
1327# paths = RatPaths paths ;
1328rule RatPaths
1329{
1330	local _i _t ;
1331	local _out = ;
1332
1333#Echo "RatPaths got '" $(<) "'" ;
1334	for _i in $(<)
1335	{
1336		_t =    [ _SepPath $(_i) ] ;
1337		_t =    [ _RatPath $(_t) ] ;
1338		_out += [ _DirName $(_t) ] ;
1339	}
1340
1341#Echo "RatPaths returns to '" $(_out) "'" ;
1342
1343	return $(_out) ;
1344}
1345
1346# Normalize a set of paths. This resolves the
1347# paths location with respect to SUBDIR, and so
1348# accounting for the location of the Jamfile
1349# the path is declared, and rationalizes the result.
1350# If the optional dir is present, use it to
1351# locate their targets rather than SUBDIR.
1352# If paths is empty, nothing is returned.
1353# SRCDIR and DSTDIR are ignored.
1354# paths = NormPaths paths : [ dir ] ;
1355rule NormPaths
1356{
1357	return [ _NormPaths $(<) : $(>) : "none" ] ;
1358}
1359
1360# Normalize a set of Source paths. This resolves the
1361# paths location with respect to SUBDIR, and so
1362# accounting for the location of the Jamfile
1363# the path is declared, and rationalizes the result.
1364# If the optional dir is present, use it to
1365# locate thie targets rather than SUBDIR.
1366# If paths is empty, nothing is returned.
1367# paths = NormPaths paths : [ dir ] ;
1368rule NormSrcPaths
1369{
1370	return [ _NormPaths $(<) : $(>) : "src" ] ;
1371}
1372
1373# Normalize a set of destination paths. This resolves the
1374# paths location with respect to SUBDIR, and so
1375# accounting for the location of the Jamfile
1376# the path is declared, and rationalizes the result.
1377# If the optional dir is present, use it to
1378# locate thie targets rather than SUBDIR.
1379# If paths is empty, nothing is returned.
1380# paths = NormPaths paths : [ dir ] ;
1381rule NormDstPaths
1382{
1383	return [ _NormPaths $(<) : $(>) : "dst" ] ;
1384}
1385
1386# Normalize a set of paths. This resolves the
1387# paths location with respect to SUBDIR, and so
1388# accounting for the location of the Jamfile
1389# the path is declared, and rationalizes the result.
1390# If the optional dir is present, use it to
1391# locate thie targets rather than SUBDIR.
1392# If paths is empty, nothing is returned.
1393# paths = NormPaths paths : dir : type ;
1394# (This and the other rules it calls, is probably a good candidate for speed optimization!)
1395#
1396#  ~~~~~ This isn't working correctly -
1397#  i.e. given "." where . = ccast and "../ccast",
1398#  it still returns "../ccast".
1399rule _NormPaths
1400{
1401	local _p _i _t ;
1402	local _out = ;
1403	local _src _dst ;
1404
1405	if $(>) {
1406		_p = [ _SepPath $(>[1]) ] ;
1407		_p = [ _RatPath $(_p) ] ;
1408	} else {
1409		_p = $(_SUBDIR) ;
1410	}
1411
1412	_src = [ _SepPath $(SRCDIR) ] ;
1413	_dst = [ _SepPath $(DSTDIR) ] ;
1414
1415#Echo "_NormPaths got '" $(<) "' dir '" $(_p) "' type '" $(3) "'srcdir "' $(_src) "' dstdir '" $(_dst) "'" ;
1416	for _i in $(<)
1417	{
1418#Echo "_i = '" $(_i) "'" ;
1419		_t =    [ _SepPath $(_i) ] ;
1420#Echo "_SepPath _i = '" $(_t) "'" ;
1421		_t =    [ _RootPath $(_p) : $(_t) ] ;
1422#Echo "_RootPath _t = '" $(_t) "'" ;
1423
1424		if $(_src) && $(3) = "src" {
1425			_t = [ _RootPath $(_src) : $(_t) ] ;
1426#Echo "_src += _t = '" $(_i) "'" ;
1427
1428		} else if $(_dst) && $(3) = "dst" {
1429			local _f ;
1430			_t = [ _DirName $(_t) ] ;
1431			_f = [ _SepPath $(_t:BS) ] ;
1432			_t = $(_t:D) ;
1433			if ! $(_t) {
1434				_t = $(DOT) ;
1435			}
1436			_t = [ _RootPath [ _SepPath $(_t) ] : $(_dst) ] $(_f) ;
1437#Echo " _t += _dst = '" $(_t) "'" ;
1438		}
1439		_t = [ _RatPath $(_t) ] ;
1440#Echo "_RatPath _t = '" $(_t) "'" ;
1441		# Special case of complete cancelation that can occure for a pure
1442		# directory path (?)
1443		if $(_t) = "" {
1444			_t = "." ;
1445		}
1446		_t = [ _DirName $(_t) ] ;
1447		_out += $(_t) ;
1448#Echo "_out += '" $(_t) "'" ;
1449	}
1450
1451#Echo "_NormPaths returns '" $(_out) "'" ;
1452	return $(_out) ;
1453}
1454
1455# Normalize a set of targets.
1456# This is the same as NormPaths except it
1457# then strips the path out and uses it to set the
1458# Grist, NOMLOC, LOCATE and SEARCH on the target.
1459# If the optional dir is present, use it to
1460# locate the targets rather than SUBDIR.
1461# Ignore SRCDIR if present.
1462# paths = NormTargets paths [ : dir ] ;
1463rule NormISrcTargets
1464{
1465	return [ _NormTargets $(<) : $(>) : "isrc" ] ;
1466}
1467
1468# Normalize a set of targets.
1469# This is the same as NormPaths except it
1470# then strips the path out and uses it to set the
1471# Grist, NOMLOC, LOCATE and SEARCH on the target.
1472# If the optional dir is present, use it to
1473# locate the targets rather than SUBDIR.
1474# se DSTDIR if present.
1475# paths = NormTargets paths [ : dir ] ;
1476rule NormIDstTargets
1477{
1478	return [ _NormTargets $(<) : $(>) : "idst" ] ;
1479}
1480
1481# Normalize a set of targets.
1482# This is the same as NormPaths except it
1483# then strips the path out and uses it to set the
1484# Grist, NOMLOC, LOCATE and SEARCH on the target.
1485# If the optional dir is present, use it to
1486# locate the targets rather than SUBDIR.
1487# Use SRCDIR if present.
1488# paths = NormTargets paths [ : dir ] ;
1489rule NormSrcTargets
1490{
1491	return [ _NormTargets $(<) : $(>) : "src" ] ;
1492}
1493
1494# Normalize a set of targets.
1495# This is the same as NormPaths except it
1496# then strips the path out and uses it to set the
1497# Grist, NOMLOC, LOCATE and SEARCH on the target.
1498# If the optional dir is present, use it to
1499# locate the targets rather than SUBDIR.
1500# Use DSTDIR if present.
1501# paths = NormTargets paths [ : dir ] ;
1502rule NormDstTargets
1503{
1504	return [ _NormTargets $(<) : $(>) : "dst" ] ;
1505}
1506
1507# Normalize a set of targets.
1508# This is the same as NormPaths except it
1509# then strips the path out and uses it to set the
1510# Grist, NOMLOC, LOCATE and SEARCH on the target.
1511# If the optional dir is present, use it to
1512# locate the targets rather than SUBDIR.
1513# paths = NormTargets paths : dir : type ;
1514rule _NormTargets
1515{
1516	local _p _i _t _d _ds ;
1517	local _out = ;
1518	local _src _dst ;
1519
1520	if $(>) {
1521		_p = [ _SepPath $(>[1]) ] ;
1522	} else {
1523		_p = $(_SUBDIR) ;
1524	}
1525
1526	if $(3) = "src" || $(3) = "dst" {
1527		_src = [ _SepPath $(SRCDIR) ] ;
1528		_dst = [ _SepPath $(DSTDIR) ] ;
1529	}
1530
1531#Echo ;
1532#Echo "_NormTargets got '" $(<) "' base = '" $(_p) "' type '" $(3) "' srcdir = '" $(_src) "' dstdirr = '" $(_dst) "'" ;
1533	for _i in $(<)
1534	{
1535		_t = [ _SepPath $(_i) ] ;
1536#Echo " _t = '" $(_t) "'" ;
1537		_t = [ _RootPath $(_p) : $(_t) ] ;
1538#Echo " _t = '" $(_t) "'" ;
1539		_t = [ _RatPath $(_t) ] ;
1540#Echo " _t = '" $(_t) "'" ;
1541		_t = [ _DirName $(_t) ] ;
1542#Echo " _t = '" $(_t) "'" ;
1543		_d = $(_t:D) ;
1544#Echo " _d = '" $(_d) "'" ;
1545		_ds = [ _SepPath $(_d) ] ;
1546#Echo " _ds = '" $(_ds) "'" ;
1547		_t = $(_t:D=) ;
1548#Echo " _t = '" $(_t) "'" ;
1549		_t = $(_t:G=$(_ds:J=!)) ;
1550#Echo " _t = '" $(_t) "'" ;
1551
1552		# dst trumps all the others
1553		if $(3) = "dst" {
1554			if $($(_t)-target) != "dst" {
1555				NOMLOC on $(_t) = $(_d) ;
1556				if $(_dst) {
1557					if ! $(_ds) {
1558						_ds = $(DOT) ;
1559					}
1560					_d = [ _DirName [ _RootPath $(_ds) : $(_dst) ] ] ;
1561				}
1562				if $(_d) = "/" || $(_d) = "\\" {	# Jam has a bug when locating in root
1563					_d = $(_d). ;
1564				}
1565				LOCATE on $(_t) = $(_d) ;
1566				$(_t)-target = "dst" ;
1567			}
1568
1569		# idst trumps src and isrc
1570		} else if $(3) = "idst" {
1571			if $($(_t)-target) != "dst" && $($(_t)-target) != "idst" {
1572				NOMLOC on $(_t) = $(_d) ;
1573				if $(_d) = "/" || $(_d) = "\\" {	# Jam has a bug when locating in root
1574					_d = $(_d). ;
1575				}
1576				LOCATE on $(_t) = $(_d) ;
1577				$(_t)-target = "idst" ;
1578			}
1579
1580		# src trumps isrc
1581		} else if $(3) = "src" {
1582			if $($(_t)-target) != "dst" && $($(_t)-target) != "idst"
1583			                            && $($(_t)-target) != "src" {
1584				local _d1 _d2 ;
1585				NOMLOC on $(_t) = $(_d) ;
1586				if $(_src) {
1587					_d1 = [ _DirName [ _RootPath $(_src) : $(_ds) ] ] ;
1588				} else {
1589					_d1 = $(_d) ;
1590				}
1591				if $(_dst) {
1592					if ! $(_ds) {
1593						_ds = $(DOT) ;
1594					}
1595					_d2 = [ _DirName [ _RootPath $(_ds) : $(_dst) ] ] ;
1596				}
1597				if $(_d1) = "/" || $(_d1) = "\\" {	# Jam has a bug when locating in root
1598					_d1 = $(_d1). ;
1599				}
1600				if $(_d2) = "/" || $(_d2) = "\\" {	# Jam has a bug when locating in root
1601					_d2 = $(_d2). ;
1602				}
1603				# We assume that if we've got a DSTDIR here, then
1604				# it may apply to this source, even if it is never
1605				# gets labelled this way. - ie. it may be a dst of a
1606				# Jamfile with the same DSTDIR that's not in scope.
1607				SEARCH on $(_t) = $(_d2) $(_d1) ;
1608				$(_t)-target = "src" ;
1609			}
1610
1611		# isrc is lowest priority
1612		} else if $(3) = "isrc" && ! $($(_t)-target) {
1613			if $(_d) = "/" || $(_d) = "\\" {	# Jam has a bug when locating in root
1614				_d = $(_d). ;
1615			}
1616			NOMLOC on $(_t) = $(_d) ;
1617			SEARCH on $(_t) = $(_d) ;
1618			$(_t)-target = "isrc" ;
1619		}
1620
1621#Echo "On '" $(_t) "' set LOCATE = '" [ geton $(_t) : LOCATE ] "' SEARCH = '" [ geton $(_t) : SEARCH ] "' NOMLOC = '" [ geton $(_t) : NOMLOC ] "'" ;
1622		_out += $(_t) ;
1623	}
1624
1625#Echo "_NormTargets returns to '" $(_out) "'" ;
1626	return $(_out) ;
1627}
1628
1629# Given a set of normalized paths, return the Target ID's for
1630# them (ie. Gristed version of path)
1631# IDs = _TargetIDs targpaths ;
1632rule _TargetIDs
1633{
1634	local _i _t _d _ds ;
1635	local _out = ;
1636
1637#Echo "_TargetIDs got '" $(<) "'" ;
1638	for _i in $(<)
1639	{
1640		_d = $(_i:D) ;
1641		_ds = [ _SepPath $(_d) ] ;
1642		_t = $(_i:D=) ;
1643		_t = $(_t:G=$(_ds:J=!)) ;
1644		_out += $(_t) ;
1645	}
1646
1647#Echo "_TargetIDs returning '" $(_out) "'" ;
1648	return $(_out) ;
1649}
1650
1651
1652# Copy the target related "on" variables from one
1653# target to another.
1654#rule CopyTarget dest : source ;
1655rule CopyTarget
1656{
1657	NOMLOC on $(<) = [ geton $(>) : NOMLOC ] ;
1658	LOCATE on $(<) = [ geton $(>) : LOCATE ] ;
1659	SEARCH on $(<) = [ geton $(>) : SEARCH ] ;
1660}
1661
1662# Make sure a non-target isn't LOCATED or SEARCH'd by
1663# setting LOCATE, SEARCH and NOMLOC to ""
1664#rule NotTargets vars ;
1665rule NotTargets
1666{
1667	NOMLOC on $(<) = "" ;
1668	LOCATE on $(<) = "" ;
1669	SEARCH on $(<) = "" ;
1670}
1671
1672# Create a destination target by locating
1673# the given files in the given directory.
1674# The dir is assumed to be normalized.
1675# SRCDIR and DSTDIR are ignored.
1676# targs = SetTargetsLoc targs : dir ;
1677rule CreateIDstTargets
1678{
1679	local _o ;
1680#Echo "CreateIDstTargets got '" $(<) "' and '" $(>) "'" ;
1681	_o = [ NormIDstTargets $(<:BS) : $(>[1]) ] ;
1682#Echo "CreateIDstTargets returning '" $(_o) "'" ;
1683	return $(_o) ;
1684}
1685
1686# Given a normalized target, return the
1687# orgiginal path to it.
1688# (We use NOMLOC to do this.)
1689# path = DeNormTargs target ;
1690rule DeNormTargs
1691{
1692	local _i _t _p _out = ;
1693
1694	for _i in $(<) {
1695		_p = [ geton $(_i) : NOMLOC ] ;
1696		_t = $(_i:G=) ;
1697		_out += $(_t:D=$(_p)) ;
1698	}
1699
1700	return $(_out) ;
1701}
1702
1703# Given a list of directories and a list of files,
1704# simply concatenate them in combination separated by a /
1705# paths1/paths = CatPaths path1 : paths ;
1706rule CatPaths
1707{
1708	return $(<)$(SLASH)$(>) ;
1709}
1710
1711# Try and locate a given file pattern starting from the current
1712# directory and working towards the root.
1713# We use a heuristic to figure out when to stop, since
1714# Jam doesn't have pwd :-(
1715# found = FindRoot starting_dir : file ;
1716rule FindToRoot
1717{
1718	local dir = $(<[1]) ;
1719	local dir_list, prev_list = ;
1720	local dir_list;
1721	local found = ;
1722
1723#Echo "FindToRoot got starting_dir '" $(<) "' file '" $(>) "'" ;
1724    found = [ GLOB $(dir) : $(>[1]) ] ;
1725
1726	if $(found) {
1727		return $(found) ;
1728	}
1729
1730#Echo "dir_list = " $(dir_list) ;
1731
1732	dir_list = [ GLOB $(dir) : * ] ;
1733	while $(dir_list:D="") != $(prev_list:D="") {
1734		dir = $(dir)$(SLASH)$(DOTDOT) ;
1735#Echo "dir = " $(dir) ;
1736	    found = [ GLOB $(dir) : $(>[1]) ] ;
1737
1738		if $(found) {
1739			return $(found) ;
1740		}
1741
1742		prev_list = $(dir_list) ;
1743		dir_list = [ GLOB $(dir) : * ] ;
1744#Echo "dir_list = " $(dir_list) ;
1745	}
1746#Echo "returning " $(found) ;
1747	return $(found) ;
1748}
1749
1750# -----------------------------------------
1751
1752rule DoInit
1753{
1754	if ! $(DONEANCHORINIT) {
1755
1756		SUBDIR ?= $(DOT) ;
1757		_SUBDIR ?= $(DOT) ;
1758
1759		# initial "parent" settings
1760		P_ASFLAGS = ;
1761		P_CCFLAGS = ;
1762		P_C++FLAGS = ;
1763		P_LINKFLAGS = ;
1764		P_SHLINKFLAGS = ;
1765		P_HDRS = ;
1766		P_DEFINES = ;
1767
1768		P_PREF_ASFLAGS = ;
1769		P_PREF_CCFLAGS = ;
1770		P_PREF_C++FLAGS = ;
1771		P_PREF_LINKFLAGS = ;
1772		P_PREF_SHLINKFLAGS = ;
1773
1774		FindTop ;		# Look for a default project file
1775
1776		TRACESTDHDRS = false ;		# don't trace system path #include file dependenicies
1777		DONEANCHORINIT = true ;
1778	}
1779}
1780
1781# Set the project top for this Jamfile and all sub Jamfiles
1782# until another top is set or we return.
1783# ProjTop d1 d2 .. ;
1784rule ProjTop
1785{
1786#Echo "ProjTop got '" $(<) "'" ;
1787
1788	_TOP = [ _RatPath $(<) ] ;
1789	TOP = [ _DirName $(_TOP) ] ;
1790
1791#Echo "ProjTop set TOP to '" $(TOP) "'" ;
1792
1793	if ! $($(TOP)-SET) {	# Not tried to read the project file
1794
1795		local found = [ GLOB $(_top) : $(JAMFILE) ] ;
1796
1797		if $(found) {
1798			local save__SUBDIR = $(_SUBDIR) ;
1799			local save__INVSUBDIR = $(_INVSUBDIR) ;
1800			local save_SUBDIR = $(SUBDIR) ;
1801
1802			_SUBDIR = $(_TOP) ;
1803			_INVSUBDIR = [ _InvertPath $(_SUBDIR) ] ;
1804			SUBDIR = [ _DirName $(_SUBDIR) ] ;
1805#Echo "_SUBDIR = '" $(_SUBDIR) "'" ;
1806#Echo "_INVSUBDIR = '" $(_INVSUBDIR) "'" ;
1807
1808			# Translate SRCDIR for new SUBDIR
1809			if $(SRCDIR) {
1810#Echo "SRCDIR olddir '" $(SRCDIR) "'" ;
1811				SRCDIR = [ _SepPath $(SRCDIR) ] ;
1812				SRCDIR = [ _RootPath $(_INVSUBDIR) : [ _RootPath $(SRCDIR) : $(_SUBDIR) ] ] ;
1813				SRCDIR = [ _DirName [ _RatPath $(SRCDIR) ] ] ;
1814#Echo "SRCDIR newdir '" $(SRCDIR) "'" ;
1815			}
1816
1817#Echo "About to include Jamtop '" $(found) "'" ;
1818			include $(found) ;
1819
1820			# Un Translate SRCDIR, in case it was set in the rules directory
1821			if $(SRCDIR) {
1822#Echo "_SUBDIR = '" $(_SUBDIR) "'" ;
1823#Echo "_INVSUBDIR = '" $(_INVSUBDIR) "'" ;
1824#Echo "SRCDIR newdir '" $(SRCDIR) "'" ;
1825				SRCDIR = [ _SepPath $(SRCDIR) ] ;
1826				SRCDIR = [ _RootPath $(_SUBDIR) : [ _RootPath $(SRCDIR) : $(_INVSUBDIR) ] ] ;
1827				SRCDIR = [ _DirName [ _RatPath $(SRCDIR) ] ] ;
1828#Echo "SRCDIR olddir '" $(SRCDIR) "'" ;
1829			}
1830
1831			# Restore things
1832			_SUBDIR = $(save__SUBDIR) ;
1833			_INVSUBDIR = $(save__INVSUBDIR) ;
1834			SUBDIR = $(save_SUBDIR) ;
1835		} else {
1836			Echo "WARNING :- no project " $(TOP) "Jamtop found" ;
1837		}
1838
1839		$(TOP)-SET = true ;
1840	}
1841}
1842
1843# Search for the project top by looking for the Jamtop
1844# starting at $(SUBDIR) and lookup upwards.
1845# FindTop ;
1846rule FindTop
1847{
1848#Echo ;
1849#Echo "FindTop called SUBDIR = '" $(SUBDIR) "'" ;
1850
1851	local _JRF = [ FindToRoot $(SUBDIR) : $(JAMTOP) ] ;
1852
1853#Echo "FindTop found '" $(_JRF) "'" ;
1854	if $(_JRF) {
1855
1856		_TOP = [ _RatPath [ _SepPath $(_JRF:D) ] ] ;
1857		TOP = [ _DirName $(_TOP) ] ;
1858#Echo "ProjTop set TOP to '" $(TOP) "'" ;
1859
1860		if ! $($(TOP)-SET) {	# Not tried to read the project file
1861			local save__SUBDIR = $(_SUBDIR) ;
1862			local save__INVSUBDIR = $(_INVSUBDIR) ;
1863			local save_SUBDIR = $(SUBDIR) ;
1864
1865			_SUBDIR = $(_TOP) ;
1866			_INVSUBDIR = [ _InvertPath $(_SUBDIR) ] ;
1867			SUBDIR = [ _DirName $(_SUBDIR) ] ;
1868#Echo "_SUBDIR = '" $(_SUBDIR) "'" ;
1869#Echo "_INVSUBDIR = '" $(_INVSUBDIR) "'" ;
1870
1871			# Translate SRCDIR for new SUBDIR
1872			if $(SRCDIR) {
1873#Echo "SRCDIR olddir '" $(SRCDIR) "'" ;
1874				SRCDIR = [ _SepPath $(SRCDIR) ] ;
1875				SRCDIR = [ _RootPath $(_INVSUBDIR) : [ _RootPath $(SRCDIR) : $(_SUBDIR) ] ] ;
1876				SRCDIR = [ _DirName [ _RatPath $(SRCDIR) ] ] ;
1877#Echo "SRCDIR newdir '" $(SRCDIR) "'" ;
1878			}
1879
1880#Echo "About to include Jamtop '" $(_JRF) "'" ;
1881			include $(_JRF) ;
1882			$(TOP)-SET = true ;
1883
1884			# Un Translate SRCDIR, in case it was set in the ruls directory
1885			if $(SRCDIR) {
1886#Echo "_SUBDIR = '" $(_SUBDIR) "'" ;
1887#Echo "_INVSUBDIR = '" $(_INVSUBDIR) "'" ;
1888#Echo "SRCDIR newdir '" $(SRCDIR) "'" ;
1889				SRCDIR = [ _SepPath $(SRCDIR) ] ;
1890				SRCDIR = [ _RootPath $(_SUBDIR) : [ _RootPath $(SRCDIR) : $(_INVSUBDIR) ] ] ;
1891				SRCDIR = [ _DirName [ _RatPath $(SRCDIR) ] ] ;
1892#Echo "SRCDIR olddir '" $(SRCDIR) "'" ;
1893			}
1894
1895			# Restore things
1896			_SUBDIR = $(save__SUBDIR) ;
1897			_INVSUBDIR = $(save__INVSUBDIR) ;
1898			SUBDIR = $(save_SUBDIR) ;
1899		}
1900	} else {
1901		Echo "WARNING :- no project Jamtop found, no TOP set !" ;
1902
1903		if ! $(TOP) {
1904			TOP = $(DOT) ;		# set a default TOP
1905			_TOP = $(DOT) ;
1906		}
1907	}
1908}
1909
1910# Given a path relative to CWD, return the inverse direction
1911# path. Return nothing if the path is absolute.
1912# [ we're using a hack here, since Jam 2.5 doesn't have
1913#   any functions that will simply resolve a path relative
1914#   to CWD into an absolute path. ]
1915# d1 d2 .. = _InvertPath d1 d2 ..
1916rule _InvertPath
1917{
1918	local _i _o _d ;
1919#Echo "_InvertPath got '" $(<) "'" ;
1920	if $(<[1]) = "/" || $(<[1]) = "\\" {
1921#Echo "_InvertPath returning nothing" ;
1922		return "" ;
1923	}
1924	if $(NT) {
1925		switch $(<[1]) {
1926			case *:* : {
1927#Echo "_InvertPath returning nothing" ;
1928				return "" ;
1929			}
1930		}
1931	}
1932
1933	for _i in $(<) {
1934#Echo "_InvertPath _i = '" $(_i) "' _o = '" $(_o) "'" ;
1935		# Ignore .
1936		if $(_i) = $(DOT) {
1937			continue ;
1938		}
1939		# The hard one. Look amongst all the
1940		# sub directories for one that has the same
1941		# contents as the directory we came from.
1942		# Too bad if two directories have the same contents...
1943		if $(_i) = $(DOTDOT) {
1944			local _j;
1945			local _d1 _d2 _l1, _l2 _l3 ;
1946
1947#Echo "_InvertPath inverting '" $(_i) "'" ;
1948
1949			_d1 = [ _DirName $(_d) ] ;
1950			_l1 = [ GLOB $(_d1) : * ] ;
1951#Echo "_d1 = '" $(_d1) "'" ;
1952			_d += $(_i) ;
1953			_d2 = [ _DirName $(_d) ] ;
1954#Echo "_d2 = '" $(_d2) "'" ;
1955			_l2 = [ GLOB $(_d2) : * ] ;
1956
1957			for _j in $(_l2) {
1958				if $(_j) = $(DOT) || $(_j) = $(DOTDOT) {
1959					continue ;
1960				}
1961#Echo "Checking _j = '" $(_j) "'" ;
1962				_l3 = [ GLOB $(_j) : * ] ;
1963#Echo "_l1 = '" $(_l1) "'" ;
1964#Echo "_l3 = '" $(_l3:BS) "'" ;
1965				if $(_l3:BS) = $(_l1) {
1966#Echo "Found reverse = '" $(_j) "'" ;
1967					_o = $(_j:BS) $(_o) ;
1968					break ;
1969				}
1970			}
1971
1972		# The easy one. the opposite of a directory
1973		# is ..
1974		} else {
1975			_o = $(DOTDOT) $(_o) ;
1976			_d += $(_i) ;
1977		}
1978	}
1979	if ! $(_o) {
1980		_o = $(DOT) ;
1981	}
1982
1983#Echo "_InvertPath returning '" $(_o) "'" ;
1984	return $(_o) ;
1985}
1986
1987# Variables containing (possible) relative paths that are to remain
1988# anchored to where they were declared. This is to prevent
1989# NormPath in a sub-Jamfile assuming they are relative to that Jamfile.
1990# (This is a bit messy. How could it be avoided ? If there were
1991#  a simple way of making paths absolute, rather than computing eveything
1992#  relative to the invokation directory, it could help.)
1993ANCHORED_PATH_VARS = ;
1994
1995# Variables to save before starting a new Jamfile, then
1996# restore once it's finished.
1997
1998SUBDIR_VARS = SUBDIR _SUBDIR TOP _TOP SRCDIR DSTDIR
1999              P_ASFLAGS P_CCFLAGS P_C++FLAGS P_LINKFLAGS P_SHLINKFLAGS
2000              ASFLAGS CCFLAGS C++FLAGS LINKFLAGS SHLINKFLAGS
2001              P_PREF_ASFLAGS P_PREF_CCFLAGS P_PREF_C++FLAGS P_PREF_LINKFLAGS
2002              PREF_ASFLAGS PREF_CCFLAGS PREF_C++FLAGS PREF_LINKFLAGS PREF_SHLINKFLAGS
2003              P_HDRS HDRS
2004              P_DEFINES DEFINES
2005              P_LINKOBJS LINKOBJS
2006              P_LINKLIBS LINKLIBS
2007              P_LINKSHLIBS LINKSHLIBS
2008              P_SHLINKOBJS SHLINKOBJS
2009              P_SHLINKLIBS SHLINKLIBS
2010              P_SHLINKSHLIBS SHLINKSHLIBS
2011              ;
2012
2013# Implement including a Jamfile from a sub or peer directory,
2014# Sub includes cause flags/headers/options to be inhereted
2015# from the calling Jamfile, while Peer includes do not.
2016# The global _JAMINCLUDE_PEER variable controls whether
2017# this is a sub or peer include.
2018# _JamInclude dir ;
2019rule _JamInclude
2020{
2021#Echo "_JamInclude called with '" $(<) "' SUBDIR '" $(SUBDIR) "' and _JAMINCLUDE_PEER '" $(_JAMINCLUDE_PEER) "'" ;
2022
2023	# Save certain variables so that sub-Jamfiles don't affect them
2024	local _jamfile ;
2025	local _SUBDIR_VARS = $(SUBDIR_VARS) $(ANCHORED_PATH_VARS) ;
2026	local _i parent_$(_SUBDIR_VARS) ;
2027
2028	for _i in $(_SUBDIR_VARS) {
2029		parent_$(_i) = $($(_i)) ;
2030	}
2031
2032	if $(_JAMINCLUDE_PEER) != "true" {
2033		# Incorporate this levels extra flags & header paths into the base
2034		P_ASFLAGS += $(ASFLAGS) ;
2035		P_CCFLAGS += $(CCFLAGS) ;
2036		P_C++FLAGS += $(C++FLAGS) ;
2037		P_LINKFLAGS += $(LINKFLAGS) ;
2038		P_SHLINKFLAGS += $(SHLINKFLAGS) ;
2039		P_HDRS = [ NormPaths $(HDRS) ] $(P_HDRS) ;
2040		P_DEFINES += $(DEFINES) ;
2041		P_LINKOBJS = [ NormPaths $(LINKOBJS) ] $(P_LINKOBJS) ;
2042		P_LINKLIBS = [ NormPaths $(LINKLIBS) ] $(P_LINKLIBS) ;
2043		P_LINKSHLIBS = [ NormPaths $(LINKSHLIBS) ] $(P_LINKSHLIBS) ;
2044		P_SHLINKOBJS = [ NormPaths $(SHLINKOBJS) ] $(P_SHLINKOBJS) ;
2045		P_SHLINKLIBS = [ NormPaths $(SHLINKLIBS) ] $(P_SHLINKLIBS) ;
2046		P_SHLINKSHLIBS = [ NormPaths $(SHLINKSHLIBS) ] $(P_SHLINKSHLIBS) ;
2047
2048		# Set parent flags no existing parent flags
2049		if ! $(P_PREF_ASFLAGS) {
2050			P_PREF_ASFLAGS = $(PREF_ASFLAGS) ; }
2051		if ! $(P_PREF_CCFLAGS) {
2052			P_PREF_CCFLAGS = $(PREF_CCFLAGS) ; }
2053		if ! $(P_PREF_C++FLAGS) {
2054			P_PREF_C++FLAGS = $(PREF_C++FLAGS) ; }
2055		if ! $(P_PREF_LINKFLAGS) {
2056			P_PREF_LINKFLAGS = $(PREF_LINKFLAGS) ; }
2057		if ! $(P_PREF_SHLINKFLAGS) {
2058			P_PREF_SHLINKFLAGS = $(PREF_SHLINKFLAGS) ; }
2059	}
2060
2061	# Set default for new Jamfile extra and preferred flags
2062	ASFLAGS = ;
2063	CCFLAGS = ;
2064	C++FLAGS = ;
2065	LINKFLAGS = ;
2066	SHLINKFLAGS = ;
2067	HDRS = ;
2068	DEFINES = ;
2069	LINKOBJS = ;
2070	LINKLIBS = ;
2071	LINKSHLIBS = ;
2072	SHLINKOBJS = ;
2073	SHLINKLIBS = ;
2074	SHLINKSHLIBS = ;
2075
2076	PREF_ASFLAGS = ;
2077	PREF_CCFLAGS = ;
2078	PREF_C++FLAGS = ;
2079	PREF_LINKFLAGS = ;
2080	PREF_SHLINKFLAGS = ;
2081
2082	_SUBDIR = [ _RatPath [ _RootPath $(_SUBDIR) : [ _SepPath $(<) ] ] ] ;
2083	_INVSUBDIR = [ _InvertPath $(_SUBDIR) ] ;
2084	SUBDIR = [ _DirName $(_SUBDIR) ] ;
2085
2086#Echo "new _SUBDIR =" $(_SUBDIR) ;
2087#Echo "new _INVSUBDIR =" $(_INVSUBDIR) ;
2088
2089	if $(_INVSUBDIR) != "." {
2090		# Keep paths relative to where they were defined, so that
2091		# NormPaths doesn't think they are relative to the sub-Jamfile.
2092#Echo "Before ANCHORED_PATH_VARS = $(ANCHORED_PATH_VARS) vals $($(ANCHORED_PATH_VARS))" ;
2093		for _i in $(ANCHORED_PATH_VARS) {
2094			$(_i) = [ RootPaths $(_INVSUBDIR) : $($(_i)) ] ;
2095		}
2096#Echo "After ANCHORED_PATH_VARS = $(ANCHORED_PATH_VARS) vals $($(ANCHORED_PATH_VARS))" ;
2097	}
2098
2099	# Translate SRCDIR for new SUBDIR
2100#Echo "SRCDIR olddir '" $(SRCDIR) "'" ;
2101	if $(SRCDIR) {
2102		local subdir = $(_SUBDIR[2-]) ;
2103		local invsubdir = [ FReverse $(_INVSUBDIR) ] ;
2104		invsubdir = [ FReverse $(invsubdir[2-]) ] ;
2105#Echo "subdir-1 =" $(subdir) ;
2106#Echo "invsubdir-1 =" $(invsubdir) ;
2107		SRCDIR = [ _SepPath $(SRCDIR) ] ;
2108		SRCDIR = [ _RootPath $(invsubdir) : [ _RootPath $(SRCDIR) : $(subdir) ] ] ;
2109		SRCDIR = [ _DirName [ _RatPath $(SRCDIR) ] ] ;
2110#Echo "SRCDIR newdir '" $(SRCDIR) "'" ;
2111	}
2112
2113	_jamfile = [ NormSrcPaths $(JAMFILE) ] ;
2114
2115#Echo "About to include " $(_jamfile) ;
2116	include $(_jamfile) ;
2117
2118	# Restore variable before returning
2119	for _i in $(_SUBDIR_VARS) {
2120		$(_i) = $(parent_$(_i)) ;
2121	}
2122
2123#Echo "Done include " $(JAMFILE:D=$(_subdir)) ;
2124#Echo "restored SUBDIR =" $(SUBDIR) ;
2125#Echo "_JamInclude done" ;
2126}
2127
2128# Invoke a Jamfile as a sub Jamfile
2129# SubInclude dir ;
2130rule SubInclude
2131{
2132#Echo "### SubInclude called with '" $(<[1]) "' and SUBDIR = '" $(SUBDIR) "'" ;
2133	_JAMINCLUDE_PEER = "false" ;	# This is a sub include
2134	return [ _JamInclude $(<) ] ;
2135}
2136
2137# Invoke a Jamfile in as a peer Jamfile
2138# PeerInclude dir ;
2139rule PeerInclude
2140{
2141#Echo "### PeerInclude called with '" $(<[1]) "' and SUBDIR = '" $(SUBDIR) "'" ;
2142	_JAMINCLUDE_PEER = "true" ;	# This is a peer include
2143	return [ _JamInclude $(<) ] ;
2144}
2145
2146# ===========================================================
2147#
2148# Rules
2149#
2150
2151# Public As
2152# As obj : source.s ;					.s -> .o
2153rule As
2154{
2155	# Normalize target names and set Grist LOCATE and SOURCE
2156	local _t = [ NormDstTargets $(<[1]:S=$(SUFOBJ)) ] ;
2157	local _s = [ NormSrcTargets $(>) ] ;
2158
2159	Depends $(_t) : $(_s) ;
2160	Depends obj : $(_t) ;
2161	MakeLocate $(_t) ;
2162
2163	HDRS on $(_t) = [ geton $(_t) : SEARCH ] [ NormPaths $(HDRS) ] $(P_HDRS) ;
2164}
2165
2166# Internal As
2167rule As_
2168{
2169	local pref_asflags = $(P_PREF_ASFLAGS) ;
2170	pref_asflags ?= $(PREF_ASFLAGS) ;
2171	ASFLAGS1 on $(<) = $(P_ASFLAGS) $(ASFLAGS) ;
2172	ASFLAGS2 on $(<) = $(pref_asflags) ;
2173	ASFLAGS on $(<) = [ geton $(<) : ASFLAGS1 ] [ geton $(<) : ASFLAGS2 ] ;
2174	ASHDRS on $(<) = [ on $(<) FIncludes $(HDRS) ] ;
2175}
2176
2177# copies sources into directory.
2178# SRCDIR and DSTDIR will be ignored.
2179# Bulk directory : sources ;
2180rule Bulk
2181{
2182#Echo "Bulk got '" $(<) "' and '" $(>) "'" ;
2183	local _d = [ NormPaths $(<) ] ; # Directory
2184	local _s = [ NormSrcTargets $(>) ] ;	# Sources
2185	local _t = [ CreateIDstTargets $(_s) : $(_d) ] ; # Relocate targs to dir
2186	local _is _it ;			# individual source and target
2187
2188	for _is in $(_s)
2189	{
2190		_it = $(_t[1]) ;
2191		_t = $(_t[2-]) ;	# Track _is
2192
2193		Depends files : $(_it) ;
2194		Depends $(_it) : $(_is) ;
2195		MakeLocate $(_it) ;
2196		File_ $(_it) : $(_is) ;
2197		MODE on $(_it) = $(FILEMODE) ;
2198		Chmod_ $(_it) ;
2199	}
2200}
2201
2202# Cc object : source : flags : defines : hdrpaths ;
2203rule Cc
2204{
2205	# Normalize target names and set Grist LOCATE and SOURCE
2206	local _t = [ NormDstTargets $(<[1]:S=$(SUFOBJ)) ] ;
2207	local _s = [ NormSrcTargets $(>[1]) ] ;
2208
2209	Depends $(_t) : $(_s) ;
2210	Depends obj : $(_t) ;
2211	Clean clean : $(_t) ;
2212	MakeLocate $(_t) ;
2213
2214	HDRS on $(_t) = [ geton $(_t) : SEARCH ] [ NormPaths $(HDRS) ] $(P_HDRS) ;
2215	SOURCE on $(_t) = $(_s) ;
2216
2217	HDRRULE on $(_s) = HdrRule ;
2218	HDRSCAN on $(_s) = $(HDRPATTERN) ;
2219	# Construct HDRSEARCH so that we can know where to look for headers
2220	local _dot = [ geton $(_>) : NOMLOC ] ;
2221	if ! $(_dot) { _dot = $(DOT) ; }
2222	HDRSEARCH1 on $(_s) = $(_dot) ;
2223	HDRSEARCH2 on $(_s) = [ NormPaths $(HDRS) ] $(P_HDRS) ;
2224	HDRSEARCH3 on $(_s) = [ NormPaths $(STDHDRS) ] ;
2225	HDRSEARCH on $(_s) = [ geton $(_s) : HDRSEARCH1 ] [ geton $(_s) : HDRSEARCH2 ]
2226	                     [ geton $(_s) : HDRSEARCH3 ] ;
2227#Echo "Cc set HDRSEARCH on '" $(_s) "' to '" [ geton $(_s) : HDRSEARCH ] "'" ;
2228
2229	# propagate target specific-defines
2230
2231	DEFINES on $(_t) = $(P_DEFINES) $(DEFINES) ;
2232
2233	Cc_ $(_t) : $(_s) : $(3) ;
2234
2235	if $(3) {
2236		ObjectCcFlags $(<) : $(3) ;
2237	}
2238	if $(4) {
2239		ObjectDefines $(<) : $(4) ;
2240	}
2241	if $(5) {
2242		ObjectHdrs $(<) : $(5) ;
2243	}
2244}
2245
2246# Internal Cc
2247# Cc_ object : sources ;
2248rule Cc_
2249{
2250	# If the compiler's -o flag doesn't work, relocate the .o
2251	if $(RELOCATE)
2252	{
2253		CcMv $(<) : $(>) ;
2254	}
2255
2256	local pref_ccflags = $(P_PREF_CCFLAGS) ;
2257	pref_ccflags ?= $(PREF_CCFLAGS) ;
2258	# Make sure we incorporate any CCFLAGS[12] on object into total
2259	CCFLAGS1 on $(<) += $(P_CCFLAGS) $(CCFLAGS) ;
2260	CCFLAGS2 on $(<) += $(pref_ccflags) ;
2261	CCFLAGS on $(<) = [ geton $(<) : CCFLAGS1 ] [ geton $(<) : CCFLAGS2 ] ;
2262
2263#Echo "Cc object '" $(<) "' got CCFLAGS1 '" [ geton $(<) : CCFLAGS1 ] "' and CCFLAGS2 '" [ geton $(<) : CCFLAGS2 ] "' for total CCFLAGS '" [ geton $(<) : CCFLAGS ] "'" ;
2264
2265	# Make sure the CCHDRS and CCDEFS are formatter correctly
2266	CCHDRS on $(<) = [ on $(<) FIncludes $(HDRS) ] ;
2267	CCDEFS on $(<) = [ on $(<) FDefines $(DEFINES) ] ;
2268}
2269
2270# C++ object : source : flags : defines : hdrpaths ;
2271rule C++
2272{
2273	# Normalize target names and set Grist LOCATE and SOURCE
2274	local _t = [ NormDstTargets $(<[1]:S=$(SUFOBJ)) ] ;
2275	local _s = [ NormSrcTargets $(>[1]) ] ;
2276
2277	Depends $(_t) : $(_s) ;
2278	Depends obj : $(_t) ;
2279	Clean clean : $(_t) ;
2280	MakeLocate $(_t) ;
2281
2282	HDRS on $(_t) = [ geton $(_t) : SEARCH ] [ NormPaths $(HDRS) ] $(P_HDRS) ;
2283	SOURCE on $(_t) = $(_s) ;
2284
2285	HDRRULE on $(_s) = HdrRule ;
2286	HDRSCAN on $(_s) = $(HDRPATTERN) ;
2287	# Construct HDRSEARCH so that we can know where to look for headers
2288	local _dot = [ geton $(_>) : NOMLOC ] ;
2289	if ! $(_dot) { _dot = $(DOT) ; }
2290	HDRSEARCH1 on $(_s) = $(_dot) ;
2291	HDRSEARCH2 on $(_s) = [ NormPaths $(HDRS) ] $(P_HDRS) ;
2292	HDRSEARCH3 on $(_s) = [ NormPaths $(STDHDRS) ] ;
2293	HDRSEARCH on $(_s) = [ geton $(_s) : HDRSEARCH1 ] [ geton $(_s) : HDRSEARCH2 ]
2294	                     [ geton $(_s) : HDRSEARCH3 ] ;
2295
2296	# propagate target specific-defines
2297
2298	DEFINES on $(_t) = $(P_DEFINES) $(DEFINES) ;
2299
2300	C++_ $(_t) : $(_s) ;
2301
2302	if $(3) {
2303		ObjectC++Flags $(<) : $(3) ;
2304	}
2305	if $(4) {
2306		ObjectDefines $(<) : $(4) ;
2307	}
2308	if $(5) {
2309		ObjectHdrs $(<) : $(5) ;
2310	}
2311}
2312
2313# Internal C++
2314# C++_ object : sources ;
2315rule C++_
2316{
2317	# If the compiler's -o flag doesn't work, relocate the .o
2318	if $(RELOCATE)
2319	{
2320		CcMv $(<) : $(>) ;
2321	}
2322
2323	local pref_c++flags = $(P_PREF_C++FLAGS) ;
2324	pref_c++flags ?= $(PREF_C++FLAGS) ;
2325	# Make sure we incorporate any C++FLAGS[12] on object into total
2326	C++FLAGS1 on $(<) += $(P_C++FLAGS) $(C++FLAGS) ;
2327	C++FLAGS2 on $(<) += $(pref_c++flags) ;
2328	C++FLAGS on $(<) = [ geton $(<) : C++FLAGS1 ] [ geton $(<) : C++FLAGS2 ] ;
2329
2330	# Make sure the CCHDRS and CCDEFS are formatter correctly
2331	CCHDRS on $(<) = [ on $(<) FIncludes $(HDRS) ] ;
2332	CCDEFS on $(<) = [ on $(<) FDefines $(DEFINES) ] ;
2333}
2334
2335rule Chmod_
2336{
2337#Echo "Chmod_ on '" $(<) "' with MODE = '" [ geton $(<) : MODE ] "'" ;
2338	if $(CHMOD) { Chmod1 $(<) ; }
2339}
2340
2341# Public use Depends that does normalisation of its targets
2342# (non-normalizing Depends is a built in)
2343# NDepends dest : source ;			make dependency
2344rule NDepends {
2345	local _t _s ;
2346	local _p = ;
2347
2348#Echo "NDepends got '" $(<) "' and '" $(>) "'" ;
2349
2350	# Don't anchor psuedo targets
2351	switch $(<)
2352	{
2353       case all : _p = true ;
2354       case first : _p = true ;
2355       case shell : _p = true ;
2356       case files : _p = true ;
2357       case lib : _p = true ;
2358       case exe : _p = true ;
2359       case obj : _p = true ;
2360       case dirs : _p = true ;
2361       case clean : _p = true ;
2362       case install : _p = true ;
2363       case uninstall : _p = true ;
2364	}
2365
2366	# Normalize target names and set Grist LOCATE and SOURCE
2367	if ! $(_p) {
2368		_t = [ NormDstTargets $(<) ] ;
2369	} else {
2370		_t = $(<) ;
2371	}
2372	_s = [ NormSrcTargets $(>) ] ;
2373
2374#Echo "Passing Depends '" $(_t) "' and '" $(_s) "'" ;
2375
2376	Depends $(_t) : $(_s) ;
2377}
2378
2379# Public use NoUpdate that does normalisation of its targets
2380# (non-normalizing NoUpdate is a built in)
2381# NNoUpdate dest ;			Make sure created, but don't update
2382rule NNoUpdate {
2383	local _t ;
2384	local _p = ;
2385
2386#Echo "NNoUpdate got '" $(<) "'" ;
2387
2388	# Don't anchor psuedo targets
2389	switch $(<)
2390	{
2391       case all : _p = true ;
2392       case first : _p = true ;
2393       case shell : _p = true ;
2394       case files : _p = true ;
2395       case lib : _p = true ;
2396       case exe : _p = true ;
2397       case obj : _p = true ;
2398       case dirs : _p = true ;
2399       case clean : _p = true ;
2400       case install : _p = true ;
2401       case uninstall : _p = true ;
2402	}
2403
2404	# Normalize target names and set Grist LOCATE and SOURCE
2405	if ! $(_p) {
2406		_t = [ NormDstTargets $(<) ] ;
2407	} else {
2408		_t = $(<) ;
2409	}
2410	_s = [ NormSrcTargets $(>) ] ;
2411
2412#Echo "Passing NoUpdate '" $(_t) "'" ;
2413
2414	NoUpdate $(_t) ;
2415}
2416
2417# Public use Includes that does normalisation of its targets
2418# (non-normalizing Includes is a built in)
2419# NDepends dest : source ;			make dependency
2420rule NIncludes {
2421	local _t _s ;
2422	local _p = ;
2423
2424#Echo "NIncludes got '" $(<) "' and '" $(>) "'" ;
2425
2426	# Normalize target names and set Grist LOCATE and SOURCE
2427	_t = [ NormDstTargets $(<) ] ;
2428	_s = [ NormSrcTargets $(>) ] ;
2429
2430#Echo "Passing Includes '" $(_t) "' and '" $(_s) "'" ;
2431
2432	Includes $(_t) : $(_s) ;
2433}
2434
2435# sets mode of file
2436# Mod target : mode ;
2437rule Mod
2438{
2439	local _t = [ NormIDstTargets $(<[1]) ] ;
2440	MODE on $(_t) = $(>) ;
2441	Chmod_ $(_t) ;
2442}
2443
2444# copies source onto target.
2445# SRCDIR and DSTDIR will be ignored.
2446# File target : source ;
2447rule File
2448{
2449	local _t = [ NormIDstTargets $(<[1]) ] ;
2450	local _s = [ NormSrcTargets $(>[1]) ] ;
2451
2452	Depends files : $(_t) ;
2453	Depends $(_t) : $(_s) ;
2454	Clean clean : $(_t) ;
2455	MakeLocate $(_t) ;
2456	File_ $(_t) : $(_s) ;
2457	MODE on $(_t) = $(FILEMODE) ;
2458	Chmod_ $(_t) ;
2459}
2460
2461# copies source onto target, but doesn't clean source.
2462# SRCDIR and DSTDIR will be ignored.
2463# File target : source ;
2464rule FileNoClean
2465{
2466	local _t = [ NormIDstTargets $(<[1]) ] ;
2467	local _s = [ NormSrcTargets $(>[1]) ] ;
2468
2469	Depends files : $(_t) ;
2470	Depends $(_t) : $(_s) ;
2471	MakeLocate $(_t) ;
2472	File_ $(_t) : $(_s) ;
2473	MODE on $(_t) = $(FILEMODE) ;
2474	Chmod_ $(_t) ;
2475}
2476
2477# Fake file copy. Creates a dependence to work around
2478# problem that Jam doesn't understand two products from one action.
2479# FakeFile target : source ;
2480rule FakeFile
2481{
2482	local _t = [ NormIDstTargets $(<[1]) ] ;
2483	local _s = [ NormSrcTargets $(>[1]) ] ;
2484
2485	FakeFile_ $(_t) : $(_s) ;
2486}
2487
2488rule FakeFile_
2489{
2490	local _t = $(<) ;
2491	local _s = $(>) ;
2492
2493	Depends files : $(_t) ;
2494	Depends $(_t) : $(_s) ;
2495	Clean clean : $(_t) ;
2496	MakeLocate $(_t) ;
2497}
2498
2499
2500# Compile Fortran source file into object
2501# Fortran object : source ;
2502rule Fortran
2503{
2504	# Normalize target names and set Grist LOCATE and SOURCE
2505	local _t = [ NormDstTargets $(<[1]:S=$(SUFOBJ)) ] ;
2506	local _s = [ NormSrcTargets $(>[1]) ] ;
2507
2508	Depends $(_t) : $(_s) ;
2509	Depends obj : $(_t) ;
2510	Clean clean : $(_t) ;
2511	MakeLocate $(_t) ;
2512
2513	Fortran_ $(_t) : $(_s) ;
2514}
2515
2516# Internal Fortran
2517rule Fortran_
2518{
2519}
2520
2521
2522# NOTE! Perhaps GenFileND and GenFileNND could be replaced by a GenFile
2523# with a $(3) for the dependecies ?
2524
2525# All > are assumed to be files that < is dependent on
2526# with >[1] being an executable
2527# SRCDIR and DSTDIR are ignored.
2528rule GenFile
2529{
2530#Echo "GenFile got '" $(<) "' and '" $(>) "'" ;
2531	# Normalize target names and set Grist LOCATE and SOURCE
2532	local _t = [ NormIDstTargets $(<) ] ;
2533	local _s = [ NormISrcTargets $(>[1]:S=$(SUFEXE)) ] ;
2534	local _a = [ NormISrcTargets $(>[2-]) ] ;
2535
2536#Echo "GenFile normed '" $(_t) "' and '" $(_s) "' plus '" $(_a) "'" ;
2537
2538	Depends $(_t) : $(_s) $(_a) ;
2539	if ! $(_s[1]:G) {		# In case PATH doesn't have . in it.
2540		_s = $(DOT)$(SLASH)$(_s[1]:G=) $(_s[2-]) ;
2541		NotTargets $(_s) ;
2542		NoCare $(_s) ;
2543		NotFile $(_s) ;
2544	}
2545	GenFile1 $(_t) : $(_s) $(_a) ;
2546	Clean clean : $(_t) ;
2547}
2548
2549rule GenFile1
2550{
2551	MakeLocate $(<) ;
2552}
2553
2554# Only >[1] is assumed to be an executable that < is dependent on.
2555# $(3) are optional extra dependecies
2556# SRCDIR and DSTDIR are ignored.
2557rule GenFileND
2558{
2559#Echo "GenFileND got '$(<)' and '$(>)' and src targets '$(_d)'" ;
2560	# Normalize target names and set Grist LOCATE and SOURCE
2561	local _t = [ NormIDstTargets $(<[1]) ] ;
2562	local _s = [ NormISrcTargets $(>[1]:S=$(SUFEXE)) ] ;
2563	local _a = $(>[2-]) ;
2564	_a = $(_a:J=" ") ;
2565	local _d = [ NormSrcTargets $(3) ] ;
2566
2567#Echo "GenFileND normed '$(_t)' and '$(_s)' plus '$(_a)' and src targets '$(_d)'" ;
2568
2569	NotTargets $(_a) ;
2570	NoCare $(_a) ;
2571	NotFile $(_a) ;			# Supresses "independent target", but may mark a directory wrongly
2572	Depends $(_t) : $(_s) $(_d) ;
2573#Echo "GenFileND set Depends '$(_t)' and '$(_s)' and '$(_d)'" ;
2574
2575	if ! $(_s[1]:G) {		# In case PATH doesn't have . in it.
2576		_s = $(DOT)$(SLASH)$(_s[1]) $(_s[2-]) ;
2577		NotTargets $(_s) ;
2578		NoCare $(_s) ;
2579		NotFile $(_s) ;
2580	}
2581	GenFileND1 $(_t) : $(_s) $(_a) ;
2582
2583	Clean clean : $(_t) ;
2584}
2585
2586rule GenFileND1
2587{
2588	MakeLocate $(<) ;
2589}
2590
2591# GenFileNND target : program args : extra_dependecies ;
2592# None of > is assumed to be a file.
2593# $(3) are optional extra dependecies
2594# SRCDIR and DSTDIR are ignored.
2595rule GenFileNND
2596{
2597#Echo "GenFileNND got '$(<)' and '$(>)' and src targets '$(3)' " ;
2598	# Normalize target names and set Grist LOCATE and SOURCE
2599	local _t = [ NormIDstTargets $(<) ] ;
2600	local _a = $(>) ;
2601	_a = $(_a:J=" ") ;		# Split up by space delimeter ?
2602	local _d = [ NormSrcTargets $(3) ] ;
2603
2604#Echo "GenFileNND normed '$(_t)' plus '$(_a)' and src targets '$(_d)'" ;
2605
2606	Depends files : $(_t) ;
2607	Depends $(_t) : $(_d) ;
2608
2609	NotTargets $(_a) ;
2610	NoCare $(_a) ;
2611	NotFile $(_a) ;			# Supresses "independent target", but may mark a directory wrongly
2612
2613	GenFileNND1 $(_t) : $(_a) ;
2614	Clean clean : $(_t) ;
2615}
2616
2617rule GenFileNND1
2618{
2619#Echo "GenFileNND1 got "' $(<) "' and "' $(>) "'" ;
2620	MakeLocate $(<) ;
2621}
2622
2623# GenFileNNDnc target : program args : extra_dependecies ;
2624# Same as GenFileNND but don't clean the target.
2625# None of > is assumed to be a file.
2626# $(3) are optional extra dependecies
2627# SRCDIR and DSTDIR are ignored.
2628rule GenFileNNDnc
2629{
2630#Echo "GenFileNNDnc got '$(<)' and '$(>)' and src targets '$(3)' " ;
2631	# Normalize target names and set Grist LOCATE and SOURCE
2632	local _t = [ NormIDstTargets $(<) ] ;
2633	local _a = $(>) ;
2634	_a = $(_a:J=" ") ;		# Split up by space delimeter ?
2635	local _d = [ NormSrcTargets $(3) ] ;
2636
2637#Echo "GenFileNNDnc normed '$(_t)' plus '$(_a)' and src targets '$(_d)'" ;
2638
2639	Depends files : $(_t) ;
2640	Depends $(_t) : $(_d) ;
2641
2642	NotTargets $(_a) ;
2643	NoCare $(_a) ;
2644	NotFile $(_a) ;			# Supresses "independent target", but may mark a directory wrongly
2645
2646	GenFileNND1 $(_t) : $(_a) ;
2647}
2648
2649# Concatenate all the argument to the file
2650# Each argument to a separate line
2651# If no arguments, create empty file
2652# SRCDIR and DSTDIR are ignored.
2653rule CatToFile
2654{
2655#Echo "CatToFile got '" $(<) "' and '" $(>) "'" ;
2656	# Normalize target names and set Grist LOCATE and SOURCE
2657	local _t = [ NormIDstTargets $(<) ] ;
2658
2659	MakeLocate $(_t) ;
2660	Depends files : $(_t) ;
2661	NotFile $(2) $(3) $(4) $(5) $(6) $(7) $(8) $(9) ;
2662
2663	Clean clean : $(_t) ;
2664
2665	if ! $(>) {
2666		CreateCatFile_ $(_t) ;
2667
2668	} else {
2669		if $(2) {
2670			CatToFile_ $(_t) : $(2) ;
2671		}
2672		if $(3) {
2673			CatToFile_ $(_t) : $(3) ;
2674		}
2675		if $(4) {
2676			CatToFile_ $(_t) : $(4) ;
2677		}
2678		if $(5) {
2679			CatToFile_ $(_t) : $(5) ;
2680		}
2681		if $(6) {
2682			CatToFile_ $(_t) : $(6) ;
2683		}
2684		if $(7) {
2685			CatToFile_ $(_t) : $(7) ;
2686		}
2687		if $(8) {
2688			CatToFile_ $(_t) : $(8) ;
2689		}
2690		if $(9) {
2691			CatToFile_ $(_t) : $(9) ;
2692		}
2693	}
2694}
2695
2696rule HardLink
2697{
2698	local _t = [ NormDstTargets $(<) ] ;
2699	local _s = [ NormSrcTargets $(>) ] ;
2700
2701	Depends files : $(_t) ;
2702	Depends $(_t) : $(_s) ;
2703
2704	HardLink_ $(_t) : $(_s) ;
2705}
2706
2707# Mark executable as GUI applications (ie. OS X Bundle)
2708# GuiImages images ;
2709rule GuiBin
2710{
2711	local _t = [ NormDstTargets $(<:S=$(SUFEXE)) ] ;
2712	GUIAPP on $(_t) = "true" ;
2713}
2714
2715rule GUIAPP
2716{
2717}
2718
2719# /HdrMacroFile
2720#
2721# this rule is specific to FT-Jam. It is used to indicate that a given file
2722# contains definitions for filename macros (e.g. "#define MYFILE_H <myfile>.h")
2723# that can later be used in #include statements in the rest of the source
2724#
2725# these files must be parsed before any make is tried.
2726#
2727rule HdrMacroFile
2728{
2729  HDRMACRO $(<) ;
2730}
2731
2732# Handle #includes that are found.
2733# Try and locate them to asociate them with declared targets, as
2734# well as tracing any further #includes they may have.
2735# HdrRule NormedSource : headers ;
2736rule HdrRule
2737{
2738	# N.B.		This rule is called during binding, potentially after
2739	# the fate of many targets has been determined, and must be
2740	# used with caution: don't add dependencies to unrelated
2741	# targets, and don't set variables on $(<).
2742
2743#Echo "HdrRule got '" $(<) "' and '" $(>) "'" ;
2744
2745	local _d = [ geton $(<) : NOMLOC ] ;		# Directory location of source file
2746	local _schpath = [ geton $(<) : HDRSEARCH ] ;	# Search path used to find these
2747	local _s _ts ;				# include source targets, sources to trace
2748
2749#Echo "HDRSEARCH on '" $(<) "' is = '" $(_schpath) "'" ;
2750
2751	# See if we can locate the header amongst the generated files.
2752#Echo "Checking for matches of known targets" ;
2753	local _i _j _k _ss _sp _n ;
2754	local _stdhdrs = [ NormPaths $(STDHDRS) ] ;
2755	_st = ;
2756	for _j in $(>) {
2757		_sp = ;			# Search path
2758		_ss = ;			# Resolved source target
2759#Echo "Checking include '" $(_j) "'" ;
2760		for _k in $(_schpath)  "__unknown__" {		# search path and plain
2761			_n = [ NormPaths $(_j) : $(_k) ] ;		# Normalized path for that search path
2762			_i = [ _TargetIDs $(_n) ] ;				# Target ID/name if it exitsts
2763#Echo "Checking target ID '" $(_i)-target "' value '" $($(_i)-target) "'" ;
2764			if $($(_i)-target) {				# Target exists
2765				_ss = $(_i) ;
2766				_s += $(_ss) ;
2767#Echo "Found existing target '" $(_ss) "'" ;
2768				break ;
2769			} else if ! $($(_i)-target) {				# unknown state
2770#Echo "Unknown statis target '" $(_i) "'" ;
2771				_sp += [ NormPaths $(_j:D) : $(_k) ] ;	# paths to search
2772			}
2773		}
2774		if ! $(_ss) && $(_sp) {		# We've not seen that target
2775			local _found = ;
2776#Echo "Searching for '" $(_j) "' in paths '" $(_sp) "'" ;
2777			# See if we can find the header
2778			_found = [ GLOB $(_sp) : $(_j:BS) ] ;
2779
2780			# Hmm. This sort of works around Windows problem of std include files being upper case.
2781			# It won't solve the problem of tracing them if TRACESTDHDRS is true though.
2782			if $(NT) && ! $(_found) {
2783				_found = [ GLOB $(_sp) : $(_j:UBS) ] ;
2784				_found = $(_found:D)\\$(_found:LBS) ;
2785			}
2786			if $(_found) {
2787				_ss = [ NormSrcTargets $(_found[1]) ] ;		# Add it to our list
2788#Echo "Using new found target '" $(_ss) "'" ;
2789				_s += $(_ss) ;
2790			}
2791			# Mark off not found targets
2792			for _k in $(_schpath) {
2793				_n = [ NormPaths $(_j) : $(_k) ] ;	# Normalized path for that search path
2794				_i = [ _TargetIDs $(_n) ] ;			# Target ID/name if it exitsts
2795				if $(_i) = $(_ss) {
2796					break ;							# The one we found
2797				}
2798#Echo "marking off '" $(_i) "' as non-existant" ;
2799				$(_i)-target = "false" ;			# That combination doesn't exist
2800			}
2801			if ! $(_found) {
2802				_k = "__unknown__" ;
2803				_ss = [ NormSrcTargets $(_j) : $(_k) ] ;
2804				# ~~99 This would make good warning information ?
2805#Echo "Include unresolved: '" $(_ss) "'" ;
2806				_s += $(_ss) ;	# Use plain header name as target ID
2807			}
2808		}
2809		# We're left with $(_ss_) being the target and $(_k) being the search path
2810
2811		# Add this to our list that will also be scanned for #includes
2812#Echo "Dealt with'" $(_j) "', _ss = '" $(_ss) "' and _k = '" $(_k) "'" ;
2813		if  ( ! $(_k) in "__unknown__" )
2814		 && ( $(TRACESTDHDRS) = true || ! $(_k) in $(_stdhdrs) )  {
2815			_st += $(_ss) ;
2816		}
2817	}
2818
2819#Echo "Normalized includes = '" $(_s) "'" ;
2820#Echo "Includes to be traced = '" $(_st) "'" ;
2821
2822	# Propagate on $(<) to $(>)
2823	# Compute header search path for any #includes in these #includes
2824
2825	if $(_st)  {
2826		HDRSEARCH2 on $(_st) = [ geton $(<) : HDRSEARCH2 ] ;
2827		HDRSEARCH3 on $(_st) = [ geton $(<) : HDRSEARCH3 ] ;
2828		for _i in $(_st) {
2829			# Replace file dot/HDRSEARCH1 with one for this file
2830			local _dot = [ geton $(_i) : NOMLOC ] ;
2831			if ! $(_dot) { _dot = $(DOT) ; }
2832			HDRSEARCH1 on $(_i) = $(_dot) ;
2833			HDRSEARCH on $(_i) = [ geton $(_i) : HDRSEARCH1 ] [ geton $(_i) : HDRSEARCH2 ]
2834			                     [ geton $(_i) : HDRSEARCH3 ] ;
2835		}
2836		HDRSCAN on $(_st)   = [ geton $(<) : HDRSCAN ] ;
2837		HDRRULE on $(_st)   = [ geton $(<) : HDRRULE ] ;
2838		HDRGRIST on $(_st)  = [ geton $(<) : HDRGRIST ] ;
2839#Echo "HdrRule SEARCH on '" $(_st) "' set to '" [ geton $(_st) : SEARCH ] "'" ;
2840#Echo "HdrRule HDRSEARCH on '" $(_st) "' set to '" [ geton $(_st) : HDRSEARCH ] "'" ;
2841#Echo "HdrRule HDRSCAN on '" $(_st) "' set to '" [ geton $(_st) : HDRSCAN ] "'" ;
2842#Echo "HdrRule HDRRULE on '" $(_st) "' set to '" [ geton $(_st) : HDRRULE ] "'" ;
2843	}
2844
2845	# Tell Jam that anything depending on $(<) also depends on $(>),
2846	# set SEARCH so Jam can find the headers, but then say we don't
2847	# care if we can't actually find the headers (they may have been
2848	# within ifdefs),
2849
2850	NoCare $(_s) ;
2851	SEARCH on $(_s) = $(_schpath) ;		# Use search path used to find these #includes as Jam SEARCH path.
2852	Includes $(<) : $(_s) ;
2853}
2854
2855# Public InstallInto
2856# InstallInto dir : sources ;		install any files
2857rule InstallInto
2858{
2859#Echo "InstallInto got '" $(<) "' and '" $(>) "'" ;
2860	local _d = [ NormPaths $(<) ] ; # Directory
2861	local _s = [ NormSrcTargets $(>) ] ;	# Sources
2862	local _t = [ CreateIDstTargets $(_s) : $(_d) ] ; # Relocate targs to dir
2863	_InstallInto $(_t) : $(_s) ;
2864}
2865
2866# Private InstallInto
2867# Note that the install rules ignore SRDDIR and DSTDIR.
2868# InstallInto destinations : sources ;		install any files
2869rule _InstallInto
2870{
2871#Echo "_InstallInto got '" $(<) "' and '" $(>) "'" ;
2872
2873	local _t = $(<) ;		# targets
2874	local _s = $(>) ;		# sources
2875	local _is _it ;			# individual source and target
2876
2877	# Arrange for jam install
2878	# Arrange for jam uninstall
2879	# targets are in dir
2880
2881	Depends install : $(_t) ;
2882	Clean uninstall : $(_t) ;
2883	MakeLocate $(_t) ;				# create directories
2884
2885	# For each source, Install, Chmod, Chown, and Chgrp
2886
2887	for _is in $(_s)
2888	{
2889		_it = $(_t[1]) ;
2890		_t = $(_t[2-]) ;	# Track _is
2891
2892#Echo "_InstallInto installing target '" $(_it) "' from src '" $(_is) "'" ;
2893		Depends $(_it) : $(_is) ;
2894		Install $(_it) : $(_is) ;
2895		Chmod_ $(_it) ;
2896
2897		if $(OWNER) && $(CHOWN)
2898		{
2899			Chown_ $(_it) ;
2900			OWNER on $(_it) = $(OWNER) ;
2901		}
2902
2903		if $(GROUP) && $(CHGRP)
2904		{
2905			Chgrp_ $(_it) ;
2906			GROUP on $(_it) = $(GROUP) ;
2907		}
2908	}
2909}
2910
2911# InstallBin dir : sources ;		install binaries
2912rule InstallBin
2913{
2914#Echo "InstallBin got '" $(<) "' and '" $(>) "'" ;
2915	local _d = [ NormPaths $(<) ] ; # Directory
2916	local _s = [ NormSrcTargets $(>:S=$(SUFEXE)) ] ;	# Sources
2917	local _t = [ CreateIDstTargets $(_s) : $(_d) ] ; # Relocate targs to dir
2918#Echo "InstallBin norm '" $(_d) "' and '" $(_s) "' and '" $(_t) "'" ;
2919	MODE on $(_t) = $(EXEMODE) ;
2920	_InstallInto $(_t) : $(_s) ;
2921#Echo "InstallBin done " ;
2922}
2923
2924# InstallFile dir : sources ;		install files
2925rule InstallFile
2926{
2927#Echo "InstallFile got '" $(<) "' and '" $(>) "'" ;
2928	local _d = [ NormPaths $(<) ] ; # Directory
2929	local _s = [ NormSrcTargets $(>) ] ;	# Sources
2930	local _t = [ CreateIDstTargets $(_s) : $(_d) ] ; # Relocate targs to dir
2931#Echo "InstallFile normed targ '" $(_t) "' src '" $(_s) "' and dir '" $(_d) "'" ;
2932	MODE on $(_t) = $(FILEMODE) ;
2933	_InstallInto $(_t) : $(_s) ;
2934}
2935
2936# InstallLib dir : sources ;		install static library files
2937rule InstallLib
2938{
2939#Echo "InstallLib got '" $(<) "' and '" $(>) "'" ;
2940	local _d = [ NormPaths $(<) ] ; # Directory
2941	local _s = [ NormSrcTargets $(>:S=$(SUFLIB)) ] ;	# Sources
2942	local _t = [ CreateIDstTargets $(_s) : $(_d) ] ; # Relocate targs to dir
2943	MODE on $(_t) = $(FILEMODE) ;
2944	_InstallInto $(_t) : $(_s) ;
2945}
2946
2947# InstallShLib dir : sources ;		install shared library files
2948rule InstallShLib
2949{
2950#Echo "InstallShLib got '" $(<) "' and '" $(>) "'" ;
2951	local _d = [ NormPaths $(<) ] ; # Directory
2952	local _s = [ NormSrcTargets $(>:S=$(SUFSHLIB)) ] ;	# Sources
2953	local _t = [ CreateIDstTargets $(_s) : $(_d) ] ; # Relocate targs to dir
2954	MODE on $(_t) = $(FILEMODE) ;
2955	_InstallInto $(_t) : $(_s) ;
2956}
2957
2958# InstallShell dir : sources ;		install files
2959rule InstallShell
2960{
2961#Echo "InstallShell got '" $(<) "' and '" $(>) "'" ;
2962	local _d = [ NormPaths $(<) ] ; # Directory
2963	local _s = [ NormSrcTargets $(>) ] ;	# Sources
2964	local _t = [ CreateIDstTargets $(_s) : $(_d) ] ; # Relocate targs to dir
2965	MODE on $(_t) = $(SHELLMODE) ;
2966	_InstallInto $(_t) : $(_s) ;
2967}
2968
2969# InstallMan dir : sources ;		install files
2970rule InstallMan
2971{
2972#Echo "InstallMan got '" $(<) "' and '" $(>) "'" ;
2973	local _d = [ NormPaths $(<) ] ;	# Directory
2974	local _s = [ NormSrcTargets $(>) ] ;	# Sources
2975	local _t = [ CreateIDstTargets $(_s) : $(_d) ] ; # Relocate targs to dir
2976
2977	# Really this just strips the . from the suffix
2978
2979	local _is _it _tt _s _id ;
2980
2981	_tt = $(_t) ;
2982	for _is in $(_s)
2983	{
2984		_it = $(_tt[1]) ;
2985		_tt = $(_tt[2-]) ;
2986
2987		switch $(_is:S)
2988		{
2989			case .1 : s = 1 ; case .2 : s = 2 ; case .3 : s = 3 ;
2990			case .4 : s = 4 ; case .5 : s = 5 ; case .6 : s = 6 ;
2991			case .7 : s = 7 ; case .8 : s = 8 ; case .l : s = l ;
2992			case .n : s = n ; case .man : s = 1 ;
2993		}
2994
2995		_id = [ RootPaths $(_d) : man$(_s) ] ;
2996		CreateIDstTargets $(_it) : $(_id) ;
2997		MODE on $(_it) = $(FILEMODE) ;
2998		_InstallInto $(_it) : $(_is) ;
2999	}
3000}
3001
3002# Lex
3003# Lex source.c : source.l ;
3004rule Lex
3005{
3006	# Normalize target names and set Grist LOCATE and SOURCE
3007	local _t = [ NormDstTargets $(<[1]) ] ;
3008	local _s = [ NormSrcTargets $(>[1]) ] ;
3009
3010	Depends $(_t) : $(_s) ;
3011	Clean clean : $(_t) ;
3012	MakeLocate $(_t) ;
3013
3014	Lex_ $(_t) : $(_s) ;
3015}
3016
3017# Internal Lex
3018rule Lex_
3019{
3020	LexMv_ $(<) : $(>) ;
3021}
3022
3023# Library - create a static library from sources.
3024# Library library : sources : flags : defines : hdrpaths : objects ;
3025rule Library
3026{
3027	LibraryFromObjects $(<) : $(>) $(6) ;
3028	Objects $(>) : $(3) : $(4) : $(5) ;
3029}
3030
3031# LibraryFromObjects - create a static library from object files.
3032# LibraryFromObjects library : objects ;
3033rule LibraryFromObjects
3034{
3035	local _i ;
3036
3037#Echo "LibraryFromObjects got " $(<) "and" $(>) "'" ;
3038	# Normalize target names and set Grist LOCATE and SOURCE
3039	local _l = [ NormDstTargets $(<[1]:S=$(SUFLIB)) ] ;
3040	local _s = [ NormSrcTargets $(>:S=$(SUFOBJ)) ] ;
3041#Echo "LibraryFromObjects nomed = " $(_l) "and" $(_s) ;
3042
3043	Depends lib : $(_l) ;
3044
3045	MakeLocate $(_l) ;
3046
3047	if $(NOARSCAN)
3048	{
3049		# If we can't scan the library to timestamp its contents,
3050		# we have to just make the library depend directly on the
3051		# on-disk object files.
3052
3053		Depends $(_l) : $(_s) ;
3054	}
3055	else
3056	{
3057		# If we can scan the library, we make the library depend
3058		# on its members and each member depend on the on-disk
3059		# object file.
3060
3061		for _i in $(_s)
3062		{
3063			local _m ;
3064			_m = $(_l:M=$(_i:BS)) ;
3065			CopyTarget $(_m) : $(_l) ;	# Transfer LOCATE, SEARCH, NOMLOC
3066			Depends $(_l) : $(_m) ;
3067			Depends $(_m) : $(_i) ;
3068		}
3069	}
3070
3071	Clean clean : $(_l) ;
3072
3073	if $(CRELIB) {
3074		CreLib $(_l) : $(_s[1]) ;
3075	}
3076
3077	Archive $(_l) : $(_s) ;
3078
3079	if $(RANLIB) {
3080		Ranlib $(_l) ;
3081	}
3082
3083	# If we can't scan the library, we have to leave the .o's around.
3084	if ! ( $(NOARSCAN) || $(NOARUPDATE) ) {
3085		local _ds ;
3086		for _i in $(_s) {
3087			# Don't delete any objects that we've marked with KEEPOBJS
3088			if ! [ geton $(_i) : KEEPOBJS ] {
3089				_ds += $(_i) ;
3090			}
3091		}
3092		if $(_ds) {
3093			RmTemps_ $(_l) : $(_ds) ;
3094		}
3095	}
3096}
3097
3098# LibraryFromLibraries - create a static library from object files and static libraries.
3099# LibraryFromLibraries library : libraries ;
3100rule LibraryFromLibraries
3101{
3102	local _i ;
3103
3104#Echo "LibraryFromLibraries got " $(<) "and" $(>) ;
3105	# Normalize target names and set Grist LOCATE and SOURCE
3106	local _l = [ NormDstTargets $(<[1]:S=$(SUFLIB)) ] ;
3107	local _s = [ NormSrcTargets $(>:S=$(SUFLIB)) ] ;
3108#Echo "LibraryFromObjects nomed = " $(_l) "and" $(_s) ;
3109
3110	Depends lib : $(_l) ;
3111	Depends $(_l) : $(_s) ;
3112
3113	MakeLocate $(_l) ;
3114
3115	Clean clean : $(_l) ;
3116
3117	if $(CRELIB) {
3118		CreLib $(_l) : $(_s[1]) ;
3119	}
3120
3121	ArchiveArchive $(_l) : $(_s) ;
3122}
3123
3124# ShLibrary - create a shared library from sources.
3125# ShLibrary library : sources : flags : defines : hdrpaths : objects : libs : shlibs ;
3126rule ShLibrary
3127{
3128	ShLibraryFromObjects $(<) : $(>) $(6) : $(7) : $(8) ;
3129	Objects $(>) : $(CCSHOBJFLAG) $(3) : $(4) : $(5) ;
3130}
3131
3132# ShLibraryFromObjects - create a shared library from object files.
3133# Both the import (if used on the system) and shared library will be created.
3134# ShLibraryFromObjects shlib : objects : libs : shlibs ;
3135rule ShLibraryFromObjects
3136{
3137	local _i _l ;
3138
3139#Echo "ShLibraryFromObjects got " $(<) "and" $(>) ;
3140	# Normalize target names and set Grist LOCATE and SOURCE
3141	local _sl = [ NormDstTargets $(<[1]:S=$(SUFSHLIB)) ] ;
3142	if $(NT) {
3143		_l = [ NormDstTargets $(<[1]:S=$(SUFIMPLIB)) ] ;
3144	}
3145	local _s = [ NormSrcTargets $(>:S=$(SUFOBJ)) ] ;
3146#Echo "ShLibraryFromObjects nomed =" $(_sl) "and" $(_l) "and" $(_s) ;
3147
3148	Depends lib : $(_sl) ;
3149#	Depends lib : $(_l) ;
3150	MakeLocate $(_sl) ;
3151
3152	Depends $(_sl) : $(_s) ;
3153	Clean clean : $(_sl) $(_l) ;
3154
3155	if $(_l) {
3156		Depends $(_l) : $(_s) ;
3157		Clean clean : $(_l:S=.exp) ;
3158	}
3159
3160#Echo "ShLibraryFromObjects SHLINKFLAGS = '" $(SHLINKFLAGS) "' and P_SHLINKFLAGS ='" $(P_LSHINKFLAGS) "'" ;
3161
3162	if $(SHLINKFLAGS) || $(P_SHLINKFLAGS)
3163	 || $(PREF_SHLINKFLAGS) || $(P_PREF_SHLINKFLAGS) {
3164		local pref_shlinkflags = $(P_PREF_SHLINKFLAGS) ;
3165		pref_shlinkflags ?= $(PREF_SHLINKFLAGS) ;
3166		SHLINKFLAGS on $(_sl) += $(P_SHLINKFLAGS) $(SHLINKFLAGS) $(pref_shlinkflags) ;
3167	}
3168
3169#Echo "ShLibraryFromObjects SHLINKOBJS = '" $(SHLINKOBJS) "' and P_SHLINKOBJS ='" $(P_SHLINKOBJS) "'" ;
3170	if $(SHLINKOBJS) || $(P_SHLINKOBJS) {
3171		local _o = [ NormSrcTargets $(SHLINKOBJS:S=$(SUFOBJ)) ] $(P_SHLINKOBJS:S=$(SUFOBJ)) ;
3172		Depends $(_sl) : $(_o) ;
3173		SHLINKOBJS on $(_sl) += $(_o) ;
3174	}
3175
3176#Echo "ShLibraryFromObjects SHLINKLIBS = '" $(SHLINKLIBS) "' and P_SHLINKLIBS ='" $(P_SHLINKLIBS) "'" ;
3177	if $(SHLINKLIBS) || $(P_SHLINKLIBS) {
3178		local _l = [ NormSrcTargets $(SHLINKLIBS:S=$(SUFLIB)) ] $(P_SHLINKLIBS:S=$(SUFLIB)) ;
3179		Depends $(_sl) : $(_l) ;
3180		SHLINKLIBS on $(_sl) += $(_l) ;
3181	}
3182
3183#Echo "ShLibraryFromObjects SHLINKSHLIBS = '" $(SHLINKSHLIBS) "' and P_SHLINKSHLIBS ='" $(P_SHLINKSHLIBS) "'" ;
3184	if $(SHLINKSHLIBS) || $(P_SHLINKSHLIBS) {
3185		local _l = [ NormSrcTargets $(SHLINKSHLIBS:S=$(SUFSHLIB)) ] $(P_SHLINKSHLIBS:S=$(SUFSHLIB)) ;
3186		Depends $(_sl) : $(_l) ;
3187		SHLINKSHLIBS on $(_sl) += $(_l) ;
3188	}
3189
3190	if $(SHLINKDEFFILE) {	# Windows special option
3191		SHLINKDEFFILE on $(_sl) $(_l) = [ NormSrcTargets $(SHLINKDEFFILE) ] ;
3192		Depends $(_sl) : [ geton $(_sl) : SHLINKDEFFILE ] ;
3193		FakeFile_ $(_l) : $(_sl) ;		# .lib is created with .dll
3194		ShLinkDef_ $(_sl) $(_l) : $(_s) ;
3195	} else {
3196		if (SHLINKSEARCHEXEPATH) {		# UNIX special option
3197
3198			if $(OS) = MACOSX {		# OS X version of ld
3199				SHLINKSEARCHEXEPATH = @executable_path/ ;
3200			} else {
3201#				SHLINKSEARCHEXEPATH = \\$PATH/ ;
3202				SHLINKSEARCHEXEPATH = \\$ORIGIN/ ;
3203			}
3204		}
3205		ShLink_ $(_sl) $(_l) : $(_s) ;
3206	}
3207
3208	# Try and make sure the objects are build with the correct flag
3209	ObjectCcFlags $(>) : $(CCSHOBJFLAG) ;
3210	ObjectC++Flags $(>) : $(CCSHOBJFLAG) ;
3211
3212	if $(3) {
3213		ShLibraryLibraries $(<) : $(3) ;
3214	}
3215	if $(4) {
3216		ShLibraryShLibraries $(<) : $(4) ;
3217	}
3218}
3219
3220# Internal link
3221rule Link_
3222{
3223	MODE on $(<) = $(EXEMODE) ;
3224	Chmod_ $(<) ;
3225}
3226
3227# Make the shared library link with the given objects.
3228# This is just a way of adding common object files to many shlibs.
3229# ShLibraryObjects shlib : objects ;
3230rule ShLibraryObjects
3231{
3232#Echo "ShLibraryObjects got '" $(<) "' and '" $(>) "'" ;
3233	# Normalize target names and set Grist LOCATE and SOURCE
3234	local _t = [ NormDstTargets $(<:S=$(SUFSHLIB)) ] ;
3235	local _o = [ NormSrcTargets $(>:S=$(SUFOBJ)) ] ;
3236
3237	Depends $(_t) : $(_o) ;
3238
3239	SHLINKOBJS on $(_t) += $(_o) ;
3240}
3241
3242# Make the executables link with the given static libraries.
3243# ShLibraryLibraries shlib : libraries ;
3244rule ShLibraryLibraries
3245{
3246#Echo "ShLibraryLibraries got '" $(<) "' and '" $(>) "'" ;
3247	# Normalize target names and set Grist LOCATE and SOURCE
3248	local _t = [ NormDstTargets $(<:S=$(SUFSHLIB)) ] ;
3249	local _l = [ NormSrcTargets $(>:S=$(SUFLIB)) ] ;
3250
3251	Depends $(_t) : $(_l) ;
3252
3253	SHLINKLIBS on $(_t) += $(_l) ;
3254}
3255
3256# Make the executables link with the given shared libraries.
3257# ShLibraryShLibraries shlib : shlibraries ;
3258rule ShLibraryShLibraries
3259{
3260#Echo "ShLibraryShLibraries got '" $(<) "' and '" $(>) "'" ;
3261	# Normalize target names and set Grist LOCATE and SOURCE
3262	local _t = [ NormDstTargets $(<:S=$(SUFSHLIB)) ] ;
3263	local _l = [ NormSrcTargets $(>:S=$(SUFSHIMPLIB)) ] ;
3264
3265	Depends $(_t) : $(_l) ;
3266
3267	SHLINKSHLIBS on $(_t) += $(_l) ;
3268}
3269
3270# Add extra LINKFLAGS to mains
3271# MainLinkFlags mains : flags ;
3272rule MainLinkFlags
3273{
3274#Echo "MainLinkFlags got '" $(<) "' and '" $(>) "'" ;
3275	local _t = [ NormDstTargets $(<:S=$(SUFEXE)) ] ;
3276	local _i ;
3277
3278	for _i in $(_t) {
3279		LINKFLAGS on $(_i) += $(>) ;
3280#Echo "exes '" $(_i) "' got LINKFLAGS '" [ geton $(_i) : LINKFLAGS ] "'" ;
3281	}
3282}
3283
3284# Make an executable from sources
3285# Main image : sources : flags : defines : hdrpaths : objects : libs : shlibs ;
3286rule Main
3287{
3288	MainFromObjects $(<) : $(>) $(6) : $(7) : $(8) ;
3289	Objects $(>) : $(3) : $(4) : $(5) ;
3290}
3291
3292# Make a variant executable from sources
3293# Objects are distiguished by appending "_image"
3294# MainVariant image : sources : flags : defines : hdrpaths : objects : libs : shlibs ;
3295rule MainVariant
3296{
3297	local _i _t _o ;
3298
3299#Echo "MainVariant got '" $(<) "' and '" $(>) "'" ;
3300	for _i in $(>) {
3301		_t = $(_i:DB)_$(<[1]) ;
3302		Object $(_t) : $(_i) : $(3) : $(4) : $(5) ;
3303#Echo "MainVariant object '" $(_t) "' and src '" $(_i) "'" ;
3304		_o += $(_t) ;
3305	}
3306#Echo "MainVariant image '" $(<) "' and objs '" $(_o) "'" ;
3307	MainFromObjects $(<) : $(_o) $(6) : $(7) : $(8) ;
3308}
3309
3310# Make an executable from objects
3311# MainFromObjects image : objects : libs : shlibs ;
3312rule MainFromObjects
3313{
3314#Echo "MainFromObjects got" $(<) "and" $(>) ;
3315
3316	# Normalize target names and set Grist LOCATE and SOURCE
3317	local _t = [ NormDstTargets $(<[1]:S=$(SUFEXE)) ] ;
3318	local _s = [ NormSrcTargets $(>:S=$(SUFOBJ)) ] ;
3319
3320#Echo "MainFromObjects _t" $(_t) "and _s" $(_s) ;
3321
3322	# so 'jam foo' works when it's really foo.exe
3323	if $(_t:S=) != $(_t)
3324	{
3325		Depends $(_t:S=) : $(_t) ;
3326		NotFile $(_t:S=) ;
3327	}
3328
3329	# make compiled sources a dependency of target
3330
3331	Depends exe : $(_t) ;
3332	Depends $(_t) : $(_s) ;
3333	Clean clean : $(_t) ;
3334	MakeLocate $(_t) ;
3335
3336	if $(3) {
3337		LinkLibraries $(<) : $(3) ;
3338	}
3339	if $(4) {
3340		LinkShLibraries $(<) : $(4) ;
3341	}
3342
3343#Echo "MainFromObjects LINKFLAGS = '" $(LINKFLAGS) "' and P_LINKFLAGS ='" $(P_LINKFLAGS) "'" ;
3344#Echo "                PREF_LINKFLAGS = '" $(PREF_LINKFLAGS) "' and P_PREF_LINKFLAGS ='" $(P_PREF_LINKFLAGS) "'" ;
3345	if $(LINKFLAGS) || $(P_LINKFLAGS)
3346	 || $(PREF_LINKFLAGS) || $(P_PREF_LINKFLAGS) {
3347		local pref_linkflags = $(P_PREF_LINKFLAGS) ;
3348		pref_linkflags ?= $(PREF_LINKFLAGS) ;
3349		LINKFLAGS on $(_t) += $(P_LINKFLAGS) $(LINKFLAGS) $(pref_linkflags) ;
3350#Echo "LINKFLAGS on $(_t) = '" [ geton $(_t) : LINKFLAGS ] "'" ;
3351	}
3352
3353#Echo "MainFromObjects LINKOBJS = '" $(LINKOBJS) "' and P_LINKOBJS ='" $(P_LINKOBJS) "'" ;
3354	if $(LINKOBJS) || $(P_LINKOBJS) {
3355		local _o = [ NormSrcTargets $(LINKOBJS:S=$(SUFOBJ)) ] $(P_LINKOBJS:S=$(SUFOBJ)) ;
3356		Depends $(_t) : $(_o) ;
3357		LINKOBJS on $(_t) += $(_o) ;
3358	}
3359
3360#Echo "MainFromObjects LINKLIBS = '" $(LINKLIBS) "' and P_LINKLIBS ='" $(P_LINKLIBS) "'" ;
3361	if $(LINKLIBS) || $(P_LINKLIBS) {
3362		local _l = [ NormSrcTargets $(LINKLIBS:S=$(SUFLIB)) ] $(P_LINKLIBS:S=$(SUFLIB)) ;
3363		Depends $(_t) : $(_l) ;
3364		LINKLIBS on $(_t) += $(_l) ;
3365	}
3366
3367#Echo "MainFromObjects LINKSHLIBS = '" $(LINKSHLIBS) "' and P_LINKSHLIBS ='" $(P_LINKSHLIBS) "'" ;
3368	if $(LINKSHLIBS) || $(P_LINKSHLIBS) {
3369		local _l = [ NormSrcTargets $(LINKSHLIBS:S=$(SUFIMPLIB)) ] $(P_LINKSHLIBS:S=$(SUFIMPLIB)) ;
3370		Depends $(_t) : $(_l) ;
3371		LINKSHLIBS on $(_t) += $(_l) ;
3372	}
3373
3374	Link_ $(_t) : $(_s) ;
3375
3376	# Some OS's need to post process GUI apps to work (ie. OS X bundle)
3377	if [ geton $(_t) : GUIAPP ] = "true" {
3378		GUIAPP $(_t) ;
3379	}
3380#Echo "MainFromObjects done" ;
3381}
3382
3383# A rule to make several mains from each of their single source files.
3384# MainsFromSources executables ;
3385rule MainsFromSources
3386{
3387	local _i ;
3388	for _i in $(<) {
3389		Main $(_i) : $(_i) ;
3390	}
3391}
3392
3393# Make the executables link with the given objects.
3394# This is just a way of adding common object files to many mains.
3395# LinkObjects image : objects ;
3396rule LinkObjects
3397{
3398#Echo "LinkObjects got '" $(<) "' and '" $(>) "'" ;
3399	# Normalize target names and set Grist LOCATE and SOURCE
3400	local _t = [ NormDstTargets $(<:S=$(SUFEXE)) ] ;
3401	local _o = [ NormSrcTargets $(>:S=$(SUFOBJ)) ] ;
3402
3403	Depends $(_t) : $(_o) ;
3404
3405	LINKOBJS on $(_t) += $(_o) ;
3406}
3407
3408# Make the executables link with the given static libraries.
3409# LinkLibraries image : libraries ;
3410rule LinkLibraries
3411{
3412#Echo "LinkLibraries got '" $(<) "' and '" $(>) "'" ;
3413	# Normalize target names and set Grist LOCATE and SOURCE
3414	local _t = [ NormDstTargets $(<:S=$(SUFEXE)) ] ;
3415	local _l = [ NormSrcTargets $(>:S=$(SUFLIB)) ] ;
3416
3417	Depends $(_t) : $(_l) ;
3418
3419	LINKLIBS on $(_t) += $(_l) ;
3420}
3421
3422# Make the executables link with the given shared libraries.
3423# LinkShLibraries image : shlibraries ;
3424rule LinkShLibraries
3425{
3426#Echo "LinkShLibraries got '" $(<) "' and '" $(>) "'" ;
3427	# Normalize target names and set Grist LOCATE and SOURCE
3428	local _t = [ NormDstTargets $(<:S=$(SUFEXE)) ] ;
3429	local _l = [ NormSrcTargets $(>:S=$(SUFSHIMPLIB)) ] ;
3430
3431	Depends $(_t) : $(_l) ;
3432
3433	LINKSHLIBS on $(_t) += $(_l) ;
3434}
3435
3436# Ensure that each targets directories are created
3437# Makelocate targets ;
3438rule MakeLocate
3439{
3440#Echo "MakeLocate got '" $(<) "'" ;
3441	local _i ;
3442	# Uses special variable LOCATE of targets, and arranges
3443	# with MkDir to create target directory.
3444	# The directory itself becomes a target
3445
3446	for _i in $(<) {
3447		local _t = [ geton $(_i) : LOCATE ] ;
3448		if $(_t) {
3449			MkDir_ $(_t) : $(_i) ;
3450		}
3451	}
3452}
3453
3454# Make the directories and all their parent directories.
3455# MkDir directories ;
3456rule MkDir
3457{
3458#Echo "MkDir got '" $(<) "'" ;
3459	# Ignore timestamps on directories: we only care if they exist.
3460	local _t= [ NormPaths $(<) ] ;
3461	local _i ;
3462
3463	for _i in $(_t) {
3464		MkDir_ $(_i) ;
3465	}
3466}
3467
3468# Internal MkDir
3469# MkDir dir [ : dependency ]
3470rule MkDir_
3471{
3472#Echo "MkDir_ got '" $(<) "' : '" $(>) "'" ;
3473
3474	if ! $(<:BS) {
3475		return ;
3476	}
3477
3478	local _t ;
3479	local _d = $(<:D) ;			# Form target id from path + last directory
3480	if ! $(_d) {
3481		_d = $(DOT) ;
3482	}
3483	local _t = [ NormIDstTargets $(<:BS) : $(_d) ] ;
3484
3485#Echo "MkDir_ target = '" $(_t) "' dependant = '" $(>) "'" ;
3486
3487	if $(>) {		# Thing that depends on this directory
3488		Depends $(>) : $(_t) ;
3489	}
3490	NoUpdate $(_t) ;
3491
3492	# Don't create . or any directory already created.
3493
3494	if $(_t) != $(DOT) && ! $($(_t)-mkdir)
3495	{
3496		# Cheesy gate to prevent multiple invocations on same dir
3497		# Arrange for jam dirs
3498		# MkDir1 has the actions
3499
3500#Echo "Making '" $(_t) "'" ;
3501		$(_t)-mkdir = true ;
3502		Depends dirs : $(_t) ;
3503		MkDir1 $(_t) ;
3504
3505		# Recursively make parent directories.
3506		# $(_t:P) = $(_t)'s parent, & we recurse until root
3507
3508		local _s = $(<:P) ;
3509#Echo "parent = '" $(_s) "'" ;
3510
3511		# Don't try to create A: or A:\ on windows
3512
3513		if $(NT)
3514		{
3515			switch $(_s)
3516			{
3517				case *:   : _s = ;
3518				case *:\\ : _s = ;
3519				case *:/  : _s = ;
3520			}
3521		}
3522
3523#Echo "parent now = '" $(_s) "'" ;
3524		if $(_s) = $(SLASH)		# Hmm. Was $(_s) = $(<). How could that work ?
3525		{
3526#Echo "At root, ignore '" $(_s) "' = '" $(<) "'" ;
3527			# The parent is the same as the dir.
3528			# We're at the root, which some OS's can't stat, so we mark
3529			# it as NotFile.
3530
3531			NotFile $(_s) ;
3532		}
3533		else if $(_s)
3534		{
3535			# There's a parent; recurse.
3536
3537#Echo "Doing Depends '" $(_t) "' with '" [ _TargetIDs $(_s) ] "'" ;
3538			Depends $(_t) : [ _TargetIDs $(_s) ] ;
3539#Echo "Recursing with parent '" $(_s) "'" ;
3540			MkDir_ $(_s) ;
3541		}
3542	} else {
3543#Echo "Not making '" $(_t) "' because it's dot, or it's been made before" ;
3544	}
3545}
3546
3547# Deal with a single source to object.
3548# Object object : sources : flags : defines : hdrpaths
3549rule Object
3550{
3551	#Echo "Object got " $(<) "and" $(>) "' flags '" $(3) "' defs '" $(4) "' hds '" $(5) "'" ;
3552
3553	# Normalize target names and set Grist LOCATE and SOURCE
3554	local _t = [ NormDstTargets $(<[1]:S=$(SUFOBJ)) ] ;
3555	local _s = [ NormSrcTargets $(>[1]) ] ;
3556	local _dot ;
3557
3558#Echo "Object norms " $(_t) "and" $(_s) ;
3559
3560	Depends $(_t) : $(_s) ;
3561	Depends obj : $(_t) ;
3562	Clean clean : $(_t) ;
3563	MakeLocate $(_t) ;
3564
3565	#  HDRS is used to provide the -I$(HDRS) options on compile.
3566
3567#Echo "Object sets HDRS on '" $(_t) "' to HDRS '" $(HDRS) "' and P_HDRS '" $(P_HDRS) "'" ;
3568	HDRS on $(_t) = [ geton $(_t) : SEARCH ] [ NormPaths $(HDRS) ] $(P_HDRS) ;
3569#Echo "HDRS on '" $(_t) "' is now '" [ geton $(_t) : HDRS ] "'" ;
3570
3571	# we need to mark what the associated source is so
3572	# that if we want to change HDRS we can propogate
3573	# it to the  #include files.
3574
3575	SOURCE on $(_t) = $(_s) ;		# ~~99 should check source is the same as any previous ?
3576
3577	# handle #includes for source: Jam scans for headers with
3578	# the regexp pattern $(HDRSCAN) and then invokes $(HDRRULE)
3579	# with the scanned file as the target and the found headers
3580	# as the sources.  HDRSEARCH is the value of SEARCH used for
3581	# the found header files.
3582
3583	HDRRULE on $(_s) = HdrRule ;
3584	HDRSCAN on $(_s) = $(HDRPATTERN) ;
3585
3586	# Construct HDRSEARCH so that we can latter add to HDRS
3587	local _dot = [ geton $(_s) : NOMLOC ] ;
3588	if ! $(_dot) { _dot = $(DOT) ; }
3589	HDRSEARCH1 on $(_s) = $(_dot) ;
3590	HDRSEARCH2 on $(_s) = [ NormPaths $(HDRS) ] $(P_HDRS) ;
3591	HDRSEARCH3 on $(_s) = [ NormPaths $(STDHDRS) ] ;
3592	HDRSEARCH on $(_s) = [ geton $(_s) : HDRSEARCH1 ] [ geton $(_s) : HDRSEARCH2 ]
3593	                     [ geton $(_s) : HDRSEARCH3 ] ;
3594#Echo "Object: HDRSEARCH on '" $(_s) "' set to '" [ geton $(_s) : HDRSEARCH ] "'" ;
3595
3596	# propagate target specific-defines
3597
3598	DEFINES on $(_t) = $(P_DEFINES) $(DEFINES) ;
3599
3600	# if source is not .c, generate .c with specific rule
3601
3602	switch $(_s:S)
3603	{
3604		case .asm : As_ $(_t) : $(_s) ;
3605
3606		case .c :	Cc_ $(_t) : $(_s) ;
3607
3608		case .C :	C++_ $(_t) : $(_s) ;
3609		case .cc :	C++_ $(_t) : $(_s) ;
3610		case .cpp : C++_ $(_t) : $(_s) ;
3611		case .cxx : C++_ $(_t) : $(_s) ;
3612
3613		case .m :	Cc_ $(_t) : $(_s) ;
3614
3615		case .f :	Fortran_ $(_t) : $(_s) ;
3616
3617		case .l :	{
3618						local _c = $(_t:S=.c) ;
3619						CopyTarget $(_c) : $(_t) ;	# Transfer LOCATE, SEARCH, NOMLOC
3620						Lex_ $(_c) : $(_s) ;
3621						Cc_ $(_t) : $(_c) ;
3622					}
3623
3624		case .s :	As_ $(_t) : $(_s) ;
3625
3626		case .y :	{
3627						local _c = $(_t:S=$(YACCGEN)) ;
3628						CopyTarget $(_c) : $(_t) ;	# Transfer LOCATE, SEARCH, NOMLOC
3629						Yacc_ $(_c) : $(_s) ;
3630						Cc_ $(_t) : $(_c) ;
3631					}
3632		# Note user object gets normalized target and source
3633		case * :	UserObject $(_t) : $(_s) : $(3) : $(4) : $(5) ;
3634	}
3635#Echo ;
3636
3637	if $(3) {
3638		ObjectCcFlags $(<) : $(3) ;
3639		switch $(_s:S)
3640		{
3641			case .c :	ObjectCcFlags $(_t) : $(3) ;
3642
3643			case .C :	ObjectC++Flags $(_t) : $(3) ;
3644			case .cc :	ObjectC++Flags $(_t) : $(3) ;
3645			case .cpp : ObjectC++Flags $(_t) : $(3) ;
3646			case .cxx : ObjectC++Flags $(_t) : $(3) ;
3647
3648			case .l :	ObjectCcFlags $(_t) : $(3) ;
3649			case .y :	ObjectCcFlags $(_t) : $(3) ;
3650		}
3651	}
3652	if $(4) {
3653		ObjectDefines $(<) : $(4) ;
3654	}
3655	if $(5) {
3656		ObjectHdrs $(<) : $(5) ;
3657	}
3658}
3659
3660# Add extra CCFLAGS to objects
3661# ObjectCcFlags objects : flags ;
3662rule ObjectCcFlags
3663{
3664#Echo "ObjectCcFLags got '" $(<) "' and '" $(>) "'" ;
3665	local _t = [ NormDstTargets $(<:S=$(SUFOBJ)) ] ;
3666	local _i ;
3667
3668	for _i in $(_t) {
3669		CCFLAGS1 on $(_i) += $(>) ;
3670		CCFLAGS on $(_i) = [ geton $(_i) : CCFLAGS1 ] [ geton $(_i) : CCFLAGS2 ] ;
3671#Echo "object '" $(_i) "' got CCFLAGS1 '" [ geton $(_i) : CCFLAGS1 ] "' and CCFLAGS2 '" [ geton $(_i) : CCFLAGS2 ] "' for total CCFLAGS '" [ geton $(_i) : CCFLAGS ] "'" ;
3672	}
3673}
3674
3675# Add extra PREF_CCFLAGS to objects
3676# ObjectPrefCcFlags objects : flags ;
3677rule ObjectPrefCcFlags
3678{
3679#Echo "ObjectPrefCcFLags got '" $(<) "' and '" $(>) "'" ;
3680	if ! $(P_PREF_CCFLAGS) {
3681		local _t = [ NormDstTargets $(<:S=$(SUFOBJ)) ] ;
3682		local _i ;
3683
3684		for _i in $(_t) {
3685			CCFLAGS2 on $(_i) += $(>) ;
3686			CCFLAGS on $(_i) = [ geton $(_i) : CCFLAGS1 ] [ geton $(_i) : CCFLAGS2 ] ;
3687#Echo "object '" $(_i) "' got CCFLAGS1 '" [ geton $(_i) : CCFLAGS1 ] "' and CCFLAGS2 '" [ geton $(_i) : CCFLAGS2 ] "' for total CCFLAGS '" [ geton $(_i) : CCFLAGS ] "'" ;
3688		}
3689	}
3690}
3691
3692# Add extra C++FLAGS to objects
3693# ObjectC++Flags objects : flags ;
3694rule ObjectC++Flags
3695{
3696#Echo "ObjectC++FLags got '" $(<) "' and '" $(>) "'" ;
3697	local _t = [ NormDstTargets $(<:S=$(SUFOBJ)) ] ;
3698	local _i ;
3699
3700	for _i in $(_t) {
3701		C++FLAGS1 on $(_i) += $(>) ;
3702		C++FLAGS on $(_i) = [ geton $(_i) : C++FLAGS1 ] [ geton $(_i) : C++FLAGS2 ] ;
3703	}
3704}
3705
3706# Add extra PREF_C++FLAGS to objects
3707# ObjectPrefC++Flags objects : flags ;
3708rule ObjectPrefC++Flags
3709{
3710#Echo "ObjectPrefC++FLags got '" $(<) "' and '" $(>) "'" ;
3711	if ! $(P_PREF_C++FLAGS) {
3712		local _t = [ NormDstTargets $(<:S=$(SUFOBJ)) ] ;
3713		local _i ;
3714
3715		for _i in $(_t) {
3716			C++FLAGS2 on $(_i) += $(>) ;
3717			C++FLAGS on $(_i) = [ geton $(_i) : C++FLAGS1 ] [ geton $(_i) : C++FLAGS2 ] ;
3718		}
3719	}
3720}
3721
3722# Add extra DEFINES to objects
3723# ObjectDefines objects : defines ;
3724rule ObjectDefines
3725{
3726	# must reformat CCDEFS according to current defines
3727
3728	local s = [ NormDstTargets $(<:S=$(SUFOBJ)) ] ;
3729
3730	DEFINES on $(s) += $(>) ;
3731	CCDEFS on $(s) = [ on $(s) FDefines $(DEFINES) ] ;
3732}
3733
3734# Add extra header search paths to objects.
3735# ObjectHdrs objects : dirs ;
3736rule ObjectHdrs
3737{
3738#Echo "ObjectHdrs HDRS got '" $(<) "' and '" $(>) "'" ;
3739	# Add to HDRS for CCHDRS benefit.
3740	local _t = [ NormDstTargets $(<:S=$(SUFOBJ)) ] ;
3741	local _h = [ NormSrcPaths $(>) ] ;
3742	local _i _s ;
3743
3744#Echo "ObjectHdrs changed  HDRS on '" $(_t) "' from '" [ geton $(_t) : HDRS ] "'" ;
3745	HDRS on $(_t) += $(_h) ;
3746#Echo " to '" [ geton $(_t) : HDRS ] "'" ;
3747	for _i in $(_t) {
3748		_s = [ geton $(_i) : SOURCE ] ;
3749#Echo " obj '" $(_i) "' has source '" $(_s) "'" ;
3750#Echo " ObjectHdrs changed HDRSEARCH on '" $(_s) "' from '" [ geton $(_s) : HDRSEARCH ] "'" ;
3751		HDRSEARCH2 on $(_s) += $(_h) ;
3752		HDRSEARCH on $(_s) = [ geton $(_s) : HDRSEARCH1 ] [ geton $(_s) : HDRSEARCH2 ]
3753		                     [ geton $(_s) : HDRSEARCH3 ] ;
3754#Echo "  to '" [ geton $(_s) : HDRSEARCH ] "'" ;
3755		CCHDRS on $(_i) = [ on $(_i) FIncludes $(HDRS) ] ;
3756	}
3757}
3758
3759# Set KEEPOBJS on the given headers
3760# ObjectKeep objects ;
3761rule ObjectKeep
3762{
3763#Echo "ObjectKeep got '" $(<) "" ;
3764	local _t = [ NormDstTargets $(<:S=$(SUFOBJ)) ] ;
3765
3766	KEEPOBJS on $(_t) = "true" ;
3767#Echo "ObjectHdrs changed  KEEPOBJS on '" $(_t) "' to '" [ geton $(_t[1]) : KEEPOBJS ] "'" ;
3768}
3769
3770# Create object files from sources.
3771# Objects sources : flags : defines : hdrpaths ;
3772rule Objects
3773{
3774#Echo "Objects got src '" $(<) "' flags '" $(2) "' def '" $(3) "' hdrs '" $(4) "'" ;
3775	local _i ;
3776
3777	for _i in $(<) {
3778		Object $(_i) : $(_i) : $(2) : $(3) : $(4) ;
3779	}
3780}
3781
3782# Marks sources as temporary with the TEMPORARY rule, and deletes sources once targets  are built.
3783# Must be the last rule invoked on targets.
3784# RmTemps targets : sources ;
3785rule RmTemps
3786{
3787	local _s = [ NormPaths $(>) ] ;
3788	if $(_s) {
3789		RmTemps_ $(<) : $(_s) ;
3790	}
3791}
3792
3793# internal RmTemps
3794rule RmTemps_
3795{
3796	Temporary $(>) ;
3797}
3798
3799# Setuid
3800rule Setuid
3801{
3802	local _t = [ NormPaths $(>:S=$(SUFEXE)) ] ;
3803	MODE on $(_t) = 4755 ;
3804}
3805
3806# Shell
3807rule Shell
3808{
3809	local _t = [ NormTargs $(>:S=$(SUFSH)) ] ;
3810	local _s = [ NormSrcTargets $(>[1]) ] ;
3811	Shell_ $(_t) : $(_s) ;
3812}
3813
3814# internal Shell
3815rule Shell_
3816{
3817	Depends shell : $(<) ;
3818	Depends $(<) : $(>) ;
3819	MODE on $(<) = $(SHELLMODE) ;
3820	Clean clean : $(<) ;
3821	Chmod_ $(<) ;
3822}
3823
3824# SoftLink
3825rule SoftLink
3826{
3827	local _t = [ NormDstTargets $(<) ] ;
3828	local _s = [ NormSrcTargets $(>) ] ;
3829
3830	SoftLink_ $(_t) : $(_s) ;
3831}
3832
3833# internal SoftLink
3834rule SoftLink_
3835{
3836	Depends files : $(<) ;
3837	Depends $(<) : $(>) ;
3838	Clean clean : $(<) ;
3839}
3840
3841#Adds flags to mark symbols as undefined on link command for images
3842rule Undefines
3843{
3844	local _t = [ NormDstTargets $(<) ] ;
3845	UNDEFS on [ $(_t:S=$(SUFEXE)) ] += $(UNDEFFLAG)$(>) ;
3846}
3847
3848# User routine to handle objects. Note that
3849# targets and sources are in normalized form.
3850rule UserObject
3851{
3852	Exit "Unknown suffix on" $(>) "- see UserObject rule in Jamfile(5)." ;
3853}
3854
3855# Yacc source.c : source.y ;
3856rule Yacc
3857{
3858	local _t = [ NormDstTargets $(<[1]) ] ;
3859	local _s = [ NormSrcTargets $(>[1]) ] ;
3860
3861	Yacc_ $(_t) : $(_s) ;
3862}
3863
3864# internal Yacc
3865rule Yacc_
3866{
3867	local _h ;
3868
3869	_h = $(<:S=.h) ;
3870	CopyTarget $(_h) : $(<) ;	# Transfer LOCATE, SEARCH, NOMLOC
3871
3872	# Some places don't have a yacc.
3873
3874	MakeLocate $(<) $(_h) ;
3875
3876	if $(YACC)
3877	{
3878		Depends $(<) : $(>) ;
3879		FakeFile_ $(_h) : $(<) ;		# .h is created with .c
3880		Yacc1_ $(<) $(_h) : $(>) ;
3881		YaccMv_ $(<) $(_h) ;
3882		Clean clean : $(<) $(_h) ;
3883	}
3884
3885	# make sure someone includes $(_h) else it will be
3886	# a deadly independent target
3887
3888	Includes $(<) : $(_h) ;
3889}
3890
3891# Aswig : source.i ;
3892# Argyll C class generator. Creates C class declaration source.h,
3893# C class partial implementation source_i.c, C++ class wrapper
3894# declaration & implementation source.hpp.
3895rule Aswig
3896{
3897#Echo "Aswig called with $(>) " ;
3898	local _s = [ NormSrcTargets $(>[1]) ] ;
3899
3900	Aswig_ : $(_s) ;
3901}
3902
3903# internal Aswig
3904rule Aswig_
3905{
3906#Echo "Aswig_ called with $(>)" ;
3907	local _i = $(>[1]) ;
3908	local _h = $(_i:S=.h) ;
3909	CopyTarget $(_h) : $(_i) ;		# Transfer LOCATE, SEARCH, NOMLOC
3910	local _c = $(_i:B=$(_i:B)_i:S=.c) ;
3911	CopyTarget $(_c) : $(_i) ;		# Transfer LOCATE, SEARCH, NOMLOC
3912	local _hpp = $(_i:S=.hpp) ;
3913	CopyTarget $(_hpp) : $(_i) ;	# Transfer LOCATE, SEARCH, NOMLOC
3914
3915#Echo "Aswig_ creates $(_h) $(_c) $(_hpp) from $(_i) " ;
3916
3917	MakeLocate $(_h) $(_c) $(_hpp) ;
3918
3919	Depends $(_h) : $(_i) ;
3920	FakeFile_ $(_c) : $(_h) ;		# _i.c is created with .h
3921	FakeFile_ $(_hpp) : $(_h) ;		# _.hpp is created with .h
3922	Aswig1_ $(_h) : $(_i) ;
3923	Clean clean : $(_h) $(_c) $(_hpp) ;
3924}
3925
3926#
3927# Utility rules; no side effects on these
3928#
3929
3930# FReverse a1 a2 a3 ... ;
3931# return ... a3 a2 a1 ;
3932rule FReverse
3933{
3934
3935	local _i _o = ;
3936	for _i in $(1)
3937	{
3938		_o = $(_i) $(_o) ;
3939	}
3940	return $(_o) ;
3941}
3942
3943# Strip common initial elements of variables v1 and v2.
3944# Modifies the variable values themselves.
3945# FStripCommon v1 : v2 ;
3946rule FStripCommon
3947{
3948
3949	if $($(<)[1]) && $($(<)[1]) = $($(>)[1])
3950	{
3951		$(<) = $($(<)[2-]) ;
3952		$(>) = $($(>)[2-]) ;
3953		FStripCommon $(<) : $(>) ;
3954	}
3955}
3956
3957# Append suffix if there is not already one
3958# E.g., "FAppendSuffix yacc lex foo.bat : $(SUFEXE) ;"
3959# returns (yacc,lex,foo.bat) on Unix and
3960# (yacc.exe,lex.exe,foo.bat) on NT.
3961# FAppendSuffix files : suffix ;
3962rule FAppendSuffix
3963{
3964
3965	if $(>)
3966	{
3967		local _i _o ;
3968
3969		for _i in $(<)
3970		{
3971			if $(_i:S)
3972			{
3973				_o += $(_i) ;
3974			}
3975			else
3976			{
3977				_o += $(_i:S=$(>)) ;
3978			}
3979		}
3980		return $(_o) ;
3981	}
3982	else
3983	{
3984		return $(<) ;
3985	}
3986}
3987
3988# return a1 a2 ... with any empty elements deleted
3989# FDelEmpty a1 a2 ... ;
3990rule FDelEmpty
3991{
3992
3993	local _i _o = ;
3994	for _i in $(<)
3995	{
3996		if $(_i) {
3997			_o += $(_i) ;
3998		}
3999	}
4000	return $(_o) ;
4001}
4002
4003#
4004# Operating system specific utility rules
4005# First, the (generic) UNIX versions
4006#
4007
4008rule FQuote { return \\\"$(<)\\\" ; }
4009rule FDefines { local _t = [ FDelEmpty $(<) ] ; return -D$(_t) ; }
4010rule FIncludes { local _t = [ FDelEmpty $(<) ] ; return -I$(_t) ; }
4011
4012if $(OS2)
4013{
4014	rule FQuote { return \"$(<)\" ; }
4015	rule FIncludes { local _t = [ FDelEmpty $(<) ] ; return /I$(_t) ; }
4016}
4017
4018else if $(NT)
4019{
4020	if ! $(MINGW) {
4021		rule FDefines { local _t = [ FDelEmpty $(<) ] ; return /D$(_t) ; }
4022		rule FIncludes { local _t = [ FDelEmpty $(<) ] ; return /I$(_t) ; }
4023	}
4024}
4025
4026else if $(MAC)
4027{
4028	rule FQuote { return \"$(<)\" ; }
4029	rule FDefines { local _t = [ FDelEmpty $(<) ] ; return "-define '$(_t)'" ; }
4030	rule FIncludes { local _t = [ FDelEmpty $(<) ] ; return \"$(_t:J=,)\" ; }
4031}
4032
4033else if $(VMS)
4034{
4035	rule FQuote { return \"\"\"$(<)\"\"\" ; }
4036	rule FDefines { local _t = [ FDelEmpty $(<) ] ; return "/define=( $(_t:J=,) )" ; }
4037	rule FIncludes { local _t = [ FDelEmpty $(<) ] ; return "/inc=( $(_t:J=,) )" ; }
4038
4039	rule FDirName
4040	{
4041			local _s _i ;
4042
4043			# Turn individual elements in $(<) into a usable path.
4044
4045			if ! $(<)
4046			{
4047				_s = $(DOT) ;
4048			}
4049			else
4050			{
4051				# This handles the following cases:
4052				#		 a -> [.a]
4053				#		 a b c -> [.a.b.c]
4054				#		 x: -> x:
4055				#		 x: a -> x:[a]
4056				#		 x:[a] b -> x:[a.b]
4057
4058				switch $(<[1])
4059				{
4060					case *:* : _s = $(<[1]) ;
4061					case \\[*\\] : _s = $(<[1]) ;
4062					case * : _s = [.$(<[1])] ;
4063				}
4064
4065				for _i in [.$(<[2-])]
4066				{
4067					_s = $(_i:R=$(_s)) ;
4068				}
4069			}
4070
4071			return $(_s) ;
4072	}
4073}
4074
4075#
4076# Actions
4077#
4078
4079#
4080# First the defaults
4081#
4082
4083actions updated together piecemeal Archive
4084{
4085	$(AR) $(<) $(>)
4086}
4087
4088actions together ArchiveArchive
4089{
4090	mkdir .jamArchiveArchive$PPID
4091	cp $(>) .jamArchiveArchive$PPID
4092	cd .jamArchiveArchive$PPID
4093	for i in $(>:BS)
4094	do
4095    	ar -xo $i
4096	done
4097    cd ..
4098	ar -r $(<) .jamArchiveArchive$PPID/*.o
4099	rm -rf .jamArchiveArchive$PPID
4100}
4101
4102actions As
4103{
4104	$(AS) $(ASFLAGS) $(ASHDRS) -o $(<) $(>)
4105}
4106
4107actions C++_
4108{
4109	$(C++) -c -o $(<) $(C++FLAGS) $(CCDEFS) $(CCHDRS) $(>)
4110}
4111
4112actions Cc_
4113{
4114	$(CC) -c -o $(<) $(CCFLAGS) $(CCDEFS) $(CCHDRS) $(>)
4115}
4116
4117actions Chgrp_
4118{
4119	$(CHGRP) $(GROUP) $(<)
4120}
4121
4122actions Chmod1
4123{
4124	$(CHMOD) $(MODE) $(<)
4125}
4126
4127actions Chown_
4128{
4129	$(CHOWN) $(OWNER) $(<)
4130}
4131
4132actions piecemeal together existing Clean
4133{
4134	$(RM) $(>)
4135}
4136
4137actions File_
4138{
4139	$(CP) $(>) $(<)
4140}
4141
4142#actions FakeFile_ { }
4143
4144actions GenFile1
4145{
4146	$(>[1]) $(<) $(>[2-])
4147}
4148
4149actions GenFileND1
4150{
4151	$(>)
4152}
4153
4154actions GenFileNND1
4155{
4156	$(>)
4157}
4158
4159actions CreateCatFile_
4160{
4161	$(CP) /Y nul $(<) > nul
4162}
4163
4164actions CatToFile_
4165{
4166	echo $(>) >> $(<)
4167}
4168
4169actions Fortran_
4170{
4171	$(FORTRAN) $(FORTRANFLAGS) -o $(<) $(>)
4172}
4173
4174actions HardLink_
4175{
4176	$(RM) $(<) && $(LN) $(>) $(<)
4177}
4178
4179actions Install
4180{
4181	$(CP) $(>) $(<)
4182}
4183
4184actions Lex_
4185{
4186	$(LEX) $(>)
4187}
4188
4189actions LexMv_
4190{
4191	$(MV) lex.yy.c $(<)
4192}
4193
4194#	Old: $(LINK) $(LINKFLAGS) $(LINKOUTFLAG)$(<) $(UNDEFS) $(>) $(LINKOBJS) $(LINKLIBS) $(LINKSHLIBS) $(STDLIBS)
4195#	$(LINK) $(LINKOUTFLAG)$(<) $(UNDEFS) $(>) $(LINKFLAGS) $(LINKOBJS) $(LINKLIBS) $(LINKSHLIBS) $(STDLIBS)
4196actions Link_ bind LINKOBJS LINKLIBS LINKSHLIBS
4197{
4198	$(LINK) $(LINKOUTFLAG)$(<) $(UNDEFS) $(>) $(LINKOBJS) $(LINKLIBS) $(LINKSHLIBS) $(LINKFLAGS) $(STDLIBS)
4199}
4200
4201if $(OS) = MACOSX {		# OS X version of ld
4202
4203	# Link .o and .a into a .dylib
4204	# gcc -dynamiclib -Wl,-headerpad_max_install_names,-undefined,dynamic_lookup,-compatibility_version,1.0,-current_version,1.0,-install_name,/usr/local/lib/libfoo.1.dylib -o libfoo.1.dylib $(OBJ)
4205	# -Wl,-install_name,@executable_path ???
4206	actions ShLink_ bind SHLINKOBJS SHLINKLIBS SHLINKSHLIBS
4207	{
4208		$(LINK) -dynamiclib -Wl,-undefined,dynamic_lookup,-install_name,$(SHLINKSEARCHEXEPATH)$(<[1]:BS) $(LINKOUTFLAG)$(<[1]) $(>) $(SHLINKOBJS) $(SHLINKLIBS) $(SHLINKSHLIBS) $(SHLINKFLAGS) $(SHSTDLIBS)
4209	}
4210
4211} else {	# General gcc
4212
4213	# Link .o and .a into a .so
4214	# To set .so search path: -Wl,-rpath,$(LINKSHLIBS:D)
4215	# or set LD_LIBRARY_PATH
4216	# or set /etc/ld.so.conf.d/*.conf
4217	# To set .so search path (after flag):  -Wl,-soname=$(<[1]:BS)
4218# Old:	$(LINK) -shared -Wl,-soname=$(SHLINKSEARCHEXEPATH)$(<[1]:BS) $(SHLINKFLAGS) $(LINKOUTFLAG)$(<[1]) $(>) $(SHLINKOBJS) $(SHLINKLIBS) $(SHLINKSHLIBS) $(SHSTDLIBS)
4219	actions ShLink_ bind SHLINKOBJS SHLINKLIBS SHLINKSHLIBS
4220	{
4221		$(LINK) -shared -Wl,-soname=$(SHLINKSEARCHEXEPATH)$(<[1]:BS) $(LINKOUTFLAG)$(<[1]) $(>) $(SHLINKOBJS) $(SHLINKLIBS) $(SHLINKSHLIBS) $(SHLINKFLAGS) $(SHSTDLIBS)
4222	}
4223}
4224
4225actions MkDir1
4226{
4227	$(MKDIR) $(<)
4228}
4229
4230actions together Ranlib
4231{
4232	$(RANLIB) $(<)
4233}
4234
4235actions quietly updated piecemeal together RmTemps_
4236{
4237	$(RM) $(>)
4238}
4239
4240actions Shell_
4241{
4242	$(AWK) '
4243		NR == 1 { print "$(SHELLHEADER)" }
4244		NR == 1 && /^[#:]/ { next }
4245		/^##/ { next }
4246		{ print }
4247	' < $(>) > $(<)
4248}
4249
4250actions SoftLink_
4251{
4252	$(RM) $(<) && $(LN) -s $(>) $(<)
4253}
4254
4255actions Yacc1_
4256{
4257	$(YACC) $(YACCFLAGS) $(>)
4258}
4259
4260actions YaccMv_
4261{
4262	$(MV) $(YACCFILES).c $(<[1])
4263	$(MV) $(YACCFILES).h $(<[2])
4264}
4265
4266actions Aswig1_
4267{
4268	aswig $(ASWIGFLAGS) -c++ -a2c $(>)
4269}
4270
4271#
4272# RELOCATE - for compilers with broken -o flags
4273#
4274
4275if $(RELOCATE)
4276{
4277	actions C++_
4278	{
4279		$(C++) -c $(C++FLAGS) $(CCDEFS) $(CCHDRS) $(>)
4280	}
4281
4282	actions Cc_
4283	{
4284		$(CC) -c $(CCFLAGS) $(CCDEFS) $(CCHDRS) $(>)
4285	}
4286
4287	actions ignore CcMv
4288	{
4289		[ $(<) != $(>:BS=$(SUFOBJ)) ] && $(MV) $(>:BS=$(SUFOBJ)) $(<)
4290	}
4291}
4292
4293#
4294# NOARUPDATE - can't update an archive
4295#
4296
4297if $(NOARUPDATE)
4298{
4299	actions Archive
4300	{
4301		$(AR) $(<) $(>)
4302	}
4303}
4304
4305#
4306# UNIX specific actions
4307#
4308
4309if $(UNIX)
4310{
4311	actions GenFile1
4312	{
4313		PATH="$PATH:."
4314		$(>[1]) $(<) $(>[2-])
4315	}
4316
4317	actions CreateCatFile_
4318	{
4319		$(CP) /dev/null $(<)
4320	}
4321
4322	actions CatToFile_
4323	{
4324		echo "$(>)" >> $(<)
4325	}
4326
4327	# Make OS X GUI apps work
4328	if $(OS) = MACOSX
4329	{
4330
4331		# Used to use /Developer/Tools/Rez -t APPL Carbon.r -o $(<)
4332		# but this no longer works in OS X 10.5, and we don't need this
4333		# stuff with TransformProcessType()
4334		# Another alternative is to use link option "-sectcreate __TEXT __info_plist Info.plist" ???
4335		# to embed the plist in the executable, but not sure what should be in plist.
4336		# Pure GUI app
4337		actions GUIAPP
4338		{
4339			rm -rf $(<).app
4340			mkdir -p $(<).app
4341			mkdir $(<).app/Contents
4342			mkdir $(<).app/Contents/Resources
4343			mkdir $(<).app/Contents/MacOS
4344			echo APPLnone > $(<).app/Contents/PkgInfo
4345			mv $(<) $(<).app/Contents/MacOS
4346			chmod 755 $(<).app/Contents/MacOS/$(<:BS)
4347			cat << EOF > $(<).app/Contents/info.plist
4348<?xml version="1.0" encoding="UTF-8"?>
4349<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
4350<plist version="0.9">
4351<dict>
4352        <key>CFBundleName</key>
4353        <string>$(<:BS)</string>
4354        <key>CFBundlePackageType</key>
4355        <string>APPL</string>
4356        <key>CFBundleVersion</key>
4357        <string>59</string>
4358        <key>CFBundleShortVersionString</key>
4359        <string>1.1</string>
4360        <key>CFBundleSignature</key>
4361        <string>none</string>
4362</dict>
4363</plist>
4364EOF
4365			cat << EOF > $(<)
4366#!/bin/sh
4367\$0.app/Contents/MacOS/$(<:BS)
4368EOF
4369			chmod 755 $(<)
4370		}
4371	}
4372}
4373
4374#
4375# NT specific actions
4376#
4377
4378if $(NT)
4379{
4380	# Ensure timestamp is updated
4381
4382	actions File_
4383	{
4384		$(CP) /b $(>) + nul $(<) > nul
4385	}
4386
4387	actions Install
4388	{
4389		$(CP) /b $(>) + nul $(<) > nul
4390	}
4391}
4392
4393if $(NT) && $(MSVCNT)
4394{
4395#	actions updated together piecemeal Archive
4396#	{
4397#		if exist $(<) set _$(<:B)_=$(<)
4398#		$(AR) /out:$(<) %_$(<:B)_% $(>)
4399#	}
4400
4401	# This is slightly dodgy if you've got multiple
4402	# libraries with the same name in different directories with
4403	# jam -j n, or you have .obj's distinguished only by their directory
4404	# being combined into the same library, but it overcomes
4405	# the problem of lib not updating a library properly if
4406	# jam is involked from different directories.
4407	actions updated together piecemeal Archive
4408	{
4409		if exist $(<:BS)_ RMDIR /S/Q $(<:BS)_
4410		MKDIR $(<:BS)_
4411		for %%i in ( $(>) ) do COPY %%i $(<:BS)_ 1>nul
4412		if exist $(<) set _$(<:B)_=$(<)
4413		$(AR) /out:$(<) %_$(<:B)_% $(<:BS)_\*
4414		DEL /F/S/Q $(<:BS)_\* 1>nul
4415		RMDIR /Q $(<:BS)_
4416	}
4417
4418	actions together ArchiveArchive
4419	{
4420		$(AR) /out:$(<) $(>)
4421	}
4422
4423	actions As
4424	{
4425		$(AS) /Ml /p /v /w2 $(>) $(<) ,nul,nul;
4426	}
4427
4428	actions Cc_
4429	{
4430		$(CC) /c /Fo$(<) $(CCFLAGS) $(CCDEFS) $(CCHDRS) /I$(STDHDRS) $(>)
4431	}
4432
4433	actions C++_
4434	{
4435		$(C++) /c /Fo$(<) $(C++FLAGS) $(CCDEFS) $(CCHDRS) /I$(STDHDRS) /Tp $(>)
4436	}
4437
4438	actions Link_ bind LINKOBJS LINKLIBS LINKSHLIBS
4439	{
4440		$(LINK) $(LINKFLAGS) $(P_LINKFLAGS) /out:$(<) $(UNDEFS) $(>) $(LINKOBJS) $(LINKLIBS) $(LINKSHLIBS) $(STDLIBS)
4441	}
4442
4443	# Create DLL using export attribute
4444	actions ShLink_  bind SHLINKOBJS SHLINKLIBS SHLINKSHLIBS
4445	{
4446		$(LINK) /DLL $(SHLINKFLAGS) /out:$(<[1]) $(>) $(SHLINKOBJS) $(SHLINKLIBS) $(SHLINKSHLIBS) $(SHSTDLIBS)
4447	}
4448
4449	# Create DLL using .def file
4450	actions ShLinkDef_ bind SHLINKDEFFILE SHLINKOBJS SHLINKLIBS SHLINKSHLIBS
4451	{
4452		$(LINK) /DLL /DEF:$(SHLINKDEFFILE) $(SHLINKFLAGS) /out:$(<[1]) $(>) $(SHLINKOBJS) $(SHLINKLIBS) $(SHLINKSHLIBS) $(SHSTDLIBS)
4453	}
4454}
4455else if $(NT) && $(MSVC)
4456{
4457	actions updated together piecemeal Archive
4458	{
4459		$(AR) $(<) -+$(>)
4460	}
4461
4462	actions Cc_
4463	{
4464		$(CC) /c /Fo$(<) $(CCFLAGS) $(CCDEFS) $(CCHDRS) $(>)
4465	}
4466
4467	actions C++_
4468	{
4469		$(C++) /c /Fo$(<) $(C++FLAGS) $(CCDEFS) $(CCHDRS) /Tp $(>)
4470	}
4471
4472	actions Link_ bind LINKOBJS LINKLIBS LINKSHLIBS
4473	{
4474		$(LINK) $(LINKFLAGS) $(P_LINKFLAGS) /out:$(<) $(UNDEFS) $(>) $(LINKOBJS) $(LINKLIBS) $(LINKSHLIBS) $(STDLIBS)
4475	}
4476}
4477else if $(NT) && $(BCCROOT)
4478{
4479	actions updated together piecemeal Archive
4480	{
4481		$(AR) $(<) -+$(>)
4482	}
4483
4484	actions Link_ bind LINKOBJS LINKLIBS LINKSHLIBS
4485	{
4486		$(LINK) -e$(<) $(LINKFLAGS) $(P_LINKFLAGS) $(UNDEFS) -L$(STDLIBS) $(LINKLIBS) $(LINKSHLIBS) $(>) $(LINKOBJS)
4487	}
4488
4489	actions C++_
4490	{
4491		$(C++) -c -o$(<) $(C++FLAGS) $(CCDEFS) $(CCHDRS) $(>)
4492	}
4493
4494	actions Cc_
4495	{
4496		$(CC) -c -o$(<) $(CCFLAGS) $(CCDEFS) $(CCHDRS) $(>)
4497	}
4498}
4499
4500else if $(NT) && $(MINGW) {
4501
4502	# Create DLL using export attribute
4503	actions ShLink_  bind SHLINKOBJS SHLINKLIBS SHLINKSHLIBS
4504	{
4505		$(LINK) -shared $(SHLINKFLAGS) $(LINKOUTFLAG)$(<[1]) -Wl,--out-implib,$(<[2]) $(>) $(SHLINKOBJS) $(SHLINKLIBS) $(SHLINKSHLIBS) $(SHSTDLIBS)
4506	}
4507	# Create DLL using .def file
4508	actions ShLinkDef_ bind SHLINKOBJS SHLINKLIBS SHLINKSHLIBS SHLINKDEFFILE
4509	{
4510		$(LINK) -shared $(SHLINKFLAGS) $(LINKOUTFLAG)$(<[1]) -Wl,--out-implib,$(<[2]) $(>) $(SHLINKOBJS) $(SHLINKLIBS) $(SHLINKSHLIBS) $(SHSTDLIBS) $(SHLINKDEFFILE)
4511	}
4512}
4513
4514#
4515# OS2 specific actions
4516#
4517
4518else if $(OS2) && $(WATCOM)
4519{
4520	actions together piecemeal Archive
4521	{
4522		$(AR) $(<) +-$(>)
4523	}
4524
4525	actions Cc_
4526	{
4527		$(CC) /Fo=$(<) $(CCFLAGS) $(CCDEFS) $(CCHDRS) $(>)
4528	}
4529
4530	actions C++_
4531	{
4532		$(C++) /Fo=$(<) $(C++FLAGS) $(CCDEFS) $(CCHDRS) $(>)
4533	}
4534
4535	actions Link_ bind LINKOBJS LINKLIBS LINKSHLIBS
4536	{
4537		$(LINK) $(LINKFLAGS) $(P_LINKFLAGS) /Fe=$(<) $(UNDEFS) $(>) $(LINKOBJS) $(LINKLIBS) $(LINKSHLIBS) $(STDLIBS)
4538	}
4539
4540	actions Shell_
4541	{
4542		$(CP) $(>) $(<)
4543	}
4544}
4545
4546#
4547# VMS specific actions
4548#
4549
4550else if $(VMS)
4551{
4552	actions updated together piecemeal Archive
4553	{
4554		lib/replace $(<) $(>[1]) ,$(>[2-])
4555	}
4556
4557	actions Cc_
4558	{
4559		$(CC)/obj=$(<) $(CCFLAGS) $(CCDEFS) $(CCHDRS) $(>)
4560	}
4561
4562	actions C++_
4563	{
4564		$(C++)/obj=$(<) $(C++FLAGS) $(CCDEFS) $(CCHDRS) $(>)
4565	}
4566
4567	actions piecemeal together existing Clean
4568	{
4569		$(RM) $(>[1]);* ,$(>[2-]);*
4570	}
4571
4572	actions together quietly CreLib
4573	{
4574		if f$search("$(<)") .eqs. "" then lib/create $(<)
4575	}
4576
4577	actions GenFile1
4578	{
4579		mcr $(>[1]) $(<) $(>[2-])
4580	}
4581
4582	actions Link_ bind LINKOBJS LINKLIBS LINKSHLIBS
4583	{
4584		$(LINK)/exe=$(<) $(LINKFLAGS) $(P_LINKFLAGS) $(>:J=,) ,$(LINKOBJS:J=,) ,$(LINKLIBS)/lib ,$(LINKSHLIBS)/lib ,$(STDLIBS)
4585	}
4586
4587	actions quietly updated piecemeal together RmTemps_
4588	{
4589		$(RM) $(>[1]);* ,$(>[2-]);*
4590	}
4591
4592	actions Shell_
4593	{
4594		$(CP) $(>) $(<)
4595	}
4596}
4597
4598#
4599# Mac specifc actions
4600#
4601
4602else if $(MAC)
4603{
4604	actions together Archive
4605	{
4606		$(LINK) -library -o $(<) $(>)
4607	}
4608
4609	actions Cc_
4610	{
4611		set -e MWCincludes $(CCHDRS)
4612		$(CC) -o $(<) $(CCFLAGS) $(CCDEFS) $(>)
4613	}
4614
4615	actions C++_
4616	{
4617		set -e MWCincludes $(CCHDRS)
4618		$(CC) -o $(<) $(C++FLAGS) $(CCDEFS) $(>)
4619	}
4620
4621	actions Link_ bind LINKOBJS LINKLIBS LINKSHLIBS
4622	{
4623		$(LINK) -o $(<) $(LINKOBJS) $(LINKFLAGS) $(P_LINKFLAGS) $(>) $(LINKLIBS) $(LINKSHLIBS) "$(STDLIBS)"
4624	}
4625}
4626
4627if $(WIN98)
4628{
4629	actions existing Clean
4630	{
4631		del $(>)
4632	}
4633}
4634
4635# =========================================
4636
4637# Now do Argyll init and read default Jamtop
4638DoInit ;
4639
4640#
4641# Now include the user's Jamfile.
4642#
4643
4644#PeerInclude $(DOT) ;
4645SubInclude $(DOT) ;
4646
4647