⛏️ index : haiku.git

#-------------------------------------------------------------------------------
# Link rule/action are overwritten as they don't handle linking files who's name
# contain spaces very well. Also adds resources and version to executable.
#-------------------------------------------------------------------------------
rule Link
{
	# Note: RESFILES must be set before invocation.

	local architecture = [ on $(1) return $(TARGET_PACKAGING_ARCH) ] ;
	if [ on $(1) return $(PLATFORM) ] = host {
		LINK on $(1) = $(HOST_LINK) ;
	 	LINKFLAGS on $(1) = $(HOST_LINKFLAGS) [ on $(1) return $(LINKFLAGS) ] ;
	} else {
		LINK on $(1) = $(TARGET_LINK_$(architecture)) ;
		LINKFLAGS on $(1) = $(TARGET_LINKFLAGS_$(architecture))
			[ on $(1) return $(LINKFLAGS) ] ;
	}

	HAIKU_TARGET_IS_EXECUTABLE on $(1) = 1 ;

 	NEEDLIBS on $(1) = [ on $(1) return $(NEEDLIBS) ] ;
 	LINKLIBS on $(1) = [ on $(1) return $(LINKLIBS) ] ;

	MODE on $(<) = $(EXEMODE) ;
	on $(1) XRes $(1) : $(RESFILES) ;
	if ! [ on $(1) return $(DONT_USE_BEOS_RULES) ] {
		SetType $(1) ;
		MimeSet $(1) : sharedObject ;
		SetVersion $(1) ;

		# For applications for the target also generate the MIME DB entries.
		if [ on $(1) return $(PLATFORM) ] != host
			&& [ on $(1) return $(RESFILES) ] {
			CreateAppMimeDBEntries $(1) ;
		}

		# If the generic attribute emulation is enabled, make sure the tool to
		# remove the attributes is built first.
		if $(HOST_RM_ATTRS_TARGET) {
			Depends $(1) : $(HOST_RM_ATTRS_TARGET) ;
		}
	}
	Chmod $(<) ;
}

# When using "real" attributes (i.e. BeOS attributes or xattr/extattr) on the
# host platform, unlinking the main target by gcc will also automatically get
# rid of the attributes. When using the generic attribute emulation, which
# uses separate files, we need to remove the target explicitely first, so that
# the attributes won't be "leaked".
if $(HAIKU_HOST_USE_XATTR) = 1 {
	actions Link bind NEEDLIBS LINK_BEGIN_GLUE LINK_END_GLUE VERSION_SCRIPT
	{
		$(LINK) $(LINKFLAGS) -o "$(1)" $(UNDEFS) "$(LINK_BEGIN_GLUE)" "$(2)" \
			"$(NEEDLIBS)" $(LINKLIBS) "$(LINK_END_GLUE)" \
			-Wl,--version-script,$(VERSION_SCRIPT)
	}
} else {
	actions Link bind NEEDLIBS LINK_BEGIN_GLUE LINK_END_GLUE VERSION_SCRIPT
	{
		$(RM) "$(1)"
		$(LINK) $(LINKFLAGS) -o "$(1)" $(UNDEFS) "$(LINK_BEGIN_GLUE)" "$(2)" \
			"$(NEEDLIBS)" $(LINKLIBS) "$(LINK_END_GLUE)" \
			-Wl,--version-script,$(VERSION_SCRIPT)
	}
}

rule Object
{
	# find out which headers and defines to use
	local headers ;
	local sysHeaders ;
	local defines ;

	on $(1) { # use on $(1) variable values
		if ! $(PLATFORM) in $(SUPPORTED_PLATFORMS) {
			return ;
		}

		# Save HDRS for -I$(HDRS) on compile.
		# We shouldn't need -I$(SEARCH_SOURCE) as cc can find headers
		# in the .c file's directory, but generated .c files (from
		# yacc, lex, etc) are located in $(LOCATE_TARGET), possibly
		# different from $(SEARCH_SOURCE).

		headers = $(HAIKU_CONFIG_HEADERS) $(SEARCH_SOURCE) $(SUBDIRHDRS)
			$(HDRS) ;
		sysHeaders = $(SUBDIRSYSHDRS) $(SYSHDRS) ;
		defines = $(DEFINES) ;

		if $(PLATFORM) = host {
			sysHeaders += $(HOST_HDRS) ;
			defines += $(HOST_DEFINES) ;

			if $(USES_BE_API) {
				sysHeaders += $(HOST_BE_API_HEADERS) ;
			}
		} else {
			local language ;
			if $(>:S) = .cpp || [ on $(2) return $(GENERATE_C++) ] {
				language = C++ ;
			}
			sysHeaders += [ FStandardHeaders $(TARGET_PACKAGING_ARCH) : $(language) ]
				$(TARGET_HDRS_$(TARGET_PACKAGING_ARCH)) ;
			defines += $(TARGET_DEFINES_$(TARGET_PACKAGING_ARCH))
				$(TARGET_DEFINES) ;
		}
	}

	# locate object and search for source

	LocalClean clean : $(<) ;

	MakeLocateDebug $(<) ;
	SEARCH on $(>) = $(SEARCH_SOURCE) ;

	HDRS on $(<) = $(headers) ;
	SYSHDRS on $(<) = $(sysHeaders) ;

	# handle #includes for source: Jam scans for headers with
	# the regexp pattern $(HDRSCAN) and then invokes $(HDRRULE)
	# with the scanned file as the target and the found headers
	# as the sources. HDRSEARCH is the value of SEARCH used for
	# the found header files. Finally, if jam must deal with
	# header files of the same name in different directories,
	# they can be distinguished with HDRGRIST.

	# $(SEARCH_SOURCE:E) is where cc first looks for #include
	# "foo.h" files. If the source file is in a distant directory,
	# look there. Else, look in "" (the current directory).

	HDRRULE on $(>) = HdrRule ;
	HDRSCAN on $(>) = $(HDRPATTERN) ;
	HDRSEARCH on $(>) = $(headers) $(sysHeaders) $(STDHDRS) ;
	HDRGRIST on $(>) = $(HDRGRIST) ;

	# propagate target specific-defines

	DEFINES on $(1) = $(defines) ;

	# if source is not .c, generate .c with specific rule

	switch $(>:S)
	{
		case .asm : As $(<) : $(>) ;
		case .nasm : AssembleNasm $(<) : $(>) ;
		case .c :	Cc $(<) : $(>) ;
		case .C :	C++ $(<) : $(>) ;
		case .cc :	C++ $(<) : $(>) ;
		case .cpp : C++ $(<) : $(>) ;
		case .f :	Fortran $(<) : $(>) ;
		case .l :	if [ on $(2) return $(GENERATE_C++) ] {
						InheritPlatform $(<:S=.cpp) : $(1) ;
						C++ $(<) : $(<:S=.cpp) ;
						Lex $(<:S=.cpp) : $(>) ;
					} else {
						InheritPlatform $(<:S=.c) : $(1) ;
						Cc $(<) : $(<:S=.c) ;
						Lex $(<:S=.c) : $(>) ;
					}
		case *.o :	return ;
		case .s :	As $(<) : $(>) ;
		case .S :	As $(<) : $(>) ;
		case .y :	if [ on $(2) return $(GENERATE_C++) ] {
						InheritPlatform $(1:S=.cpp) $(1:S=.hpp) : $(1) ;
						C++ $(1) : $(1:S=.cpp) ;
						Yacc $(1:S=.cpp) $(1:S=.hpp) : $(2) ;
					} else {
						InheritPlatform $(1:S=.c) $(1:S=.h) : $(1) ;
						Cc $(1) : $(1:S=.c) ;
						Yacc $(1:S=.c) $(1:S=.h) : $(2) ;
					}
		case * :	UserObject $(<) : $(>) ;
	}
}

rule As
{
	Depends $(<) : $(>) [ on $(1) return $(PLATFORM) ] ;

	on $(1) {
		local flags ;
		local includesSeparator ;
		local localIncludesOption ;
		local systemIncludesOption ;

		if $(PLATFORM) = host {
			flags = $(HOST_ASFLAGS) $(ASFLAGS) ;

			CC on $(1) = $(HOST_CC) ;

			includesSeparator = $(HOST_INCLUDES_SEPARATOR) ;
			localIncludesOption = $(HOST_LOCAL_INCLUDES_OPTION) ;
			systemIncludesOption = $(HOST_SYSTEM_INCLUDES_OPTION) ;
		} else {
			flags = $(TARGET_ASFLAGS_$(TARGET_PACKAGING_ARCH)) $(ASFLAGS) ;

			CC on $(1) = $(TARGET_CC_$(TARGET_PACKAGING_ARCH)) ;

			includesSeparator
				= $(TARGET_INCLUDES_SEPARATOR_$(TARGET_PACKAGING_ARCH)) ;
			localIncludesOption
				= $(TARGET_LOCAL_INCLUDES_OPTION_$(TARGET_PACKAGING_ARCH)) ;
			systemIncludesOption
				= $(TARGET_SYSTEM_INCLUDES_OPTION_$(TARGET_PACKAGING_ARCH)) ;
		}

		ASFLAGS on $(<) += $(flags) $(SUBDIRASFLAGS) ;
		ASHDRS on $(<) = [ on $(<) FIncludes $(HDRS) : $(localIncludesOption) ]
			$(includesSeparator)
			[ on $(<) FSysIncludes $(SYSHDRS) : $(systemIncludesOption) ] ;
		ASDEFS on $(<) = [ on $(<) FDefines $(DEFINES) ] ;
	}
}

actions As
{
	$(CC) -c "$(2)" -O2 $(ASFLAGS) -D_ASSEMBLER $(ASDEFS) $(ASHDRS) -o "$(1)"
}

rule Lex
{
	Depends $(1) : $(2) [ on $(1) return $(PLATFORM) ] ;
	MakeLocateArch $(1) ;
	LocalClean clean : $(1) ;
}

actions Lex
{
	$(LEX) $(LEXFLAGS) -o$(1) $(2)
}

rule Yacc
{
	local source = $(1[1]) ;
	local header = $(1[2]) ;
	local yaccSource = $(2) ;

	MakeLocateArch $(source) $(header) ;

	Depends $(source) $(header)
		: $(yaccSource) [ on $(source) return $(PLATFORM) ] ;
	Yacc1 $(source) $(header) : $(yaccSource) ;
	LocalClean clean : $(source) $(header) ;

	# make sure someone includes $(header) else it will be
	# a deadly independent target

	Includes $(source) : $(header) ;
}

actions Yacc1
{
	bison $(YACCFLAGS) -o $(1[1]) $(2)
	[ -f $(1[1]).h ] && mv $(1[1]).h $(1[2]) || true
}

rule Cc
{
	Depends $(<) : $(>) [ on $(1) return $(PLATFORM) ] ;

	on $(1) {
		local flags ;
		local includesSeparator ;
		local localIncludesOption ;
		local systemIncludesOption ;

		# optimization flags
		if $(DEBUG) = 0 {
			flags += $(OPTIM) ;
		} else {
			flags += -O0 ;
		}

		if $(PLATFORM) = host {
			# warning flags
			if $(WARNINGS) != 0 {
				flags += $(HOST_WARNING_CCFLAGS) ;
				if $(WARNINGS) = treatAsErrors {
					flags += -Werror $(HOST_WERROR_FLAGS) ;
				}
			}

			# debug and other flags
			flags += $(HOST_CCFLAGS) $(HOST_DEBUG_$(DEBUG)_CCFLAGS)
				$(SUBDIRCCFLAGS) $(CCFLAGS) ;

			if $(USES_BE_API) {
				flags += $(HOST_BE_API_CCFLAGS) ;
			}

			CC on $(1) = $(HOST_CC) ;

			includesSeparator = $(HOST_INCLUDES_SEPARATOR) ;
			localIncludesOption = $(HOST_LOCAL_INCLUDES_OPTION) ;
			systemIncludesOption = $(HOST_SYSTEM_INCLUDES_OPTION) ;
		} else {
			# warning flags
			if $(WARNINGS) != 0 {
				flags += $(TARGET_WARNING_CCFLAGS_$(TARGET_PACKAGING_ARCH)) ;
				if $(WARNINGS) = treatAsErrors {
					flags += -Werror
						$(TARGET_WERROR_FLAGS_$(TARGET_PACKAGING_ARCH)) ;
				}
			}

			# debug and other flags
			flags += $(TARGET_CCFLAGS_$(TARGET_PACKAGING_ARCH))
				$(TARGET_DEBUG_$(DEBUG)_CCFLAGS_$(TARGET_PACKAGING_ARCH))
				$(SUBDIRCCFLAGS) $(CCFLAGS) ;

			CC on $(1) = $(TARGET_CC_$(TARGET_PACKAGING_ARCH)) ;

			includesSeparator
				= $(TARGET_INCLUDES_SEPARATOR_$(TARGET_PACKAGING_ARCH)) ;
			localIncludesOption
				= $(TARGET_LOCAL_INCLUDES_OPTION_$(TARGET_PACKAGING_ARCH)) ;
			systemIncludesOption
				= $(TARGET_SYSTEM_INCLUDES_OPTION_$(TARGET_PACKAGING_ARCH)) ;
		}

		CCFLAGS on $(<) = $(flags) ;
		CCHDRS on $(<) = [ FIncludes $(HDRS) : $(localIncludesOption) ]
			$(includesSeparator)
			[ FSysIncludes $(SYSHDRS) : $(systemIncludesOption) ] ;
		CCDEFS on $(<) = [ FDefines $(DEFINES) ] ;
	}
}

actions Cc
{
	$(CC) $(CCFLAGS) -c "$(2)" $(CCDEFS) $(CCHDRS) -o "$(1)"
}

rule C++
{
	Depends $(<) : $(>) [ on $(1) return $(PLATFORM) ] ;

	on $(1) {
		local flags ;
		local includesSeparator ;
		local localIncludesOption ;
		local systemIncludesOption ;

		# optimization flags
		if $(DEBUG) = 0 {
			flags += $(OPTIM) ;
		} else {
			flags += -O0 ;
		}

		if $(PLATFORM) = host {
			# warning flags
			if $(WARNINGS) != 0 {
				flags += $(HOST_WARNING_C++FLAGS) ;
				if $(WARNINGS) = treatAsErrors {
					flags += -Werror $(HOST_WERROR_FLAGS) ;
				}
			}

			# debug and other flags
			flags += $(HOST_C++FLAGS) $(HOST_DEBUG_$(DEBUG)_C++FLAGS)
				$(SUBDIRC++FLAGS) $(C++FLAGS) ;

			if $(USES_BE_API) {
				flags += $(HOST_BE_API_C++FLAGS) ;
			}

			C++ on $(1) = $(HOST_C++) ;

			includesSeparator = $(HOST_INCLUDES_SEPARATOR) ;
			localIncludesOption = $(HOST_LOCAL_INCLUDES_OPTION) ;
			systemIncludesOption = $(HOST_SYSTEM_INCLUDES_OPTION) ;
		} else {
			# warning flags
			if $(WARNINGS) != 0 {
				flags += $(TARGET_WARNING_C++FLAGS_$(TARGET_PACKAGING_ARCH)) ;
				if $(WARNINGS) = treatAsErrors {
					flags += -Werror
						$(TARGET_WERROR_FLAGS_$(TARGET_PACKAGING_ARCH)) ;
				}
			}

			# debug and other flags
			flags += $(TARGET_C++FLAGS_$(TARGET_PACKAGING_ARCH))
				$(TARGET_DEBUG_$(DEBUG)_C++FLAGS_$(TARGET_PACKAGING_ARCH))
				$(SUBDIRC++FLAGS) $(C++FLAGS) ;

			C++ on $(1) = $(TARGET_C++_$(TARGET_PACKAGING_ARCH)) ;

			includesSeparator
				= $(TARGET_INCLUDES_SEPARATOR_$(TARGET_PACKAGING_ARCH)) ;
			localIncludesOption
				= $(TARGET_LOCAL_INCLUDES_OPTION_$(TARGET_PACKAGING_ARCH)) ;
			systemIncludesOption
				= $(TARGET_SYSTEM_INCLUDES_OPTION_$(TARGET_PACKAGING_ARCH)) ;
		}

		C++FLAGS on $(<) = $(flags) ;
		CCHDRS on $(<) = [ FIncludes $(HDRS) : $(localIncludesOption) ]
			$(includesSeparator)
			[ FSysIncludes $(SYSHDRS) : $(systemIncludesOption) ] ;
		CCDEFS on $(<) = [ FDefines $(DEFINES) ] ;
	}
}

actions C++
{
	$(C++) -c "$(2)" $(C++FLAGS) $(CCDEFS) $(CCHDRS) -o "$(1)"
}

# Force recreation of the archive to avoid build errors caused by
# stale dependencies after renaming or deleting object files.
actions together Archive
{
	$(RM) $(<)
	$(AR) $(<) $(>)
}

rule Library
{
	local lib = $(1) ;
	local sources = [ FGristFiles $(2) ] ;
	local objects = $(sources:S=$(SUFOBJ)) ;

	InheritPlatform $(objects) : $(lib) ;
	LibraryFromObjects $(lib) : $(objects) ;
	Objects $(sources) ;
}

rule LibraryFromObjects
{
	local _i _l _s ;

	# Add grist to file names
	# bonefish: No, don't. The Library rule does that anyway, and when we
	# have an object from another dir, we certainly don't want that.

	_s = $(>) ;
	_l = $(<:S=$(SUFLIB)) ;

	on $(_l) {
		# set the tools according to the platform
		if $(PLATFORM) = host {
			AR on $(_l) = $(HOST_AR) $(HOST_ARFLAGS) ;
			RANLIB on $(_l) = $(HOST_RANLIB) ;
		} else {
			AR on $(_l) = $(TARGET_AR_$(TARGET_PACKAGING_ARCH))
				$(TARGET_ARFLAGS_$(TARGET_PACKAGING_ARCH)) ;
			RANLIB on $(_l) = $(TARGET_RANLIB_$(TARGET_PACKAGING_ARCH)) ;
		}

		# library depends on its member objects

		if $(KEEPOBJS) {
			LocalDepends obj : $(_s) ;
		}

		LocalDepends lib : $(_l) ;

		# Set LOCATE for the library and its contents. The bound
		# value shows up as $(NEEDLIBS) on the Link actions.
		# For compatibility, we only do this if the library doesn't
		# already have a path.

		if ! $(_l:D) {
			# locate the library only, if it hasn't been located yet
			local dir = $(LOCATE[1]) ;
			if ! $(dir) {
				MakeLocateDebug $(_l) ;
				dir = [ on $(_l) return $(LOCATE[1]) ] ;
					# Note: The "on ..." is necessary, since our environment
					# isn't changed by MakeLocateDebug.
			}
			MakeLocate $(_l)($(_s:BS)) : $(dir) ;
		}

		if $(NOARSCAN) {
			# If we can't scan the library to timestamp its contents,
			# we have to just make the library depend directly on the
			# on-disk object files.

			Depends $(_l) : $(_s) ;
		} else {
			# If we can scan the library, we make the library depend
			# on its members and each member depend on the on-disk
			# object file.

			Depends $(_l) : $(_l)($(_s:BS)) ;

			for _i in $(_s)
			{
			Depends $(_l)($(_i:BS)) : $(_i) ;
			}
		}

		LocalClean clean : $(_l) ;

		Archive $(_l) : $(_s) ;

		if $(RANLIB) { Ranlib $(_l) ; }

		# If we can't scan the library, we have to leave the .o's around.

		if ! ( $(KEEPOBJS) || $(NOARSCAN) || $(NOARUPDATE) ) {
			RmTemps $(_l) : $(_s) ;
		}
	}
}

rule Main
{
	local target = $(1) ;
	local sources = [ FGristFiles $(2) ] ;
	local objects = $(sources:S=$(SUFOBJ)) ;

	InheritPlatform $(objects) : $(target) ;
	MainFromObjects $(target) : $(objects) ;
	Objects $(sources) ;
}

rule MainFromObjects
{
	local _s _t ;

	# Add grist to file names
	# Add suffix to exe

	_s = [ FGristFiles $(>) ] ;
	_t = [ FAppendSuffix $(<) : $(SUFEXE) ] ;

	# so 'jam foo' works when it's really foo.exe

	if $(_t) != $(<)
	{
		Depends $(<) : $(_t) ;
		NotFile $(<) ;
	}

	# make compiled sources a dependency of target

	LocalDepends exe : $(_t) ;
	Depends $(_t) : $(_s) ;
	MakeLocateDebug $(_t) ;

	LocalClean clean : $(_t) ;

	Link $(_t) : $(_s) ;
}

# Override Jam 2.5rc3 MakeLocate and MkDir to deal more intelligently
# with grist set on the supplied directory name. Also do nothing for already
# located files.
rule MakeLocate
{
	local dir = $(2[1]) ;

	if $(dir) {
		if ! $(dir:G) {
			dir = $(dir:G=dir) ;
		}

		local target ;
		for target in $(1) {
			# don't relocate once located
			LOCATE on $(target) += $(dir:G=) ;
			if [ on $(target) return $(LOCATE) ] = $(dir:G=) {
				Depends $(target) : $(dir) ;
				MkDir $(dir) ;
			}
		}
	}
}

# Overridden to use "-p", as Jam does not properly normalize
# paths passed to NoUpdate, and so tries to make some directories
# twice: once for the relative path, and once for the absolute path.
actions MkDir1
{
	$(MKDIR) -p "$(<)"
}

rule MkDir
{
	local dir = $(<) ;
	if ! $(dir:G) {
		dir = $(dir:G=dir) ;
	}

	# make this and all super directories
	while true {
		# If dir exists, don't update it
		# Do this even for $(DOT).
		NoUpdate $(dir) ;

		# Bail out when reaching the CWD (".") or a directory we've already
		# made.
		if $(dir:G=) = $(DOT) || $($(dir:G=)-mkdir) {
			return ;
		}

		local s ;

		# Cheesy gate to prevent multiple invocations on same dir
		# MkDir1 has the actions
		# Arrange for jam dirs

		$(dir:G=)-mkdir = true ;
		MkDir1 $(dir) ;
		LocalDepends dirs : $(dir) ;

		# Recursively make parent directories.
		# $(dir:P) = $(dir)'s parent, & we recurse until root

		s = $(dir:P) ;	# parent keeps grist

		if $(s:G=) && $(s) != $(dir) {
			Depends $(dir) : $(s) ;
			dir = $(s) ;
		} else if $(s) {
			NotFile $(s) ;
			break ;
		}
	}
}

rule ObjectCcFlags
{
	# supports inheriting the global variable value

	local file ;
	for file in [ FGristFiles $(1:S=$(SUFOBJ)) ] {
		CCFLAGS on $(file) = [ on $(file) return $(CCFLAGS) ] $(2) ;
	}
}

rule ObjectC++Flags
{
	# supports inheriting the global variable value

	local file ;
	for file in [ FGristFiles $(1:S=$(SUFOBJ)) ] {
		C++FLAGS on $(file) = [ on $(file) return $(C++FLAGS) ] $(2) ;
	}
}

rule ObjectDefines
{
	# supports inheriting the global variable value and multiple files

	if $(2) {
		local file ;
		for file in [ FGristFiles $(1:S=$(SUFOBJ)) ] {
			DEFINES on $(file) = [ on $(file) return $(DEFINES) ] $(2) ;
			CCDEFS on $(file) = [ on $(file) FDefines $(DEFINES) ] ;
		}
	}
}

rule ObjectHdrs
{
	# ObjectHdrs <sources or objects> : <headers> : <gristed objects>
	# Note: Parameter 3 <gristed objects> is an extension.

	local objects = [ FGristFiles $(1:S=$(SUFOBJ)) ] $(3) ;
	local headers = $(2) ;

	local file ;
	for file in $(objects) {
		on $(file) {
			local localHeaders = $(HDRS) $(headers) ;
			SYSHDRS on $(file) = $(localHeaders) ;

			# reformat ASHDRS and CCHDRS
			local fileHeaders ;

			if $(PLATFORM) = host {
				fileHeaders =
					[ FIncludes $(localHeaders) : $(HOST_LOCAL_INCLUDES_OPTION) ]
					$(HOST_INCLUDES_SEPARATOR)
					[ FSysIncludes $(SYSHDRS)
						: $(HOST_SYSTEM_INCLUDES_OPTION) ] ;
			} else {
				local architecture = $(TARGET_PACKAGING_ARCH) ;
				fileHeaders =
					[ FIncludes $(localHeaders)
						: $(TARGET_LOCAL_INCLUDES_OPTION_$(architecture)) ]
					$(TARGET_INCLUDES_SEPARATOR_$(architecture))
					[ FSysIncludes $(SYSHDRS)
						: $(TARGET_SYSTEM_INCLUDES_OPTION_$(architecture)) ] ;
			}

			ASHDRS on $(file) = $(fileHeaders) ;
			CCHDRS on $(file) = $(fileHeaders) ;
		}
	}
}

# Overridden to avoid calling SubDir for a directory twice (in SubInclude
# and from the Jamfile in the directory).
rule SubInclude
{
	# SubInclude TOP d1 ... ;
	#
	# Include a subdirectory's Jamfile.

	if ! $($(<[1]))
	{
		Exit SubInclude $(<[1]) without prior SubDir $(<[1]) ;
	}

	# Set up the config variables for the subdirectory.
	local config = [ ConfigObject $(1) ] ;

	__configured = ;
	if ! [ on $(config) return $(__configured) ] {
		# No custom configuration defined for the subdir. We use the variable
		# values inherited by the closest ancestor.
		config = $(HAIKU_INHERITED_SUBDIR_CONFIG) ;
	}

	# store SUBDIR_TOKENS
	local oldSubDirTokens = $(SUBDIR_TOKENS) ;

	on $(config) {
		include [ FDirName $($(1[1])) $(1[2-) $(JAMFILE) ] ;
	}

	# restore SUBDIR_TOKENS
	SUBDIR_TOKENS = $(oldSubDirTokens) ;
}