xref: /haiku/build/jam/ImageRules (revision 87f4776937505e3014251c9c3434be78ae29d7d0)
1rule FSameTargetWithPrependedGrist
2{
3	# SameTargetWithPrependedGrist <target> : <grist to prepend> ;
4	#
5	local target = $(1) ;
6	local gristToPrepend = $(2) ;
7	local grist = $(target:G) ;
8
9	if $(grist) {
10		grist = $(gristToPrepend)!$(grist) ;
11	} else {
12		grist = $(gristToPrepend) ;
13	}
14
15	return $(target:G=$(grist)) ;
16}
17
18rule InitScript
19{
20	# Note: The script must have been LOCATEd before.
21	local script = $(1) ;
22	local initScript
23		= [ FSameTargetWithPrependedGrist $(script) : init-script ] ;
24
25	if ! [ on $(script) return $(__is_initialized) ] {
26		__is_initialized on $(script) = true ;
27
28		MakeLocate $(initScript) : [ on $(script) return $(LOCATE) ] ;
29		Always $(initScript) ;
30		Depends $(script) : $(initScript) ;
31
32		InitScript1 $(initScript) ;
33	}
34
35	return $(initScript) ;
36}
37
38actions InitScript1
39{
40	$(RM) $(1)
41	touch $(1)
42}
43
44rule AddVariableToScript script : variable : value
45{
46	# AddVariableToScript <script> : <variable> : <value> ;
47
48	# interpret an empty variable value as empty string
49	if ! $(value) {
50		value = "" ;
51	}
52
53	InitScript $(script) ;
54
55	VARIABLE_DEFS on $(script) += "echo $(variable)=\\\"$(value[1])\\\" >> " ;
56
57	# if the value is an array, add the other array elements
58	value = $(value[2-]) ;
59	while $(value) {
60		VARIABLE_DEFS on $(script)
61			+= "echo $(variable)=\\\" \\\$$(variable) $(value[1])\\\" >> " ;
62		value = $(value[2-]) ;
63	}
64
65	AddVariableToScript1 $(script) ;
66}
67
68actions together AddVariableToScript1
69{
70	$(VARIABLE_DEFS)$(1);
71}
72
73
74rule AddTargetVariableToScript script : targets : variable
75{
76	# AddTargetVariableToScript <script> : <targets> [ : <variable> ] ;
77	#
78	# If <targets> contains multiple targets, their paths must not contain
79	# whitespaces or other characters that need to be escaped in the shell.
80	#
81	variable ?= $(3:E=$(targets[1]:BS)) ;
82
83	local initScript = [ InitScript $(script) ] ;
84
85	serialization = [ on $(script) return $(HAIKU_SERIALIZATION) ] ;
86
87	local variableTarget = [ NewUniqueTarget ] ;
88	NotFile $(variableTarget) ;
89	Depends $(variableTarget) : $(initScript) $(targets) $(serialization) ;
90	Depends $(script) : $(variableTarget) ;
91
92	HAIKU_SERIALIZATION on $(script) = $(variableTarget) ;
93
94	HAIKU_VARIABLE_NAME on $(variableTarget) = $(variable) ;
95	AddTargetVariableToScript1 $(variableTarget) : $(initScript) $(targets) ;
96}
97
98
99actions AddTargetVariableToScript1
100{
101	script="$(2[1])"
102	echo "$(HAIKU_VARIABLE_NAME)=" >> "$script"
103
104	firstSeen=
105	for value in "$(2[2-])" ; do
106		if [ -z "$firstSeen" ]; then
107			echo "$(HAIKU_VARIABLE_NAME)=\"$value\"" >> "$script"
108			firstSeen=1
109		else
110			echo "$(HAIKU_VARIABLE_NAME)=\"\$$(HAIKU_VARIABLE_NAME) $value\"" \
111				>> "$script"
112		fi
113	done
114}
115
116
117#pragma mark -
118
119rule AddDirectoryToContainer container : directoryTokens : attributeFiles
120{
121	# AddDirectoryToContainer <container> : <directoryTokens> : <attributeFiles>
122
123	local containerGrist = [ on $(container) return $(HAIKU_CONTAINER_GRIST) ] ;
124	local directory = [ FDirName $(directoryTokens) ] ;
125	directory = $(directory:G=$(containerGrist)) ;
126
127	if ! [ on $(directory) return $(__is_on_image) ] {
128		HAIKU_INSTALL_DIRECTORIES on $(container) += $(directory) ;
129		__is_on_image on $(directory) = true ;
130		DIRECTORY_TOKENS on $(directory) = $(directoryTokens) ;
131		NotFile $(directory) ;
132
133		# mark the parent dir as not to be created
134		local parent = [ FReverse $(directoryTokens) ] ;
135		parent = [ FReverse $(parent[2-]) ] ;
136		if $(parent) {
137			parent = [ FDirName $(parent) ] ;
138			parent = $(parent:G=$(containerGrist)) ;
139			DONT_CREATE on $(parent) = true ;
140		}
141	}
142
143	if $(attributeFiles) {
144		SEARCH on $(attributeFiles)
145			+= [ FDirName $(HAIKU_TOP) src data directory_attrs ] ;
146		ATTRIBUTE_FILES on $(directory) += $(attributeFiles) ;
147	}
148
149	return $(directory) ;
150}
151
152rule FilterContainerUpdateTargets targets : filterVariable
153{
154	# FilterContainerUpdateTargets targets : filterVariable
155
156	local filteredTargets ;
157	local target ;
158	for target in $(targets) {
159		if [ on $(target) return $($(filterVariable)) ] {
160			filteredTargets += $(target) ;
161		}
162	}
163	return $(filteredTargets) ;
164}
165
166
167rule IncludeAllTargetsInContainer container
168{
169	local filterVar
170		= [ on $(container) return $(HAIKU_INCLUDE_IN_CONTAINER_VAR) ] ;
171	if $(filterVar) {
172		return $($(filterVar)) ;
173	}
174
175	return ;
176}
177
178
179rule PropagateContainerUpdateTargetFlags toTarget : fromTarget
180{
181	if [ on $(fromTarget) return $(HAIKU_INCLUDE_IN_IMAGE) ] {
182		HAIKU_INCLUDE_IN_IMAGE on $(toTarget) = 1 ;
183	}
184
185	if [ on $(fromTarget) return $(HAIKU_INCLUDE_IN_PACKAGES) ] {
186		HAIKU_INCLUDE_IN_PACKAGES on $(toTarget) = 1 ;
187	}
188}
189
190
191rule AddFilesToContainer container : directoryTokens : targets : destName
192	: flags
193{
194	# AddFilesToContainer <container> : <directoryTokens> : <targets>
195	#	: [ <destName> ] : [ <flags> ]
196	#
197	# Supported flags:
198	#	computeName - <destName> is the name of a shell command/function that
199	#		computes the destination name.
200	#	alwaysUpdate - When only updating the container, always also update the
201	#		given targets.
202
203	local containerGrist = [ on $(container) return $(HAIKU_CONTAINER_GRIST) ] ;
204	local systemDirTokens
205		= [ on $(container) return $(HAIKU_CONTAINER_SYSTEM_DIR_TOKENS) ] ;
206
207	targets = [ FFilterByBuildFeatures $(targets) ] ;
208
209	# If the image shall only be updated, we filter out all targets not marked
210	# accordingly.
211	if [ on $(container) return $(HAIKU_CONTAINER_UPDATE_ONLY) ]
212		&& ! [ IncludeAllTargetsInContainer $(container) ]
213		&& ! alwaysUpdate in $(flags) {
214		local filterVar
215			= [ on $(container) return $(HAIKU_INCLUDE_IN_CONTAINER_VAR) ] ;
216		if $(filterVar) {
217			targets = [ FilterContainerUpdateTargets $(targets)
218				: $(filterVar) ] ;
219
220			# If there are any targets, mark the container as to be included in
221			# an update, too, if it has set the update inheritance variable.
222			# This makes updating a target that lives in a package on an image
223			# work.
224			if $(targets) {
225				local updateVariable = [ on $(container) return
226					$(HAIKU_CONTAINER_INHERIT_UPDATE_VARIABLE) ] ;
227				if $(updateVariable) {
228					$(updateVariable) on $(container) = 1 ;
229				}
230			}
231		}
232	}
233
234	if ! $(targets) {
235		return ;
236	}
237
238	local directory = [ AddDirectoryToContainer $(container)
239		: $(directoryTokens) ] ;
240
241	# We create a unique dummy target per target to install.
242	local installTargetsVar
243		= [ on $(container) return $(HAIKU_INSTALL_TARGETS_VAR) ] ;
244	local stripExecutables
245		= [ on $(container) return $(HAIKU_CONTAINER_STRIP_EXECUTABLES) ] ;
246	local target ;
247	for target in $(targets) {
248		local name ;
249		local nameFunction ;
250		if $(destName) {
251			if computeName in $(flags) {
252				nameFunction = $(destName) ;
253				name = $(destName)/$(target:BSM) ;
254			} else {
255				name = $(destName) ;
256			}
257		} else {
258			name = $(target:BSM) ;
259		}
260
261		local installTarget = $(target) ;
262		if $(stripExecutables)
263			&& [ on $(target) return $(HAIKU_TARGET_IS_EXECUTABLE) ] {
264			installTarget = [ StripFiles $(target) ] ;
265		}
266
267		local destTarget = $(name:G=$(containerGrist)__$(directory:G=)) ;
268		TARGET on $(destTarget) = $(installTarget) ;
269		INSTALL_DIR on $(destTarget) = $(directory) ;
270		NAME_FUNCTION on $(destTarget) = $(nameFunction) ;
271		$(installTargetsVar) on $(target) += $(destTarget) ;
272		TARGETS_TO_INSTALL on $(directory) += $(destTarget) ;
273
274		# If the target is associated with catalog files, add those, too.
275		local catalogs = [ on $(target) return $(HAIKU_CATALOG_FILES) ] ;
276		if $(catalogs) {
277			local signature
278				= [ on $(target) return $(HAIKU_CATALOG_SIGNATURE) ] ;
279			AddFilesToContainer $(container)
280				: $(systemDirTokens) data locale catalogs $(signature)
281				: $(catalogs) ;
282		}
283
284		# If the target is associated with MIME DB entries, add those, too.
285		local mimeDBEntries = [ on $(target) return $(HAIKU_MIME_DB_ENTRIES) ] ;
286		if $(mimeDBEntries) {
287			# Make sure we add the entries only once by tracking the containers
288			# we have already added it to.
289			local containers = [ on $(mimeDBEntries)
290				return $(HAIKU_MIME_DB_ENTRIES_IN_CONTAINERS) ] ;
291			if ! $(container) in $(containers) {
292				HAIKU_MIME_DB_ENTRIES_IN_CONTAINERS on $(mimeDBEntries)
293					= $(containers) $(container) ;
294	 			CopyDirectoryToContainer $(container) : data
295 					: $(mimeDBEntries) : mime_db : : alwaysUpdate isTarget ;
296 			}
297		}
298	}
299}
300
301rule FFilesInContainerDirectory container : directoryTokens
302{
303	local containerGrist = [ on $(container) return $(HAIKU_CONTAINER_GRIST) ] ;
304	local directory = [ FDirName $(directoryTokens) ] ;
305	directory = $(directory:G=$(containerGrist)) ;
306
307	if [ on $(directory) return $(__is_on_image) ] {
308		on $(directory) return $(TARGETS_TO_INSTALL) ;
309	}
310
311	return ;
312}
313
314rule AddSymlinkToContainer container : directoryTokens : linkTarget : linkName
315{
316	# AddSymlinkToContainer <container> : <directory> : <link target>
317	#	[ : <link name> ] ;
318	#
319
320	# If the image shall only be updated, we don't add any symlinks.
321	if [ on $(container) return $(HAIKU_CONTAINER_UPDATE_ONLY) ]
322		&& ! [ IncludeAllTargetsInContainer $(container) ] {
323		return ;
324	}
325
326	local directory = [ AddDirectoryToContainer $(container)
327		: $(directoryTokens) ] ;
328
329	if ! $(linkName) {
330		local path = [ FReverse [ FSplitPath $(linkTarget) ] ] ;
331		linkName = $(path[1]) ;
332	}
333
334	local link = $(directory)/$(linkName) ;
335	SYMLINK_TARGET on $(link) = $(linkTarget) ;
336	SYMLINKS_TO_INSTALL on $(directory) += $(link) ;
337}
338
339rule FSymlinksInContainerDirectory container : directoryTokens
340{
341	local containerGrist = [ on $(container) return $(HAIKU_CONTAINER_GRIST) ] ;
342	local directory = [ FDirName $(directoryTokens) ] ;
343	directory = $(directory:G=$(containerGrist)) ;
344
345	if [ on $(directory) return $(__is_on_image) ] {
346		on $(directory) return $(SYMLINKS_TO_INSTALL) ;
347	}
348
349	return ;
350}
351
352rule CopyDirectoryToContainer container : directoryTokens : sourceDirectory
353	: targetDirectoryName : excludePatterns : flags
354{
355	# CopyDirectoryToContainer <container> : <directoryTokens>
356	#	: <sourceDirectory> : <targetDirectoryName> : <excludePatterns>
357	#	[ : <flags> ] ;
358	#
359	# Supported flags: alwaysUpdate, isTarget
360	# isTarget: <sourceDirectory> is a target, not a path
361
362	# If the image shall only be updated, we don't copy any directories
363	if [ on $(container) return $(HAIKU_CONTAINER_UPDATE_ONLY) ]
364			&& ! [ IncludeAllTargetsInContainer $(container) ]
365			&& ! alwaysUpdate in $(flags) {
366		return ;
367	}
368
369	if ! $(targetDirectoryName) {
370		targetDirectoryName = $(sourceDirectory[1]:BSM) ;
371	}
372
373	# If sourceDirectory is a path, not a target, make it a target, so we can
374	# treat both the same way.
375	if ! isTarget in $(flags) {
376		sourceDirectory = $(sourceDirectory:G=copy-directory-to-container) ;
377		SEARCH on $(sourceDirectory) = ;
378		TARGET on $(sourceDirectory) = ;
379	}
380
381	local directory = [ AddDirectoryToContainer $(container)
382		: $(directoryTokens) $(targetDirectoryName) ] ;
383
384	local targetDir = $(directory)/-/$(sourceDirectory) ;
385	Depends $(targetDir) : $(sourceDirectory) ;
386	EXCLUDE_PATTERNS on $(targetDir) = $(excludePatterns) ;
387	SOURCE_DIRECTORY on $(targetDir) = $(sourceDirectory) ;
388	TARGET_DIRECTORY on $(targetDir) = $(directory) ;
389	DIRECTORIES_TO_INSTALL on $(directory) += $(targetDir) ;
390}
391
392
393rule AddHeaderDirectoryToContainer container : dirTokens : dirName
394	: flags
395{
396	# AddHeaderDirectoryToContainer <container> : <dirTokens> : [ <dirName> ]
397	#	[ : <flags> ] ;
398	#
399	# Supported flags: alwaysUpdate
400
401	local systemDirTokens
402		= [ on $(container) return $(HAIKU_CONTAINER_SYSTEM_DIR_TOKENS) ] ;
403
404	CopyDirectoryToContainer $(container) : $(systemDirTokens) develop headers
405		: [ FDirName $(HAIKU_TOP) headers $(dirTokens) ]
406		: $(dirName) : -x *~ : $(flags) ;
407}
408
409
410rule AddWifiFirmwareToContainer container : driver : package : archive : extract
411{
412	# AddWifiFirmwareToContainer <container> : <driver> : <package> : <archive>
413	#	: <extract>
414
415	# complete location to wifi firmware archive
416	local firmwareArchive = [ FDirName
417		$(HAIKU_TOP) data system data firmware $(driver) $(archive) ] ;
418
419	local systemDirTokens
420		= [ on $(container) return $(HAIKU_CONTAINER_SYSTEM_DIR_TOKENS) ] ;
421
422	local dirTokens = $(systemDirTokens) data firmware $(driver) ;
423	if $(extract) = true || $(extract) = 1 {
424		ExtractArchiveToContainer $(container) : $(dirTokens)
425			: $(firmwareArchive) : : $(package) ;
426	} else {
427		AddFilesToContainer $(container) : $(dirTokens) : $(firmwareArchive) ;
428	}
429}
430
431
432rule ExtractArchiveToContainer container : directoryTokens : archiveFile
433	: flags : extractedSubDir
434{
435	# ExtractArchiveToContainer <container> : <directory> : <archiveFile>
436	#	: [ <flags> ] : <extractedSubDir> ;
437	#
438	# Supported flags: alwaysUpdate
439
440	# If the container shall only be updated, we extract only, if explicitely
441	# requested.
442	if [ on $(container) return $(HAIKU_CONTAINER_UPDATE_ONLY) ]
443		&& ! alwaysUpdate in $(flags) {
444		return ;
445	}
446
447	local directory = [ AddDirectoryToContainer $(container)
448		: $(directoryTokens) ] ;
449
450	ARCHIVE_FILES_TO_INSTALL on $(directory) += $(archiveFile) ;
451	ARCHIVE_SUBDIR_TO_INSTALL_FROM on $(archiveFile) = $(extractedSubDir) ;
452}
453
454rule AddDriversToContainer container : relativeDirectoryTokens : targets
455{
456	# AddDriversToContainer <container> : <relative directory> : <targets> ;
457	#
458	local systemDirTokens
459		= [ on $(container) return $(HAIKU_CONTAINER_SYSTEM_DIR_TOKENS) ] ;
460	local directoryTokens = $(systemDirTokens) add-ons kernel drivers dev
461		$(relativeDirectoryTokens) ;
462
463	targets = [ FFilterByBuildFeatures $(targets) ] ;
464
465	# A driver can be in multiple categories. Avoid adding it to the bin/
466	# directory more than once.
467	local binTargets ;
468	local target ;
469	for target in $(targets) {
470		local containers
471			= [ on $(target) return $(HAIKU_DRIVER_IN_CONTAINERS) ] ;
472		if ! $(container) in $(containers) {
473			HAIKU_DRIVER_IN_CONTAINERS on $(target)
474				= $(containers) $(container) ;
475			binTargets += $(target) ;
476		}
477	}
478
479	AddFilesToContainer $(container)
480		: $(systemDirTokens) add-ons kernel drivers bin
481		: $(binTargets) ;
482
483	# If the image shall only be updated, we don't add any symlinks.
484	if [ on $(container) return $(HAIKU_CONTAINER_UPDATE_ONLY) ]
485		&& ! [ IncludeAllTargetsInContainer $(container) ] {
486		return ;
487	}
488
489	# get the relative symlink path prefix
490	local linkPrefix = ;
491	local i ;
492	for i in $(relativeDirectoryTokens) {
493		linkPrefix += .. ;
494	}
495	linkPrefix += .. bin ;
496
497	# add the symlinks
498	local name ;
499	for name in $(targets:BSM) {
500		AddSymlinkToContainer $(container) : $(directoryTokens)
501			: [ FDirName $(linkPrefix) $(name) ] : $(name) ;
502	}
503}
504
505rule AddNewDriversToContainer container : relativeDirectoryTokens
506	: targets : flags
507{
508	# AddNewDriversToContainer <container> : <directory> : <targets> : <flags> ;
509	#
510	# Supported flags:
511	#	alwaysUpdate - When only updating the container, always also update the
512	#		given targets.
513
514	local systemDirTokens
515		= [ on $(container) return $(HAIKU_CONTAINER_SYSTEM_DIR_TOKENS) ] ;
516	local directoryTokens = $(systemDirTokens) add-ons kernel drivers
517		$(relativeDirectoryTokens) ;
518
519	targets = [ FFilterByBuildFeatures $(targets) ] ;
520
521	AddFilesToContainer $(container) : $(directoryTokens)
522		: $(targets) : : $(flags) ;
523}
524
525rule AddBootModuleSymlinksToContainer container : targets
526{
527	# AddBootModuleSymlinksToContainer <container> : <targets> ;
528	#
529
530	# If the container shall only be updated, we don't add any symlinks.
531
532	if [ on $(container) return $(HAIKU_CONTAINER_UPDATE_ONLY) ]
533		&& ! [ IncludeAllTargetsInContainer $(container) ] {
534		return ;
535	}
536
537	local systemDirTokens
538		= [ on $(container) return $(HAIKU_CONTAINER_SYSTEM_DIR_TOKENS) ] ;
539	targets = [ FFilterByBuildFeatures $(targets) ] ;
540
541	# add the symlinks
542	local installTargetsVar
543		= [ on $(container) return $(HAIKU_INSTALL_TARGETS_VAR) ] ;
544	local target ;
545	for target in $(targets) {
546		# Symlink to the first place where the target has been installed.
547		local destTarget = [ on $(target) return $($(installTargetsVar)[1]) ] ;
548		local installDir = [ on $(destTarget) return $(INSTALL_DIR) ] ;
549
550		if ! $(installDir) {
551			Echo "ERROR: AddBootModuleSymlinksToContainer: Can't create a "
552				"symlink to target" \"$(target)"\"." ;
553			Exit "ERROR: Add*ToContainer has not been invoked for it yet." ;
554		}
555
556		# chop off the system dir prefix from installDir
557		installDir = [ on $(installDir) return $(DIRECTORY_TOKENS) ] ;
558		local dummy ;
559		for dummy in $(systemDirTokens) {
560			installDir = $(installDir[2-]) ;
561		}
562
563		local name = $(target:BSM) ;
564		local linkTarget = [ FDirName ../../.. $(installDir) $(name) ] ;
565
566		AddSymlinkToContainer $(container)
567			: $(systemDirTokens) add-ons kernel boot
568			: $(linkTarget) : $(name) ;
569	}
570}
571
572
573rule AddLibrariesToContainer container : directory : libs
574{
575	# AddLibrariesToContainer <container> : <directory> : <libs>
576	#
577	# Installs libraries with the appropriate links into the container.
578	#
579
580	local lib ;
581	for lib in $(libs) {
582		local abiVersion = [ on $(lib) return $(HAIKU_LIB_ABI_VERSION) ] ;
583		if $(abiVersion) {
584			local abiVersionedLib = $(lib:G=).$(abiVersion) ;
585			AddFilesToContainer $(container) : $(directory) : $(lib)
586				: $(abiVersionedLib) ;
587			AddSymlinkToContainer $(container) : $(directory)
588				: $(abiVersionedLib) : $(lib:G=) ;
589		} else {
590			AddFilesToContainer $(container) : $(directory) : $(lib) ;
591		}
592	}
593}
594
595
596rule CreateContainerMakeDirectoriesScript container : script
597{
598	MakeLocate $(script) : $(HAIKU_OUTPUT_DIR) ;
599	Always $(script) ;
600
601	local initScript = [ InitScript $(script) ] ;
602
603	local scriptBody
604		= [ FSameTargetWithPrependedGrist $(script) : script-body ] ;
605	LOCATE on $(scriptBody) = [ on $(script) return $(LOCATE) ] ;
606	Depends $(scriptBody) : $(initScript) ;
607	Depends $(script) : $(scriptBody) ;
608
609	# collect the directories to create
610	local dirsToCreate ;
611	local directories
612		= [ on $(container) return $(HAIKU_INSTALL_DIRECTORIES) ] ;
613	local dir ;
614	for dir in $(directories) {
615		if ! [ on $(dir) return $(DONT_CREATE) ] {
616			dirsToCreate += $(dir) ;
617		}
618	}
619
620	# If the image shall only be updated, we don't create directories.
621	if $(dirsToCreate)
622		&& ( ! [ on $(container) return $(HAIKU_CONTAINER_UPDATE_ONLY) ]
623			|| [ IncludeAllTargetsInContainer $(container) ]
624			|| [ on $(container) return
625				$(HAIKU_CONTAINER_ALWAYS_CREATE_DIRECTORIES) ] ) {
626		Depends $(scriptBody) : $(dirsToCreate) ;
627		CreateContainerMakeDirectoriesScript1 $(scriptBody) : $(dirsToCreate) ;
628
629		local serializationDependency = $(scriptBody) ;
630			# Used to create a dependency chain between the dummy targets.
631			# This forces jam to build them one after the other, thus preventing
632			# concurrent writes to the script file when building with multiple
633			# jobs.
634
635		# For directories with attributes, we convert those the specified
636		# resource files to files with attributes and add commands to the script
637		# adding the attributes to the directories.
638		for dir in $(directories) {
639			local resourceFiles = [ on $(dir) return $(ATTRIBUTE_FILES) ] ;
640			if $(resourceFiles) {
641				local dirTokens = [ on $(dir) return $(DIRECTORY_TOKENS) ] ;
642
643				# translate resources file to file with attributes
644				local attributeFile = $(script)-attributes-$(dirTokens:J=-) ;
645				ResAttr $(attributeFile) : $(resourceFiles) ;
646
647				# use a unique dummy target for this file, on which we
648				# can define the TARGET_DIR variable
649				local dummyTarget = $(script)-attributes-dummy-$(dir:G=) ;
650				NotFile $(dummyTarget) ;
651				TARGET_DIR on $(dummyTarget) = $(dir:G=) ;
652
653				Depends $(dummyTarget) : $(initScript) $(attributeFile)
654					$(serializationDependency) ;
655				Depends $(script) : $(dummyTarget) ;
656				serializationDependency = $(dummyTarget) ;
657
658				AppendToContainerMakeDirectoriesScriptAttributes $(dummyTarget)
659					: $(initScript) $(attributeFile) ;
660			}
661		}
662	}
663}
664
665actions piecemeal CreateContainerMakeDirectoriesScript1
666{
667	echo \$mkdir -p "\"\${tPrefix}$(2:G=)\"" >> $(1)
668}
669
670actions AppendToContainerMakeDirectoriesScriptAttributes
671{
672	echo \$copyAttrs "\"\${sPrefix}$(2[2])\"" \
673		"\"\${tPrefix}$(TARGET_DIR)\"" >> $(2[1])
674}
675
676rule CreateContainerCopyFilesScript container : script
677{
678	MakeLocate $(script) : $(HAIKU_OUTPUT_DIR) ;
679	Always $(script) ;
680
681	local initScript = [ InitScript $(script) ] ;
682
683	local scriptBody
684		= [ FSameTargetWithPrependedGrist $(script) : script-body ] ;
685	LOCATE on $(scriptBody) = [ on $(script) return $(LOCATE) ] ;
686	Depends $(scriptBody) : $(initScript) ;
687	Depends $(script) : $(scriptBody) ;
688
689	local serializationDependency = $(scriptBody) ;
690		# Used to create a dependency chain between the dummy targets.
691		# This forces jam to build them one after the other, thus preventing
692		# concurrent writes to the script file when building with multiple
693		# jobs.
694
695	local dir ;
696	for dir in [ on $(container) return $(HAIKU_INSTALL_DIRECTORIES) ] {
697		# filter the targets that shall be renamed; they have to be copied
698		# individually
699		local destTargets = [ on $(dir) return $(TARGETS_TO_INSTALL) ] ;
700		local remainingTargets ;
701		local destTarget ;
702		for destTarget in $(destTargets) {
703			local target = [ on $(destTarget) return $(TARGET) ] ;
704			local name = $(destTarget:G=) ;
705			if $(name) != $(target:BSM) {
706				# use a unique dummy target for this file, on which we
707				# can define the TARGET_DIR variable
708				local dummyTarget = $(script)-dummy-$(dir:G=)-$(target) ;
709				NotFile $(dummyTarget) ;
710				TARGET_DIR on $(dummyTarget) = $(dir:G=) ;
711
712				local nameFunction
713					= [ on $(destTarget) return $(NAME_FUNCTION) ] ;
714				if $(nameFunction) {
715					INSTALL_TARGET_NAME on $(dummyTarget) = "\\${name}" ;
716				} else {
717					INSTALL_TARGET_NAME on $(dummyTarget) = $(name) ;
718				}
719				NAME_FUNCTION on $(dummyTarget) = $(nameFunction) ;
720
721				Depends $(dummyTarget) : $(initScript) $(target)
722					$(serializationDependency) ;
723				Depends $(script) : $(dummyTarget) ;
724				serializationDependency = $(dummyTarget) ;
725
726				AppendToContainerCopyFilesScriptSingleFile $(dummyTarget)
727					: $(initScript) $(target) ;
728			} else {
729				remainingTargets += $(target) ;
730			}
731		}
732		targets = $(remainingTargets) ;
733
734		if $(targets) {
735			# use a unique dummy target for this directory, on which we
736			# can define the TARGET_DIR variable
737			local dummyTarget = $(script)-dummy-$(dir:G=) ;
738			NotFile $(dummyTarget) ;
739			TARGET_DIR on $(dummyTarget) = $(dir:G=) ;
740
741			Depends $(dummyTarget) : $(initScript) $(targets)
742				$(serializationDependency) ;
743			Depends $(script) : $(dummyTarget) ;
744			serializationDependency = $(dummyTarget) ;
745
746			OUTPUT_SCRIPT on $(dummyTarget) = $(initScript) ;
747			AppendToContainerCopyFilesScript $(dummyTarget) : $(targets) ;
748		}
749
750		local symlinks = [ on $(dir) return $(SYMLINKS_TO_INSTALL) ] ;
751		local symlink ;
752		for symlink in $(symlinks) {
753			NotFile $(symlink) ;
754
755			Depends $(script) : $(symlink) ;
756			Depends $(symlink) : $(initScript) $(serializationDependency) ;
757			serializationDependency = $(symlink) ;
758
759			AddSymlinkToContainerCopyFilesScript $(symlink) : $(initScript) ;
760		}
761
762		local targetDirs = [ on $(dir) return $(DIRECTORIES_TO_INSTALL) ] ;
763		local targetDir ;
764		for targetDir in $(targetDirs) {
765			NotFile $(targetDir) ;
766
767			Depends $(script) : $(targetDir) ;
768			Depends $(targetDir) : $(initScript) $(serializationDependency) ;
769			serializationDependency = $(targetDir) ;
770
771			AddDirectoryToContainerCopyFilesScript $(targetDir)
772				: $(initScript) ;
773		}
774	}
775}
776
777
778actions piecemeal AppendToContainerCopyFilesScript bind OUTPUT_SCRIPT
779{
780	echo \$cp "\"\${sPrefix}$(2)\"" "\"\${tPrefix}$(TARGET_DIR)\"" \
781		>> $(OUTPUT_SCRIPT)
782}
783
784
785actions AppendToContainerCopyFilesScriptSingleFile
786{
787	if [ -n "$(NAME_FUNCTION:E)" ]; then
788		echo "name=\`$(NAME_FUNCTION:E) \"$(2[2])\" 2> /dev/null \` || exit 1" \
789			>> $(2[1])
790	fi
791
792	echo \$cp "\"\${sPrefix}$(2[2])\"" \
793		"\"\${tPrefix}$(TARGET_DIR)/$(INSTALL_TARGET_NAME)\"" >> $(2[1])
794}
795
796
797actions AddSymlinkToContainerCopyFilesScript
798{
799	echo \$ln -sfn "\"$(SYMLINK_TARGET)\"" "\"\${tPrefix}$(1:G=)\"" >> $(2[1])
800}
801
802
803actions AddDirectoryToContainerCopyFilesScript bind SOURCE_DIRECTORY
804{
805	echo \$cp -r $(EXCLUDE_PATTERNS) "\"\${sPrefix}$(SOURCE_DIRECTORY)/.\"" \
806		"\"\${tPrefix}$(TARGET_DIRECTORY:G=)\"" >> $(2[1])
807}
808
809
810rule CreateContainerExtractFilesScript container : script
811{
812	MakeLocate $(script) : $(HAIKU_OUTPUT_DIR) ;
813	Always $(script) ;
814
815	local initScript = [ InitScript $(script) ] ;
816
817	local scriptBody
818		= [ FSameTargetWithPrependedGrist $(script) : script-body ] ;
819	LOCATE on $(scriptBody) = [ on $(script) return $(LOCATE) ] ;
820	Depends $(scriptBody) : $(initScript) ;
821	Depends $(script) : $(scriptBody) ;
822
823	local serializationDependency = $(scriptBody) ;
824		# Used to create a dependency chain between the dummy targets.
825		# This forces jam to build them one after the other, thus preventing
826		# concurrent writes to the script file when building with multiple
827		# jobs.
828
829	local dir ;
830	for dir in [ on $(container) return $(HAIKU_INSTALL_DIRECTORIES) ] {
831		local archiveFiles = [ on $(dir) return $(ARCHIVE_FILES_TO_INSTALL) ] ;
832		local archiveFile ;
833		for archiveFile in $(archiveFiles) {
834			# use a unique dummy target for this file, on which we
835			# can define the TARGET_DIR variable
836			local dummyTarget = $(script)-dummy-$(dir:G=)-$(archiveFile) ;
837			NotFile $(dummyTarget) ;
838			TARGET_DIR on $(dummyTarget) = $(dir:G=) ;
839
840			local extractedSubDir = [ on $(archiveFile)
841				return $(ARCHIVE_SUBDIR_TO_INSTALL_FROM) ] ;
842			ARCHIVE_SUBDIR_TO_INSTALL_FROM on $(dummyTarget) =
843				$(extractedSubDir:E=.) ;
844
845			Depends $(dummyTarget) : $(initScript) $(archiveFile)
846				$(serializationDependency) ;
847			Depends $(script) : $(dummyTarget) ;
848			serializationDependency = $(dummyTarget) ;
849
850			AddExtractFileToContainerExtractFilesScript $(dummyTarget)
851				: $(initScript) $(archiveFile) ;
852		}
853	}
854}
855
856
857actions AddExtractFileToContainerExtractFilesScript
858{
859	echo extractFile "\"$(2[2])\"" "\"$(TARGET_DIR)\"" \
860		"\"$(ARCHIVE_SUBDIR_TO_INSTALL_FROM)\"" >> $(2[1])
861}
862
863
864rule AddPackagesAndRepositoryVariablesToContainerScript script : container
865{
866	AddVariableToScript $(script) : downloadDir : $(HAIKU_DOWNLOAD_DIR) ;
867	AddTargetVariableToScript $(script) : <build>package ;
868	AddTargetVariableToScript $(script) : <build>get_package_dependencies
869		: getPackageDependencies ;
870
871	# Add a variable to indicate whether packages dependencies shall be
872	# resolved. We always want to do that in non-update mode, but also in update
873	# mode when all packages are updated.
874	local updateOnly
875		= [ on $(container) return $(HAIKU_CONTAINER_UPDATE_ONLY) ] ;
876	local resolvePackageDependencies ;
877	if ( ! $(updateOnly) || $(HAIKU_UPDATE_ALL_PACKAGES) )
878		&& $(HAIKU_BUILD_TYPE) != bootstrap {
879		resolvePackageDependencies = 1 ;
880	}
881	AddVariableToScript $(script) : resolvePackageDependencies
882		: $(resolvePackageDependencies) ;
883
884	AddVariableToScript $(script) : noDownloads : $(HAIKU_NO_DOWNLOADS) ;
885
886	AddVariableToScript $(script) : updateAllPackages
887		: $(HAIKU_UPDATE_ALL_PACKAGES) ;
888
889	# Add variable "systemPackages" with the packages copied/updated.
890	local systemPackages = [ on $(container) return $(HAIKU_SYSTEM_PACKAGES_IN_IMAGE) ] ;
891	if $(updateOnly) && ! [ IncludeAllTargetsInContainer $(container) ] {
892		systemPackages = [ FilterContainerUpdateTargets $(systemPackages)
893			: [ on $(container) return $(HAIKU_INCLUDE_IN_CONTAINER_VAR) ] ] ;
894	}
895	AddTargetVariableToScript $(script) : $(systemPackages) : systemPackages ;
896
897	# Add variable "otherPackages" with the packages copied/updated.
898	local otherPackages = [ on $(container) return $(HAIKU_OTHER_PACKAGES_IN_IMAGE) ] ;
899	if $(updateOnly) && ! [ IncludeAllTargetsInContainer $(container) ] {
900		otherPackages = [ FilterContainerUpdateTargets $(otherPackages)
901			: [ on $(container) return $(HAIKU_INCLUDE_IN_CONTAINER_VAR) ] ] ;
902	}
903	AddTargetVariableToScript $(script) : $(otherPackages) : otherPackages ;
904
905	# Generate the repository package lists and add variables for the
906	# repositories.
907	local repository ;
908	local repositoryFiles ;
909	for repository in $(HAIKU_REPOSITORIES) {
910		repositoryFiles
911			+= [ on $(repository) return $(HAIKU_REPOSITORY_CACHE_FILE) ] ;
912	}
913
914	AddTargetVariableToScript $(script) : $(repositoryFiles) : repositories ;
915}
916
917
918#pragma mark - Haiku Image rules
919
920rule SetUpdateHaikuImageOnly flag
921{
922	HAIKU_CONTAINER_UPDATE_ONLY on $(HAIKU_IMAGE_CONTAINER_NAME) = $(flag) ;
923}
924
925rule IsUpdateHaikuImageOnly
926{
927	on $(HAIKU_IMAGE_CONTAINER_NAME) return $(HAIKU_CONTAINER_UPDATE_ONLY) ;
928}
929
930rule AddDirectoryToHaikuImage directoryTokens : attributeFiles
931{
932	# AddDirectoryToHaikuImage <directoryTokens> : <attributeFiles>
933
934	return [ AddDirectoryToContainer $(HAIKU_IMAGE_CONTAINER_NAME)
935		: $(directoryTokens) : $(attributeFiles) ] ;
936}
937
938rule AddFilesToHaikuImage directory : targets : destName : flags
939{
940	# AddFilesToHaikuImage <directory> : <targets> : [ <destName> ]
941	#	: [ <flags> ]
942
943	AddFilesToContainer $(HAIKU_IMAGE_CONTAINER_NAME) : $(directory)
944		: $(targets) : $(destName) : $(flags) ;
945}
946
947rule FFilesInHaikuImageDirectory directoryTokens
948{
949	return [ FFilesInContainerDirectory $(HAIKU_IMAGE_CONTAINER_NAME)
950		: $(directoryTokens) ] ;
951}
952
953rule AddSymlinkToHaikuImage directoryTokens : linkTarget : linkName
954{
955	# AddSymlinkToHaikuImage <directory> : <link target> [ : <link name> ] ;
956
957	linkTarget = $(linkTarget:J=/) ;
958
959	AddSymlinkToContainer $(HAIKU_IMAGE_CONTAINER_NAME) : $(directoryTokens)
960		: $(linkTarget) : $(linkName) ;
961}
962
963rule FSymlinksInHaikuImageDirectory directoryTokens
964{
965	return [ FSymlinksInContainerDirectory $(HAIKU_IMAGE_CONTAINER_NAME)
966		: $(directoryTokens) ] ;
967}
968
969rule CopyDirectoryToHaikuImage directoryTokens : sourceDirectory
970	: targetDirectoryName : excludePatterns : flags
971{
972	CopyDirectoryToContainer $(HAIKU_IMAGE_CONTAINER_NAME) : $(directoryTokens)
973		: $(sourceDirectory) : $(targetDirectoryName) : $(excludePatterns)
974		: $(flags) ;
975}
976
977rule AddSourceDirectoryToHaikuImage dirTokens : flags
978{
979	# AddSourceDirectoryToHaikuImage <dirTokens> : <flags> ;
980
981	CopyDirectoryToHaikuImage home HaikuSources
982		: [ FDirName $(HAIKU_TOP) $(dirTokens) ]
983		: : : $(flags) ;
984}
985
986rule AddHeaderDirectoryToHaikuImage dirTokens : dirName : flags
987{
988	# AddHeaderDirectoryToHaikuImage <dirTokens> : [ <dirName> ]
989	#	: <flags> ;
990
991	AddHeaderDirectoryToContainer $(HAIKU_IMAGE_CONTAINER_NAME) : $(dirTokens)
992		: $(dirName) : $(flags) ;
993}
994
995rule AddWifiFirmwareToHaikuImage driver : package : archive : extract
996{
997	# AddWifiFirmwareToHaikuImage <driver> : <package> : <archive> : <extract>
998
999	AddWifiFirmwareToHaikuImage $(HAIKU_IMAGE_CONTAINER_NAME) : $(driver)
1000		: $(package) : $(archive) : $(extract) ;
1001}
1002
1003rule ExtractArchiveToHaikuImage dirTokens : archiveFile : flags
1004	: extractedSubDir
1005{
1006	# ExtractArchiveToHaikuImage <dirTokens> : <archiveFile> : <flags>
1007	#	: <extractedSubDir> ;
1008
1009	ExtractArchiveToContainer $(HAIKU_IMAGE_CONTAINER_NAME) : $(dirTokens)
1010		: $(archiveFile) : $(flags) : $(extractedSubDir) ;
1011}
1012
1013rule AddDriversToHaikuImage relativeDirectoryTokens : targets
1014{
1015	# AddDriversToHaikuImage <relative directory> : <targets> ;
1016
1017	AddDriversToContainer $(HAIKU_IMAGE_CONTAINER_NAME)
1018		: $(relativeDirectoryTokens) : $(targets) ;
1019}
1020
1021rule AddNewDriversToHaikuImage relativeDirectoryTokens : targets : flags
1022{
1023	# AddNewDriversToHaikuImage <relative directory> : <targets> : <flags> ;
1024
1025	AddNewDriversToContainer $(HAIKU_IMAGE_CONTAINER_NAME)
1026		: $(relativeDirectoryTokens) : $(targets) : $(flags) ;
1027}
1028
1029rule AddBootModuleSymlinksToHaikuImage targets
1030{
1031	# AddBootModuleSymlinksToHaikuImage <targets> ;
1032
1033	AddBootModuleSymlinksToContainer $(HAIKU_IMAGE_CONTAINER_NAME)
1034		: $(targets) ;
1035}
1036
1037rule AddPackageFilesToHaikuImage location : packages : flags
1038{
1039	# AddPackageFilesToHaikuImage <location> : <packages> : <flags>
1040	#
1041	# Supported flags:
1042	#	nameFromMetaInfo - determine the target file name from the package meta
1043	#		info
1044
1045	packages = [ FFilterByBuildFeatures $(packages) ] ;
1046
1047	if $(location[1]) = system && $(location[2]) = packages && ! $(location[3]) {
1048		HAIKU_SYSTEM_PACKAGES_IN_IMAGE on $(HAIKU_IMAGE_CONTAINER_NAME)
1049			= [ on $(HAIKU_IMAGE_CONTAINER_NAME) return $(HAIKU_SYSTEM_PACKAGES_IN_IMAGE) ]
1050				$(packages) ;
1051	} else {
1052		HAIKU_OTHER_PACKAGES_IN_IMAGE on $(HAIKU_IMAGE_CONTAINER_NAME)
1053			= [ on $(HAIKU_IMAGE_CONTAINER_NAME) return $(HAIKU_OTHER_PACKAGES_IN_IMAGE) ]
1054				$(packages) ;
1055	}
1056
1057	if nameFromMetaInfo in $(flags) {
1058		AddFilesToHaikuImage $(location) : $(packages)
1059			: packageFileName : computeName ;
1060	} else {
1061		AddFilesToHaikuImage $(location) : $(packages) ;
1062	}
1063}
1064
1065rule AddOptionalHaikuImagePackages packages
1066{
1067	local package ;
1068	for package in $(packages) {
1069		if ! [ on $(package) return $(HAIKU_OPTIONAL_PACKAGE_ADDED) ] {
1070			HAIKU_OPTIONAL_PACKAGE_ADDED on $(package) = 1 ;
1071			HAIKU_ADDED_OPTIONAL_PACKAGES += $(package) ;
1072		}
1073		local dependencies = [ on $(package)
1074			return $(HAIKU_OPTIONAL_PACKAGE_DEPENDENCIES) ] ;
1075		AddOptionalHaikuImagePackages $(dependencies) ;
1076	}
1077}
1078
1079rule SuppressOptionalHaikuImagePackages packages
1080{
1081	local package ;
1082	for package in $(packages) {
1083		if ! [ on $(package) return $(HAIKU_OPTIONAL_PACKAGE_SUPPRESSED) ] {
1084			HAIKU_OPTIONAL_PACKAGE_SUPPRESSED on $(package) = 1 ;
1085		}
1086	}
1087}
1088
1089rule IsOptionalHaikuImagePackageAdded package
1090{
1091	if ! [ on $(package) return $(HAIKU_OPTIONAL_PACKAGE_EXISTS) ] {
1092		HAIKU_OPTIONAL_PACKAGE_EXISTS on $(package) = 1 ;
1093		HAIKU_EXISTING_OPTIONAL_PACKAGES += $(package) ;
1094	}
1095
1096	if [ on $(package) return $(HAIKU_OPTIONAL_PACKAGE_ADDED) ] &&
1097			! [ on $(package) return $(HAIKU_OPTIONAL_PACKAGE_SUPPRESSED) ] {
1098		return 1 ;
1099	}
1100
1101	return ;
1102}
1103
1104rule OptionalPackageDependencies package : dependencies
1105{
1106	HAIKU_OPTIONAL_PACKAGE_DEPENDENCIES on $(package) = $(dependencies) ;
1107	if [ on $(package) return $(HAIKU_OPTIONAL_PACKAGE_ADDED) ] {
1108		AddOptionalHaikuImagePackages $(dependencies) ;
1109	}
1110}
1111
1112
1113rule AddHaikuImagePackages packages : directory
1114{
1115	# AddHaikuImagePackages <packages> : <directory> ;
1116	# Adds the given packages <packages> to the image in the given directory.
1117
1118	packages = [ FFilterByBuildFeatures $(packages) ] ;
1119
1120	local package ;
1121	for package in $(packages) {
1122		local resolvedPackage = [ IsPackageAvailable $(package) ] ;
1123		if ! $(resolvedPackage) {
1124			Echo "AddHaikuImagePackages: package" $(package)
1125				"not available!" ;
1126			continue ;
1127		}
1128
1129		if ! [ on $(resolvedPackage) return $(HAIKU_PACKAGE_ADDED) ] {
1130			HAIKU_PACKAGE_ADDED on $(resolvedPackage) = 1 ;
1131			HAIKU_ADDED_PACKAGES += $(resolvedPackage) ;
1132
1133			# download the package file and add it to the image
1134			local file = [ FetchPackage $(package) ] ;
1135
1136			if $(HAIKU_UPDATE_ALL_PACKAGES) {
1137				HAIKU_INCLUDE_IN_IMAGE on $(file) = 1 ;
1138			}
1139
1140			AddPackageFilesToHaikuImage $(directory) : $(file) ;
1141		}
1142	}
1143}
1144
1145rule AddHaikuImageSourcePackages packages
1146{
1147	# AddHaikuImageSourcePackages <packages> ;
1148	# Adds the given source packages for <packages> to the image.
1149
1150	if $(HAIKU_INCLUDE_SOURCES) = 1 {
1151		AddHaikuImagePackages $(packages)_source : _sources_ ;
1152	}
1153}
1154
1155rule AddHaikuImageSystemPackages packages
1156{
1157	# AddHaikuImageSystemPackages <packages> ;
1158	# Adds the given packages for <packages> to the image, in the system
1159	# directory, so they will be activated on first boot.
1160
1161	AddHaikuImagePackages $(packages) : system packages ;
1162}
1163
1164rule AddHaikuImageDisabledPackages packages
1165{
1166	# AddHaikuImageDisabledPackages <packages> ;
1167	# Adds the given packages for <packages> to the image, in the _packages_
1168	# directory, so they can be later enabled in Installer.
1169
1170	AddHaikuImagePackages $(packages) : _packages_ ;
1171}
1172
1173rule IsHaikuImagePackageAdded package
1174{
1175	local resolvedPackage = [ IsPackageAvailable $(package) ] ;
1176	if $(resolvedPackage)
1177		&& [ on $(resolvedPackage) return $(HAIKU_PACKAGE_ADDED) ] {
1178		return 1 ;
1179	}
1180
1181	return ;
1182}
1183
1184
1185rule BuildHaikuImagePackageList target
1186{
1187	if ! $(target) {
1188		return ;
1189	}
1190
1191	# get the file names of all added packages
1192	local packageFiles ;
1193	local package ;
1194	for package in $(HAIKU_ADDED_PACKAGES) {
1195		packageFiles += [ FetchPackage $(package) : nameResolved ] ;
1196	}
1197
1198	# extract the versioned package names (without revision)
1199	packageFiles = [ Match "^([^-]*)" : $(packageFiles:B) ] ;
1200
1201	HAIKU_IMAGE_PACKAGES on $(target) = $(packageFiles) ;
1202}
1203
1204
1205actions BuildHaikuImagePackageList
1206{
1207	echo $(HAIKU_IMAGE_PACKAGES) | xargs -n 1 echo | LC_ALL=C sort -u > $(1)
1208}
1209
1210
1211rule AddEntryToHaikuImageUserGroupFile file : entry
1212{
1213	local allEntries = [ on $(file) return $(HAIKU_IMAGE_USER_GROUP_ENTRIES) ] ;
1214
1215	if $(allEntries) {
1216		allEntries = $(allEntries)|$(entry) ;
1217	} else {
1218		allEntries = $(entry) ;
1219
1220		Always $(file) ;
1221		MakeLocate $(file) : $(HAIKU_COMMON_PLATFORM_OBJECT_DIR) ;
1222		BuildHaikuImageUserGroupFile $(file) ;
1223		AddFilesToHaikuImage system settings etc : $(file) ;
1224	}
1225
1226	HAIKU_IMAGE_USER_GROUP_ENTRIES on $(file) = $(allEntries) ;
1227}
1228
1229actions BuildHaikuImageUserGroupFile
1230{
1231	echo "$(HAIKU_IMAGE_USER_GROUP_ENTRIES)" | tr '|' '\n' > $(1)
1232}
1233
1234rule AddUserToHaikuImage user : uid : gid : home : shell : realName
1235{
1236	if ! $(user) || ! $(uid) || ! $(gid) || ! $(home) {
1237		Exit "Invalid haiku user specification passed to AddUserToHaikuImage." ;
1238	}
1239
1240	local entry
1241		= $(user):x:$(uid):$(gid):$(realName:E=$(user)):$(home):$(shell:E="") ;
1242
1243	AddEntryToHaikuImageUserGroupFile <haiku-image>passwd : $(entry) ;
1244}
1245
1246rule AddGroupToHaikuImage group : gid : members
1247{
1248	if ! $(group) || ! $(gid) {
1249		Exit "Invalid haiku group specification passed to"
1250			"AddGroupToHaikuImage." ;
1251	}
1252
1253	local entry = $(group):x:$(gid):$(members:J=,:E) ;
1254
1255	AddEntryToHaikuImageUserGroupFile <haiku-image>group : $(entry) ;
1256}
1257
1258
1259rule AddLibrariesToHaikuImage directory : libs
1260{
1261	# AddLibraryToHaikuImage <directory> : <libs>
1262	#
1263	# Installs libraries with the appropriate links onto the image.
1264	#
1265
1266	AddLibrariesToContainer $(HAIKU_IMAGE_CONTAINER_NAME) : $(directory)
1267		: $(libs) ;
1268}
1269
1270
1271rule CreateHaikuImageMakeDirectoriesScript script
1272{
1273	CreateContainerMakeDirectoriesScript $(HAIKU_IMAGE_CONTAINER_NAME)
1274		: $(script) ;
1275}
1276
1277rule CreateHaikuImageCopyFilesScript script
1278{
1279	CreateContainerCopyFilesScript $(HAIKU_IMAGE_CONTAINER_NAME) : $(script) ;
1280}
1281
1282rule CreateHaikuImageExtractFilesScript script
1283{
1284	CreateContainerExtractFilesScript $(HAIKU_IMAGE_CONTAINER_NAME)
1285		: $(script) ;
1286}
1287
1288rule BuildHaikuImage haikuImage : scripts : isImage : isVMwareImage
1289{
1290	# BuildHaikuImage <haiku image> : <scripts> : <is image> : <isVMwareImage> ;
1291
1292	if $(isImage) = 1 || $(isImage) = true {
1293		IS_IMAGE on $(haikuImage) = 1 ;
1294	} else {
1295		IS_IMAGE on $(haikuImage) = "" ;
1296	}
1297
1298	if $(isVMwareImage) = 1 || $(isVMwareImage) = true {
1299		IS_VMWARE_IMAGE on $(haikuImage) = 1 ;
1300	} else {
1301		IS_VMWARE_IMAGE on $(haikuImage) = "" ;
1302	}
1303
1304	local mainScript = build_haiku_image ;
1305	SEARCH on $(mainScript) = [ FDirName $(HAIKU_TOP) build scripts ] ;
1306
1307	Depends $(haikuImage) : $(mainScript) $(scripts) ;
1308	BuildHaikuImage1 $(haikuImage) : $(mainScript)
1309		$(scripts:R=$(HAIKU_ABSOLUTE_OUTPUT_DIR)) ;
1310}
1311
1312actions BuildHaikuImage1
1313{
1314	export imagePath="$(1)"
1315	export isImage="$(IS_IMAGE)"
1316	export isVMwareImage="$(IS_VMWARE_IMAGE)"
1317	$(2[1]) $(2[2-])
1318}
1319
1320rule BuildVMWareImage vmwareImage : plainImage : imageSize
1321{
1322	# BuildVMWareImage <vmware image> : <plain image> : <image size in MB>
1323
1324	IMAGE_SIZE on $(vmwareImage) = $(imageSize) ;
1325
1326	Depends $(vmwareImage) : <build>vmdkheader $(plainImage) ;
1327	BuildVMWareImage1 $(vmwareImage) : <build>vmdkheader $(plainImage) ;
1328}
1329
1330actions BuildVMWareImage1
1331{
1332	$(RM) $(1)
1333	$(2[1]) -h 64k -i$(IMAGE_SIZE)M $(1) &&
1334	cat $(2[2]) >> $(1)
1335}
1336
1337
1338#pragma mark - Network Boot Archive rules
1339
1340rule AddDirectoryToNetBootArchive directoryTokens
1341{
1342	# AddDirectoryToNetBootArchive <directoryTokens>
1343
1344	return [ AddDirectoryToContainer $(HAIKU_NET_BOOT_ARCHIVE_CONTAINER_NAME)
1345		: $(directoryTokens) ] ;
1346}
1347
1348rule AddFilesToNetBootArchive directory : targets : destName
1349{
1350	# AddFilesToNetBootArchive <directory> : <targets> [ : dest name ]
1351
1352	AddFilesToContainer $(HAIKU_NET_BOOT_ARCHIVE_CONTAINER_NAME) : $(directory)
1353		: $(targets) : $(destName) ;
1354}
1355
1356rule AddSymlinkToNetBootArchive directoryTokens : linkTarget : linkName
1357{
1358	# AddSymlinkToNetBootArchive <directory> : <link target> [ : <link name> ] ;
1359
1360	AddSymlinkToContainer $(HAIKU_NET_BOOT_ARCHIVE_CONTAINER_NAME)
1361		: $(directoryTokens) : $(linkTarget) : $(linkName) ;
1362}
1363
1364rule AddDriversToNetBootArchive relativeDirectoryTokens : targets
1365{
1366	# AddDriversToNetBootArchive <relative directory> : <targets> ;
1367
1368	AddDriversToContainer $(HAIKU_NET_BOOT_ARCHIVE_CONTAINER_NAME)
1369		: $(relativeDirectoryTokens) : $(targets) ;
1370}
1371
1372rule AddNewDriversToNetBootArchive relativeDirectoryTokens : targets
1373{
1374	# AddNewDriversToNetBootArchive <relative directory> : <targets> ;
1375
1376	AddNewDriversToContainer $(HAIKU_NET_BOOT_ARCHIVE_CONTAINER_NAME)
1377		: $(relativeDirectoryTokens) : $(targets) ;
1378}
1379
1380rule AddDriverRegistrationToNetBootArchive relativeDirectoryTokens : target
1381	: links
1382{
1383	# AddDriverRegistrationToNetBootArchive <directory> : <link target>
1384	#	: <link names> ] ;
1385
1386	AddDriverRegistrationToContainer $(HAIKU_NET_BOOT_ARCHIVE_CONTAINER_NAME)
1387		: $(relativeDirectoryTokens) : $(target) : $(links) ;
1388}
1389
1390rule AddBootModuleSymlinksToNetBootArchive targets
1391{
1392	# AddBootModuleSymlinksToNetBootArchive <targets> ;
1393
1394	AddBootModuleSymlinksToContainer $(HAIKU_NET_BOOT_ARCHIVE_CONTAINER_NAME)
1395		: $(targets) ;
1396}
1397
1398rule CreateNetBootArchiveMakeDirectoriesScript script
1399{
1400	CreateContainerMakeDirectoriesScript
1401		$(HAIKU_NET_BOOT_ARCHIVE_CONTAINER_NAME) : $(script) ;
1402}
1403
1404rule CreateNetBootArchiveCopyFilesScript script
1405{
1406	CreateContainerCopyFilesScript $(HAIKU_NET_BOOT_ARCHIVE_CONTAINER_NAME)
1407		: $(script) ;
1408}
1409
1410rule BuildNetBootArchive archive : scripts
1411{
1412	# BuildNetBootArchive <archive> : <scripts> ;
1413
1414	local mainScript = build_archive ;
1415	SEARCH on $(mainScript) = [ FDirName $(HAIKU_TOP) build scripts ] ;
1416
1417	Depends $(archive) : $(mainScript) $(scripts) ;
1418	BuildNetBootArchive1 $(archive) : $(mainScript)
1419		$(scripts:R=$(HAIKU_ABSOLUTE_OUTPUT_DIR)) ;
1420}
1421
1422actions BuildNetBootArchive1
1423{
1424	$(2[1]) $(1) $(2[2-])
1425}
1426
1427
1428#pragma mark - Floppy Boot Archive rules
1429
1430
1431rule AddDirectoryToFloppyBootArchive directoryTokens
1432{
1433	# AddDirectoryToFloppyBootArchive <directoryTokens>
1434
1435	return [ AddDirectoryToContainer $(HAIKU_FLOPPY_BOOT_IMAGE_CONTAINER_NAME)
1436		: $(directoryTokens) ] ;
1437}
1438
1439rule AddFilesToFloppyBootArchive directory : targets : destName
1440{
1441	# AddFilesToFloppyBootArchive <directory> : <targets> [ : dest name ]
1442
1443	AddFilesToContainer $(HAIKU_FLOPPY_BOOT_IMAGE_CONTAINER_NAME) : $(directory)
1444		: $(targets) : $(destName) ;
1445}
1446
1447rule AddSymlinkToFloppyBootArchive directoryTokens : linkTarget : linkName
1448{
1449	# AddSymlinkToFloppyBootArchive <directory> : <link target>
1450	#	[ : <link name> ] ;
1451
1452	AddSymlinkToContainer $(HAIKU_FLOPPY_BOOT_IMAGE_CONTAINER_NAME)
1453		: $(directoryTokens) : $(linkTarget) : $(linkName) ;
1454}
1455
1456rule AddDriversToFloppyBootArchive relativeDirectoryTokens : targets
1457{
1458	# AddDriversToFloppyBootArchive <relative directory> : <targets> ;
1459
1460	AddDriversToContainer $(HAIKU_FLOPPY_BOOT_IMAGE_CONTAINER_NAME)
1461		: $(relativeDirectoryTokens) : $(targets) ;
1462}
1463
1464rule AddNewDriversToFloppyBootArchive relativeDirectoryTokens : targets
1465{
1466	# AddNewDriversToFloppyBootArchive <relative directory> : <targets> ;
1467
1468	AddNewDriversToContainer $(HAIKU_FLOPPY_BOOT_IMAGE_CONTAINER_NAME)
1469		: $(relativeDirectoryTokens) : $(targets) ;
1470}
1471
1472rule AddDriverRegistrationToFloppyBootArchive relativeDirectoryTokens : target
1473	: links
1474{
1475	# AddDriverRegistrationToFloppyBootArchive <directory> : <link target>
1476	#	: <link names> ] ;
1477
1478	AddDriverRegistrationToContainer $(HAIKU_FLOPPY_BOOT_IMAGE_CONTAINER_NAME)
1479		: $(relativeDirectoryTokens) : $(target) : $(links) ;
1480}
1481
1482rule AddBootModuleSymlinksToFloppyBootArchive targets
1483{
1484	# AddBootModuleSymlinksToFloppyBootArchive <targets> ;
1485
1486	AddBootModuleSymlinksToContainer $(HAIKU_FLOPPY_BOOT_IMAGE_CONTAINER_NAME)
1487		: $(targets) ;
1488}
1489
1490rule CreateFloppyBootArchiveMakeDirectoriesScript script
1491{
1492	CreateContainerMakeDirectoriesScript
1493		$(HAIKU_FLOPPY_BOOT_IMAGE_CONTAINER_NAME) : $(script) ;
1494}
1495
1496rule CreateFloppyBootArchiveCopyFilesScript script
1497{
1498	CreateContainerCopyFilesScript $(HAIKU_FLOPPY_BOOT_IMAGE_CONTAINER_NAME)
1499		: $(script) ;
1500}
1501
1502rule BuildFloppyBootArchive archive : scripts
1503{
1504	# BuildHFloppyBootArchive <archive> : <scripts> ;
1505
1506	local mainScript = build_archive ;
1507	SEARCH on $(mainScript) = [ FDirName $(HAIKU_TOP) build scripts ] ;
1508
1509	Depends $(archive) : $(mainScript) $(scripts) ;
1510	BuildFloppyBootArchive1 $(archive) : $(mainScript)
1511		$(scripts:R=$(HAIKU_ABSOLUTE_OUTPUT_DIR)) ;
1512}
1513
1514actions BuildFloppyBootArchive1
1515{
1516	$(2[1]) $(1) $(2[2-])
1517}
1518
1519# warning: that is quite x86 dependant...
1520
1521rule BuildFloppyBootImage image : haikuLoader : archive
1522{
1523	Depends $(image) : $(haikuLoader) ;
1524	Depends $(image) : $(archive) ;
1525	#MakeLocateDebug $(image) ;
1526	FLOPPY_IMAGE_SIZE on $(image) = $(HAIKU_BOOT_FLOPPY_IMAGE_SIZE) ;
1527	ARCHIVE_IMAGE_OFFSET on $(image) = $(HAIKU_BOOT_ARCHIVE_IMAGE_OFFSET) ;
1528	BuildFloppyBootImage1 $(image) : $(haikuLoader) $(archive) ;
1529	if $(HAIKU_KERNEL_PLATFORM) = atari_m68k {
1530		Depends $(image) : <build>fixup_tos_boot_checksum ;
1531		BuildFloppyBootImageFixupM68K $(image)
1532			: <build>fixup_tos_boot_checksum ;
1533	}
1534	if $(HAIKU_KERNEL_PLATFORM) = amiga_m68k {
1535		Depends $(image) : <build>fixup_amiga_boot_checksum ;
1536		BuildFloppyBootImageFixupM68K $(image)
1537			: <build>fixup_amiga_boot_checksum ;
1538	}
1539}
1540
1541actions BuildFloppyBootImage1
1542{
1543	haiku_loader_size=`stat -c %s "$(>[1])"`
1544	drivers_tgz_size=`stat -c %s "$(>[2])"`
1545	if [ $? -ne 0 ] ; then
1546		# FreeBSD's stat command don't support -c/--format option
1547		# and use %z specifier for file size
1548		haiku_loader_size=`stat -f %z "$(>[1])"`
1549		drivers_tgz_size=`stat -f %z "$(>[2])"`
1550	fi
1551	archive_image_offset=`echo "$(ARCHIVE_IMAGE_OFFSET) * 1024" | bc`
1552	floppy_tgz_size=\
1553		`echo "($(FLOPPY_IMAGE_SIZE) - $(ARCHIVE_IMAGE_OFFSET)) * 1024" | bc`
1554	if [ $haiku_loader_size -gt $archive_image_offset ] ; then
1555		echo "Error: $(>[1]) is too big ($haiku_loader_size) to fit "
1556		echo "       before the boot archive starting at $archive_image_offset!"
1557		exit 1
1558	fi
1559	if [ $drivers_tgz_size -gt $floppy_tgz_size ] ; then
1560		echo "Error: $(>[2]) is too big ($drivers_tgz_size) to fit "
1561		echo "       in the boot floppy ($floppy_tgz_size)!"
1562		exit 1
1563	fi
1564	$(RM) $(<)
1565	# make an empty image
1566	dd if=/dev/zero of=$(<) bs=1k count=$(FLOPPY_IMAGE_SIZE)
1567	# add haiku_loader
1568	dd if=$(>[1]) of=$(<) conv=notrunc
1569	# add the boot drivers tgz archive
1570	dd if=$(>[2]) of=$(<) bs=$(ARCHIVE_IMAGE_OFFSET)k seek=1 conv=notrunc
1571}
1572
1573actions BuildFloppyBootImageFixupM68K
1574{
1575	# fixup the boot sector checksum
1576	$(>[1]) $(<)
1577}
1578
1579#pragma mark - CD Boot Image rules
1580
1581rule BuildCDBootImage image : bootfloppy : bootefi : extrafiles
1582{
1583	Depends $(image) : $(bootfloppy) ;
1584	Depends $(image) : $(bootefi) ;
1585	Depends $(image) : $(extrafiles) ;
1586	BOOTIMG on $(image) = $(bootfloppy) ;
1587
1588	if $(HAIKU_NIGHTLY_BUILD) = 1 {
1589		VOLID on $(image) = haiku-nightly-$(TARGET_ARCH) ;
1590	} else {
1591		VOLID on $(image) = haiku-$(HAIKU_VERSION)-$(TARGET_ARCH) ;
1592	}
1593
1594	if $(HAIKU_ANYBOOT_LEGACY) = 1 {
1595		BuildCDBootImageMBR $(image) : $(bootfloppy) $(extrafiles) ;
1596	} else {
1597		BOOTEFI on $(image) = $(bootefi) ;
1598		BuildCDBootImageEFI $(image) : $(bootfloppy) $(bootefi) $(extrafiles) ;
1599	}
1600}
1601
1602actions BuildCDBootImageMBR
1603{
1604	$(RM) $(<)
1605	xorriso -as mkisofs -b $(BOOTIMG) -r -J -V $(VOLID) -o $(<) $(>[1]) $(>[2-])
1606}
1607
1608actions BuildCDBootImageEFI
1609{
1610	$(RM) $(<)
1611	xorriso -as mkisofs -b $(BOOTIMG) -eltorito-alt-boot -no-emul-boot -e $(BOOTEFI) \
1612		-r -J -V $(VOLID) -o $(<) $(>[1]) $(>[2]) $(>[3-])
1613}
1614
1615
1616#pragma mark - CD Boot PPC Image rules
1617
1618rule BuildCDBootPPCImage image : hfsmaps : elfloader : coffloader : chrpscript
1619	: extrafiles
1620{
1621	Depends $(image) : $(elfloader) ;
1622	Depends $(image) : $(coffloader) ;
1623	Depends $(image) : $(chrpscript) ;
1624	Depends $(image) : $(extrafiles) ;
1625	Depends $(image) : $(hfsmaps) ;
1626	MAPS on $(image) = $(hfsmaps) ;
1627
1628	if $(HAIKU_NIGHTLY_BUILD) = 1 {
1629		VOLID on $(image) = haiku-nightly-$(TARGET_ARCH) ;
1630	} else {
1631		VOLID on $(image) = haiku-$(HAIKU_VERSION)-$(TARGET_ARCH) ;
1632	}
1633
1634	BuildCDBootPPCImage1 $(image) : $(elfloader) $(coffloader) $(chrpscript)
1635		$(extrafiles) ;
1636}
1637
1638actions BuildCDBootPPCImage1 bind MAPS
1639{
1640	$(RM) $(<)
1641	mkdir -p $(HAIKU_OUTPUT_DIR)/cd/ppc
1642	mkdir -p $(HAIKU_OUTPUT_DIR)/cd/boot
1643	# CHRP Boot script
1644	cp $(>[3]) $(HAIKU_OUTPUT_DIR)/cd/ppc/bootinfo.txt
1645	cp $(>[3]) $(HAIKU_OUTPUT_DIR)/cd/boot/boot.chrp
1646	# Haiku Bootloaders
1647	cp $(>[2]) $(HAIKU_OUTPUT_DIR)/cd/boot/haikuloader.xcf
1648	cp $(>[1]) $(HAIKU_OUTPUT_DIR)/cd/boot/haikuloader.elf
1649	# Extras (readme files, etc)
1650	cp $(>[4]) $(HAIKU_OUTPUT_DIR)/cd/
1651
1652	# Xorriso doesn't have map and some other required tools
1653	# to make bootable PowerPC images
1654	genisoimage -v -hfsplus -map $(MAPS) \
1655		-hfs-bless $(HAIKU_OUTPUT_DIR)/cd/boot -part -no-desktop \
1656		-hfs-parms MAX_XTCSIZE=2656248 -hfs-volid Haiku \
1657		--chrp-boot -r -J -o $(<) $(HAIKU_OUTPUT_DIR)/cd
1658
1659	$(RM) -r $(HAIKU_OUTPUT_DIR)/cd
1660}
1661
1662#pragma mark - EFI System Partition rules
1663
1664rule BuildEfiSystemPartition image : efiLoader
1665{
1666	local macVolumeIcon = [ FDirName
1667		$(HAIKU_TOP) data artwork VolumeIcon.icns ] ;
1668
1669	Depends $(image) : $(efiLoader) ;
1670	Depends $(image) : $(macVolumeIcon) ;
1671
1672	switch $(TARGET_ARCH) {
1673		case x86_64 :
1674			EFINAME on $(image) = "BOOTX64.EFI" ;
1675		case arm :
1676			EFINAME on $(image) = "BOOTARM.EFI" ;
1677		case arm64 :
1678			EFINAME on $(image) = "BOOTAA64.EFI" ;
1679		case riscv32 :
1680			EFINAME on $(image) = "BOOTRISCV32.EFI" ;
1681		case riscv64 :
1682			EFINAME on $(image) = "BOOTRISCV64.EFI" ;
1683		case * :
1684			Exit "Error: Unknown EFI architecture!" ;
1685	}
1686
1687	EFIICON on $(image) = $(macVolumeIcon) ;
1688
1689	BuildEfiSystemPartition1 $(image) : $(efiLoader) ;
1690}
1691
1692actions BuildEfiSystemPartition1
1693{
1694	$(RM) $(<)
1695	dd if=/dev/zero of=$(<) bs=1024 count=2880
1696	mformat -i $(<) -f 2880
1697	mmd -D s -i $(<) ::/EFI
1698	mmd -D s -i $(<) ::/EFI/BOOT
1699	mcopy -D o -i $(<) $(EFIICON) ::/.VolumeIcon.icns
1700	mcopy -D o -i $(<) $(>) ::/EFI/BOOT/$(EFINAME)
1701}
1702