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