1rule SetupObjectsDir
2{
3	# SetupObjectsDir
4	#
5	# Internal rule used to set up the *{LOCATE,SEARCH}*_{TARGET,SOURCE}
6	# variables for the current directory.
7
8	local relPath = [ FDirName $(SUBDIR_TOKENS[2-]) ] ;
9	if $(relPath) = . {
10		relPath = ;
11	}
12
13	COMMON_PLATFORM_LOCATE_TARGET
14		= [ FDirName $(HAIKU_COMMON_PLATFORM_OBJECT_DIR) $(relPath) ] ;
15	HOST_COMMON_ARCH_LOCATE_TARGET
16		= [ FDirName $(HOST_COMMON_ARCH_OBJECT_DIR) $(relPath) ] ;
17	TARGET_COMMON_ARCH_LOCATE_TARGET
18		= [ FDirName $(TARGET_COMMON_ARCH_OBJECT_DIR) $(relPath) ] ;
19
20	local var ;
21	for var in COMMON_DEBUG DEBUG_$(HAIKU_DEBUG_LEVELS) {
22		HOST_$(var)_LOCATE_TARGET
23			= [ FDirName $(HOST_$(var)_OBJECT_DIR) $(relPath) ] ;
24		TARGET_$(var)_LOCATE_TARGET
25			= [ FDirName $(TARGET_$(var)_OBJECT_DIR_$(TARGET_PACKAGING_ARCH))
26				$(relPath) ] ;
27	}
28
29	LOCATE_TARGET = $(COMMON_PLATFORM_LOCATE_TARGET) ;
30	LOCATE_SOURCE = $(LOCATE_TARGET) ;
31	SEARCH_SOURCE = $(SUBDIR) $(LOCATE_SOURCE)
32		$(HOST_COMMON_DEBUG_LOCATE_TARGET)		# Also add the standard output
33		$(TARGET_COMMON_DEBUG_LOCATE_TARGET)	# dirs for generated sources.
34	;
35}
36
37rule SetupFeatureObjectsDir feature
38{
39	# SetupFeatureObjectsDir <feature>
40	#
41	# Updates the *{LOCATE,SEARCH}*_{TARGET,SOURCE} variables for the current
42	# directory appending a <feature> to each of them. Note that it resets
43	# the LOCATE_TARGET, LOCATE_SOURCE, SEARCH_SOURCE (!) variables. I.e. it
44	# should be invoked before customizing these variables further (e.g. like
45	# adding additional source directories to SEARCH_SOURCE).
46
47	COMMON_PLATFORM_LOCATE_TARGET
48		= [ FDirName $(COMMON_PLATFORM_LOCATE_TARGET) $(feature) ] ;
49
50	local var ;
51	for var in COMMON_ARCH COMMON_DEBUG DEBUG_$(HAIKU_DEBUG_LEVELS) {
52		HOST_$(var)_LOCATE_TARGET
53			= [ FDirName $(HOST_$(var)_LOCATE_TARGET) $(feature) ] ;
54		TARGET_$(var)_LOCATE_TARGET
55			= [ FDirName $(TARGET_$(var)_LOCATE_TARGET) $(feature) ] ;
56	}
57
58	LOCATE_TARGET = [ FDirName $(LOCATE_TARGET) $(feature) ] ;
59	LOCATE_SOURCE = $(LOCATE_TARGET) ;
60	SEARCH_SOURCE = $(SUBDIR) $(LOCATE_SOURCE)
61		$(HOST_COMMON_DEBUG_LOCATE_TARGET)		# Also add the standard output
62		$(TARGET_COMMON_DEBUG_LOCATE_TARGET)	# dirs for generated sources.
63	;
64}
65
66
67# pragma mark - MakeLocate variants
68
69
70rule MakeLocateCommonPlatform files : subdir
71{
72	# The file is shared between all target platforms.
73	MakeLocate $(files)
74		: [ FDirName $(COMMON_PLATFORM_LOCATE_TARGET) $(subdir) ] ;
75}
76
77rule MakeLocatePlatform files : subdir
78{
79	# The file is specific for the target platform, but
80	# architecture independent. Usually the right rule for generated
81	# sources, though sometimes sources can be architecture specific.
82	local file ;
83	for file in $(files) {
84		local directory ;
85		if [ on $(file) return $(PLATFORM) ] = host {
86			directory = $(HOST_COMMON_ARCH_LOCATE_TARGET) ;
87		} else {
88			directory = $(TARGET_COMMON_ARCH_LOCATE_TARGET) ;
89		}
90		MakeLocate $(file) : [ FDirName $(directory) $(subdir) ] ;
91	}
92}
93
94rule MakeLocateArch files : subdir
95{
96	# The file is platform+architecture specific, but is debug
97	# level independent. This is usually the right rule for generated
98	# architecture specific data or source files.
99	local file ;
100	for file in $(files) {
101		local directory ;
102		if [ on $(file) return $(PLATFORM) ] = host {
103			directory = $(HOST_COMMON_DEBUG_LOCATE_TARGET) ;
104		} else {
105			directory = $(TARGET_COMMON_DEBUG_LOCATE_TARGET) ;
106		}
107		MakeLocate $(file) : [ FDirName $(directory) $(subdir) ] ;
108	}
109}
110
111rule MakeLocateDebug files : subdir
112{
113	# The file is platform+architecture+debug level specific.
114	# That's what should be used for compiled code.
115	local file ;
116	for file in $(files) {
117		local directory ;
118		on $(file) {
119			if $(PLATFORM) = host {
120				directory = $(HOST_DEBUG_$(DEBUG)_LOCATE_TARGET) ;
121			} else {
122				directory = $(TARGET_DEBUG_$(DEBUG)_LOCATE_TARGET) ;
123			}
124		}
125		MakeLocate $(file) : [ FDirName $(directory) $(subdir) ] ;
126	}
127}
128
129
130# pragma mark - Deferred SubIncludes
131
132
133# The variable used to collect the deferred SubIncludes.
134HAIKU_DEFERRED_SUB_INCLUDES = ;
135
136rule DeferredSubInclude params : jamfile : scope
137{
138	# DeferredSubInclude <subdir tokens> [ : <jamfile name> [ : <scope> ] ] ;
139	#
140	# Takes the same directory tokens parameter as SubInclude plus an optional
141	# alternative Jamfile name. The the subdirectory referred to by
142	# <subdir tokens> will be included when ExecuteDeferredSubIncludes is
143	# invoked, i.e. at the end of the root Jamfile. The <jamfile name> parameter
144	# specifies the name of the Jamfile to include. By default it is "Jamfile".
145	# The <scope> parameter can be "global" (default) or "local", specifying
146	# whether the alternative Jamfile name shall also be used for subdirectories.
147
148	HAIKU_DEFERRED_SUB_INCLUDES += "/" $(params) ;
149	if $(jamfile) {
150		SetConfigVar JAMFILE : $(params) : $(jamfile) : $(scope) ;
151	}
152}
153
154rule ExecuteDeferredSubIncludes
155{
156	# ExecuteDeferredSubIncludes ;
157	#
158	# Performs the deferred SubIncludes scheduled by DeferredSubInclude.
159
160	local tokensList = $(HAIKU_DEFERRED_SUB_INCLUDES) ;
161	while $(tokensList) {
162		# chop off leading "/"
163		tokensList = $(tokensList[2-]) ;
164
165		# get the tokens for the next include
166		local tokens ;
167		while $(tokensList) && $(tokensList[1]) != "/" {
168			tokens += $(tokensList[1]) ;
169			tokensList = $(tokensList[2-]) ;
170		}
171
172		# perform the include
173		if $(tokens) {
174			SubInclude $(tokens) ;
175		}
176	}
177}
178
179rule HaikuSubInclude tokens
180{
181	# HaikuSubInclude <tokens> ;
182	#
183	# Current subdir relative SubInclude.
184	# <tokens> - subdir tokens specifying the subdirectory to be include
185	#            (relative to the current subdir)
186
187	if $(tokens) {
188		SubInclude HAIKU_TOP $(SUBDIR_TOKENS) $(tokens) ;
189	}
190}
191
192
193# pragma mark - Unique IDs/targets
194
195
196# private to NextID; incremented with each NextID invocation
197HAIKU_NEXT_ID = 0 ;
198
199rule NextID
200{
201	# NextID ;
202
203	local result = $(HAIKU_NEXT_ID:J=) ;
204	HAIKU_NEXT_ID = [ AddNumAbs $(HAIKU_NEXT_ID) : 1 ] ;
205	return $(result) ;
206}
207
208rule NewUniqueTarget basename
209{
210	# NewUniqueTarget [ basename ] ;
211
212	local id = [ NextID ] ;
213	return $(basename[1]:E=_target:G=unique!target)_$(id) ;
214}
215
216
217# pragma mark - RunCommandLine
218
219
220rule RunCommandLine commandLine
221{
222	# RunCommandLine <commandLine>
223	#
224	# Creates a pseudo target that, when made by jam, causes the supplied shell
225	# command line to be executed. Elements of <commandLine> with the prefix ":"
226	# are replaced by the rule. After stripping the prefix such a string specifies
227	# a build system target and the finally executed command line will contain
228	# a path to the target instead.
229	# The pseudo target will depend on all targets thus identified. Each
230	# invocation of this rule creates a different pseudo target, which is
231	# returned to the caller.
232
233	# collect the targets in the command line and replace them by $targetX*
234	# variables
235	local substitutedCommandLine ;
236	local targets ;
237
238	local targetVarName = target ;
239	local i ;
240	for i in $(commandLine) {
241		# targets are marked by the ":" prefix
242		local target = [ Match ^:(.*) : $(i) ] ;
243		if $(target) {
244			targets += $(target) ;
245			targetVarName = $(targetVarName)X ;
246			i = "$"$(targetVarName) ;
247		}
248
249		substitutedCommandLine += $(i) ;
250	}
251
252	# define the "run" target
253	local run = [ NewUniqueTarget run ] ;
254	COMMAND_LINE on $(run) = $(substitutedCommandLine) ;
255	NotFile $(run) ;
256	Always $(run) ;
257	Depends $(run) : $(targets) ;
258	RunCommandLine1 $(run) : $(targets) ;
259
260	return $(run) ;
261}
262
263actions RunCommandLine1 {
264	target=target;
265	for t in $(2) ; do
266		target=${target}X
267		eval "${target}=${t}"
268	done
269	$(HOST_ADD_BUILD_COMPATIBILITY_LIB_DIR) \
270	"$(COMMAND_LINE)"
271}
272
273
274#pragma mark - DefineBuildProfile
275
276
277rule DefineBuildProfile name : type : path {
278	# DefineBuildProfile <name> : <type> [ : <path> ]
279	#
280	# Makes a build profile known. Build profiles can be used to define
281	# different sets of settings for Haiku images/installations. For each
282	# profile the default actions "build", "update", and "mount" (the latter
283	# only for disks or image types) will be available (i.e. can be specified
284	# as second parameter on the jam command line). They will build an image
285	# or installation, update only given targets, respectively just mount the
286	# image or disk using the bfs_shell.
287	#
288	# <name> - The name of the build profile.
289	# <type> - The type of the build profile. Must be one of "image" (plain
290	#          disk image), "anyboot-image" (custom disk image that can be
291	#          written to CD or disk device), "cd-image" (ISO CD image),
292	#          "vmware-image" (VMware disk image), "disk" (actual partition
293	#          or hard disk device), "install" (installation in a directory),
294	#          or "custom" (user-defined).
295	# <path> - The path associated with the profile. Depending on the profile
296	#          type, this is the path to the disk image/VMware image, hard
297	#          disk/partition device, or the installation directory. If the
298	#          parameter is omitted, the value of the HAIKU[_VMWARE]_IMAGE_NAME,
299	#          HAIKU_IMAGE_DIR, respectively HAIKU_INSTALL_DIR or their default
300	#          values will be used instead.
301
302	if [ on $(name) return $(HAIKU_BUILD_PROFILE_SPECIFIED) ] {
303		Exit "ERROR: Build profile \"$(name)\" defined twice!" ;
304	}
305	HAIKU_BUILD_PROFILE_SPECIFIED on $(name) = 1 ;
306
307	if ! $(HAIKU_BUILD_PROFILE) || $(HAIKU_BUILD_PROFILE) != $(name) {
308		return ;
309	}
310
311	HAIKU_BUILD_PROFILE_DEFINED = 1 ;
312
313	# split path into directory path and name
314	local targetDir = $(path:D) ;
315	local targetName = $(path:BS) ;
316
317	# Jam's path splitting produces an empty string, if a component doesn't
318	# exist. That's a little unhandy for checks.
319	if $(targetDir) = "" {
320		targetDir = ;
321	}
322	if $(targetName) = "" {
323		targetName = ;
324	}
325
326	targetDir ?= $(HAIKU_IMAGE_DIR) ;
327	targetDir ?= $(HAIKU_DEFAULT_IMAGE_DIR) ;
328
329	# "disk" is "image" with HAIKU_DONT_CLEAR_IMAGE
330	if $(type) = "disk" {
331		type = "image" ;
332		HAIKU_DONT_CLEAR_IMAGE = 1 ;
333	}
334
335	local buildTarget ;
336	local startOffset ;
337
338	switch $(type) {
339		case "anyboot-image" : {
340			targetName ?= $(HAIKU_ANYBOOT_NAME) ;
341			targetName ?= $(HAIKU_DEFAULT_ANYBOOT_NAME) ;
342			HAIKU_ANYBOOT_DIR = $(targetDir) ;
343			HAIKU_ANYBOOT_NAME = $(targetName) ;
344			buildTarget = haiku-anyboot-image ;
345		}
346
347		case "cd-image" : {
348			targetName ?= $(HAIKU_CD_NAME) ;
349			targetName ?= $(HAIKU_DEFAULT_CD_NAME) ;
350			HAIKU_CD_DIR = $(targetDir) ;
351			HAIKU_CD_NAME = $(targetName) ;
352			buildTarget = haiku-cd ;
353		}
354
355		case "image" : {
356			targetName ?= $(HAIKU_IMAGE_NAME) ;
357			targetName ?= $(HAIKU_DEFAULT_IMAGE_NAME) ;
358			HAIKU_IMAGE_DIR = $(targetDir) ;
359			HAIKU_IMAGE_NAME = $(targetName) ;
360			buildTarget = haiku-image ;
361		}
362
363		case "haiku-mmc-image" : {
364			targetName ?= $(HAIKU_MMC_IMAGE_NAME) ;
365			targetName ?= $(HAIKU_DEFAULT_MMC_IMAGE_NAME) ;
366			HAIKU_IMAGE_DIR = $(targetDir) ;
367			HAIKU_IMAGE_NAME = $(targetName) ;
368			buildTarget = haiku-mmc-image ;
369		}
370
371		case "vmware-image" : {
372			targetName ?= $(HAIKU_VMWARE_IMAGE_NAME) ;
373			targetName ?= $(HAIKU_DEFAULT_VMWARE_IMAGE_NAME) ;
374			HAIKU_IMAGE_DIR = $(targetDir) ;
375			HAIKU_VMWARE_IMAGE_NAME = $(targetName) ;
376			buildTarget = haiku-vmware-image ;
377			startOffset = --start-offset 65536 ;
378		}
379
380		case "install" : {
381			path ?= $(HAIKU_INSTALL_DIR) ;
382			path ?= $(HAIKU_DEFAULT_INSTALL_DIR) ;
383			HAIKU_INSTALL_DIR = $(path) ;
384			buildTarget = install-haiku ;
385		}
386
387		case "custom" : {
388			# user-defined -- don't do anything
389			return 1 ;
390		}
391
392		case * : {
393			Exit "Unsupported build profile type: " $(type) ;
394		}
395	}
396
397	switch $(HAIKU_BUILD_PROFILE_ACTION) {
398		case "build" : {
399			# If parameters are specified, only build those targets (under the
400			# influence of the build profile).
401			if $(HAIKU_BUILD_PROFILE_PARAMETERS) {
402				JAM_TARGETS = $(HAIKU_BUILD_PROFILE_PARAMETERS) ;
403			} else {
404				JAM_TARGETS = $(buildTarget) ;
405			}
406		}
407
408		case "update" : {
409			JAM_TARGETS = $(buildTarget) ;
410			SetUpdateHaikuImageOnly 1 ;
411			HAIKU_PACKAGES_UPDATE_ONLY = 1 ;
412			HAIKU_INCLUDE_IN_IMAGE on $(HAIKU_BUILD_PROFILE_PARAMETERS) = 1 ;
413			HAIKU_INCLUDE_IN_PACKAGES on $(HAIKU_BUILD_PROFILE_PARAMETERS) = 1 ;
414		}
415
416		case "update-all" : {
417			JAM_TARGETS = $(buildTarget) ;
418			SetUpdateHaikuImageOnly 1 ;
419			HAIKU_INCLUDE_IN_IMAGE = 1 ;
420			HAIKU_UPDATE_ALL_PACKAGES = 1 ;
421		}
422
423		case "update-packages" : {
424			JAM_TARGETS = $(buildTarget) ;
425			SetUpdateHaikuImageOnly 1 ;
426			HAIKU_UPDATE_ALL_PACKAGES = 1 ;
427		}
428
429		case "build-package-list" : {
430			HAIKU_IMAGE_LIST_PACKAGES_TARGET
431				= $(HAIKU_BUILD_PROFILE_PARAMETERS[1]) ;
432			HAIKU_IMAGE_ADDITIONAL_PACKAGES
433				= $(HAIKU_BUILD_PROFILE_PARAMETERS[2-]) ;
434			JAM_TARGETS = $(HAIKU_IMAGE_LIST_PACKAGES_TARGET) ;
435		}
436
437		case "mount" : {
438			if $(type) in "install" "cd-image" {
439				Exit "Build action \"mount\" not supported for profile type"
440					"\"$(type)\"." ;
441			}
442
443			local commandLine = :<build>bfs_shell $(startOffset)
444				\"$(targetName:D=$(targetDir))\" ;
445			JAM_TARGETS = [ RunCommandLine $(commandLine) ] ;
446		}
447	}
448
449	return 1 ;
450}
451