1# -*- mode: makefile;-*-
2#
3# Copyright (C) 2010-2012 Apple Inc. All rights reserved.
4#
5# MakeInc.top is the top-level makefile for the xnu
6# build system. All the main XBS targets
7# (like "installhdrs") are defined here, as
8# well as globals that can be overridden on 
9# the command-line by the user.
10#
11# This makefile's main purpose is to bootstrap
12# the user's intent ("build these 3 kernels")
13# into 3 single-architecture builds that each
14# invoke the recursive make build system.
15# As such, we have no knowledge of how to build
16# a kernel or perform actions other than
17# invoking a sub-make with a different
18# current directory, makefile, and target. One
19# side effect of this is that each
20# single-architecture build is responsible for
21# inserting its build products into the final
22# multi-architecture output files. To avoid
23# races, these aggregating stages for 
24# "primary" build configs are done in serial.
25# 
26
27export MakeInc_cmd=${VERSDIR}/makedefs/MakeInc.cmd
28
29include $(MakeInc_cmd)
30
31
32#
33# Architecture Configuration options
34#
35
36# Default to current kernel architecture
37ifeq ($(PLATFORM),iPhoneOS)
38     override DEFAULT_ARCH_CONFIG := ARM
39else ifeq ($(PLATFORM),iPhoneSimulator)
40     override DEFAULT_ARCH_CONFIG := X86_64
41else
42     override DEFAULT_ARCH_CONFIG := X86_64
43endif
44
45
46# Accept either explicit ARCH_CONFIGS or XBS-style RC_ARCHS
47ifndef ARCH_CONFIGS
48ifdef RC_ARCHS
49ARCH_CONFIGS 	:= $(shell printf "%s" "$(RC_ARCHS)" | $(TR) a-z A-Z | sed -E 's/ARMV[0-9][A-Z]?/ARM/g' | $(TR) " " "\n" | sort -u | $(TR) "\n" " ")
50else
51ARCH_CONFIGS	:= DEFAULT
52endif
53endif
54
55#
56# Kernel Configuration options  
57#
58
59ifeq ($(RC_ProjectName),xnu_debug)
60override DEFAULT_KERNEL_CONFIG := DEBUG
61else ifeq ($(PLATFORM),iPhoneOS)
62override DEFAULT_KERNEL_CONFIG := DEVELOPMENT
63else
64override DEFAULT_KERNEL_CONFIG := RELEASE
65endif
66
67# If KERNEL_CONFIGS is specified it should override default
68ifndef KERNEL_CONFIGS
69KERNEL_CONFIGS := DEFAULT
70endif
71
72#
73# Machine Configuration options  
74#
75
76override DEFAULT_I386_MACHINE_CONFIG := NONE
77override DEFAULT_X86_64_MACHINE_CONFIG := NONE
78
79
80# This is typically never specified (TARGET_CONFIGS is used)
81ifndef MACHINE_CONFIGS
82MACHINE_CONFIGS 	:= DEFAULT
83endif
84
85#
86# Target configuration options.  NOTE - target configurations will 
87# override ARCH_CONFIGS and KERNEL_CONFIGS and MACHINE_CONFIGS.
88#
89# Target configs come in groups of three parameters.  The first is the 
90# kernel configuration, the second is the architecture configuration,
91# and the third is the machine configuration.  You may pass in as
92# many groups of configurations as you wish.  Each item passed in is
93# seperated by whitespace.
94#
95# Example:
96#	TARGET_CONFIGS="release ppc default debug i386 default release arm MX31ADS"
97# Parameters may be in upper or lower case (they are converted to upper).
98#
99# "default" parameter is a special case.  It means use the default value for 
100# that parameter.  Here are the default values for each configuration:
101#
102# default kernel configuration = DEFAULT_KERNEL_CONFIG
103# default architecture configuration = system architecture where you are running make.
104
105
106ifndef TARGET_CONFIGS
107ifneq ($(PRODUCT_CONFIGS),)
108# generate TARGET_CONFIGS using KERNEL_CONFIGS and PRODUCT_CONFIGS
109TARGET_CONFIGS := $(foreach my_kernel_config,$(KERNEL_CONFIGS),$(foreach my_product_config,$(shell printf "%s" "$(PRODUCT_CONFIGS)" | $(TR) A-Z a-z),$(my_kernel_config) $(subst ;, ,$(call function_lookup_product,$(my_product_config)))))
110else ifneq ($(filter %_embedded,$(MAKECMDGOALS)),)
111# generate TARGET_CONFIGS for all kernel configs and products in the device map
112TARGET_CONFIGS := $(foreach my_kernel_config,$(KERNEL_CONFIGS_EMBEDDED),$(foreach my_arch_config,$(ARCH_CONFIGS_EMBEDDED),$(foreach my_product_config,$(DEVICEMAP_PRODUCTS_$(my_arch_config)),$(my_kernel_config) $(subst ;, ,$(call function_lookup_product,$(my_product_config))))))
113else
114# generate TARGET_CONFIGS using KERNEL_CONFIGS and ARCH_CONFIGS and MACHINE_CONFIGS (which defaults to "DEFAULT")
115TARGET_CONFIGS := $(foreach my_kern_config, $(KERNEL_CONFIGS), $(foreach my_arch_config, $(ARCH_CONFIGS), $(foreach my_machine_config, $(MACHINE_CONFIGS), $(my_kern_config) $(my_arch_config) $(my_machine_config))))
116endif
117endif
118
119ifeq ($(TARGET_CONFIGS),)
120$(error No TARGET_CONFIGS specified)
121endif
122
123TARGET_CONFIGS_UC := $(strip $(shell printf "%s" "$(TARGET_CONFIGS)" | $(TR) a-z A-Z))
124
125#
126# Build Configurations
127#
128# TARGET_CONFIGS is unwieldy for use in Makefiles. Convert them to
129# "build configurations" which are tuples joined by "^". For
130# example, "RELEASE I386 DEFAULT DEVELOPMENT ARM DEFAULT" becomes
131# "RELEASE^I386^NONE DEVELOPMENT^ARM^S5L8920X", which can be looped
132# over trivially. PRIMARY_BUILD_CONFIGS is the first config
133# for each architecture, used primarily for machine-dependent recursion.
134
135BUILD_CONFIGS = $(call function_create_build_configs, $(TARGET_CONFIGS_UC))
136
137PRIMARY_ARCHS = $(strip $(sort $(foreach build_config, $(BUILD_CONFIGS), $(call function_extract_arch_config_from_build_config, $(build_config)))))
138PRIMARY_BUILD_CONFIGS = $(strip $(foreach arch, $(PRIMARY_ARCHS), $(firstword $(foreach build_config, $(BUILD_CONFIGS), $(if $(filter $(arch),$(call function_extract_arch_config_from_build_config, $(build_config))), $(build_config), )))))
139NON_PRIMARY_BUILD_CONFIGS = $(strip $(filter-out $(PRIMARY_BUILD_CONFIGS), $(BUILD_CONFIGS)))
140FIRST_BUILD_CONFIG = $(firstword $(BUILD_CONFIGS))
141
142# $(warning PRIMARY_ARCHS is $(PRIMARY_ARCHS))
143# $(warning TARGET_CONFIGS is $(TARGET_CONFIGS))
144# $(warning BUILD_CONFIGS is $(BUILD_CONFIGS))
145# $(warning PRIMARY_BUILD_CONFIGS is $(PRIMARY_BUILD_CONFIGS))
146# $(warning NON_PRIMARY_BUILD_CONFIGS is $(NON_PRIMARY_BUILD_CONFIGS))
147
148MEMORY_SIZE := $(shell /usr/sbin/sysctl -n hw.memsize)
149
150# Embedded kernels use LTO by default.
151ifeq ($(PLATFORM),iPhoneOS)
152export BUILD_LTO := 1
153endif
154
155LARGE_BUILD_FOOTPRINT := $(BUILD_LTO)
156
157ifeq ($(LARGE_BUILD_FOOTPRINT),1)
158RAM_PER_KERNEL_BUILD := 8589934592
159FLOCK_SIZE := $(shell if [ $(MEMORY_SIZE) -le $$((1 * $(RAM_PER_KERNEL_BUILD))) ]; then echo 1; elif [ $(MEMORY_SIZE) -gt $$((8 * $(RAM_PER_KERNEL_BUILD))) ]; then echo 8; else expr $(MEMORY_SIZE) / $(RAM_PER_KERNEL_BUILD); fi )
160else
161RAM_PER_KERNEL_BUILD := 268435456
162FLOCK_SIZE := $(shell if [ $(MEMORY_SIZE) -le $$((2 * $(RAM_PER_KERNEL_BUILD))) ]; then echo 2; elif [ $(MEMORY_SIZE) -gt $$((8 * $(RAM_PER_KERNEL_BUILD))) ]; then echo 8; else expr $(MEMORY_SIZE) / $(RAM_PER_KERNEL_BUILD); fi )
163endif
164
165# $(warning Building $(FLOCK_SIZE) kernels in parallel)
166
167#
168# TOP_LEVEL_EACH_BUILD_CONFIG_BOOTSTRAP_template
169#
170# $(1) is the name of the makefile target to invoke for the each build config
171#      after setting up the parallel hierarchy in the TARGET directory
172# $(2) is an optional suffix on the TARGET directory, which might even be
173#      "/.."
174# $(3) are any dependencies for the bootstrap target
175# $(4) are any dependencies that are expanded per-build config to another bootstrap target
176# $(5) is how many build configurations to build in parallel
177# $(6) is which build configs to build in parallel
178#
179# Since building many configurations in parallel may overwhelm the system,
180# we try to throttle behavior into more managable "flocks" of N configurations
181# at once, by creating a dependency on all members of the previous flock.
182
183define TOP_LEVEL_EACH_BUILD_CONFIG_BOOTSTRAP_template
184
185# Create a list of synthesized targets for each build config
186$(1)_bootstrap_target_list = $$(addprefix $(1)_bootstrap_,$(6))
187
188.PHONY: $$($(1)_bootstrap_target_list)
189
190$$(eval $$(call _function_generate_flock_groupings,$(1),$$(wordlist 1,$(5),$(6)),$$(wordlist $(call increment,$(5)),$$(words $(6)),$(6)),,$(5)))
191
192$$($(1)_bootstrap_target_list): $(1)_bootstrap_% : $(1)_flock_dep_for_% $$(addsuffix _bootstrap_%,$(4)) $(3)
193	$$(_v)$$(MKDIR) $${OBJROOT}/$$(call function_convert_build_config_to_objdir,$$(patsubst $(1)_bootstrap_%,%,$$@))$(2)
194	$$(_v)$${MAKE} 													        \
195		-C $${OBJROOT}/$$(call function_convert_build_config_to_objdir,$$(patsubst $(1)_bootstrap_%,%,$$@))$(2)		\
196		-f $${SRCROOT}/Makefile												\
197		CURRENT_KERNEL_CONFIG=$$(call function_extract_kernel_config_from_build_config,$$(patsubst $(1)_bootstrap_%,%,$$@)) \
198		CURRENT_ARCH_CONFIG=$$(call function_extract_arch_config_from_build_config,$$(patsubst $(1)_bootstrap_%,%,$$@))	  \
199		CURRENT_MACHINE_CONFIG=$$(call function_extract_machine_config_from_build_config,$$(patsubst $(1)_bootstrap_%,%,$$@))	\
200		CURRENT_BUILD_CONFIG=$$(patsubst $(1)_bootstrap_%,%,$$@)							\
201		PRIMARY_BUILD_CONFIGS="$(PRIMARY_BUILD_CONFIGS)"							\
202		SOURCE=$${SRCROOT}/												\
203		RELATIVE_SOURCE_PATH=.											\
204		TARGET=$${OBJROOT}/$$(call function_convert_build_config_to_objdir,$$(patsubst $(1)_bootstrap_%,%,$$@))$(2)/	\
205		OBJPATH=$${OBJROOT}/$$(call function_convert_build_config_to_objdir,$$(patsubst $(1)_bootstrap_%,%,$$@))	\
206		$(1)
207
208.PHONY: $(1)_bootstrap
209
210$(1)_bootstrap: $$($(1)_bootstrap_target_list)
211endef
212
213#
214# TOP_LEVEL_FLOCK_DEPENDENCY_template
215#
216# $(1) is the Makefile target we are building for
217# $(2) are the members of the current flock
218# $(3) is what the flock depends on. None of the build
219#      configs in $(2) will start building until all of
220#      $(3) are done building
221
222define TOP_LEVEL_FLOCK_DEPENDENCY_template
223
224.PHONY: $(addprefix $(1)_flock_dep_for_,$(2))
225
226$(addprefix $(1)_flock_dep_for_,$(2)): $(addprefix $(1)_bootstrap_,$(3))
227
228endef
229
230# $(1) is the Makefile target we are building for
231# $(2) is the first flock (5 build configs)
232# $(3) is the rest of the build configs
233# $(4) is the build configs that the first flock depends on
234# $(5) is the flock size
235_function_generate_flock_groupings = $(if $(3), $(call _function_generate_flock_groupings,$(1),$(wordlist 1,$(5),$(3)),$(wordlist $(call increment,$(5)),$(words $(3)),$(3)),$(2),$(5))) $(call TOP_LEVEL_FLOCK_DEPENDENCY_template,$(1),$(2),$(4))
236
237#
238# Setup pass for build system tools
239#
240
241generated_top_level_build_setup = $(call TOP_LEVEL_EACH_BUILD_CONFIG_BOOTSTRAP_template,build_setup,/..,,,$(FLOCK_SIZE),$(FIRST_BUILD_CONFIG))
242ifeq ($(VERBOSE),YES)
243$(warning Generate makefile fragment: $(generated_top_level_build_setup))
244endif
245$(eval $(generated_top_level_build_setup))
246
247.PHONY: setup
248
249setup: build_setup_bootstrap
250
251#
252# Install kernel header files
253#
254.PHONY: exporthdrs exporthdrs_mi exporthdrs_md
255
256exporthdrs: exporthdrs_mi exporthdrs_md 
257
258#
259# Install machine independent kernel header files
260#
261
262generated_top_level_build_exporthdrs_mi = $(call TOP_LEVEL_EACH_BUILD_CONFIG_BOOTSTRAP_template,build_exporthdrs_mi,,setup,,1,$(FIRST_BUILD_CONFIG))
263ifeq ($(VERBOSE),YES)
264$(warning Generate makefile fragment: $(generated_top_level_build_exporthdrs_mi))
265endif
266$(eval $(generated_top_level_build_exporthdrs_mi))
267
268exporthdrs_mi: build_exporthdrs_mi_bootstrap
269
270#
271# Install machine dependent kernel header files 
272#
273
274generated_top_level_build_exporthdrs_md = $(call TOP_LEVEL_EACH_BUILD_CONFIG_BOOTSTRAP_template,build_exporthdrs_md,,setup,,$(FLOCK_SIZE),$(PRIMARY_BUILD_CONFIGS))
275ifeq ($(VERBOSE),YES)
276$(warning Generate makefile fragment: $(generated_top_level_build_exporthdrs_md))
277endif
278$(eval $(generated_top_level_build_exporthdrs_md))
279
280exporthdrs_md: build_exporthdrs_md_bootstrap
281
282#
283# Install kernel header files
284#
285
286.PHONY: installhdrs installhdrs_mi installhdrs_md
287
288ifeq ($(RC_ProjectName),xnu_debug)
289installhdrs:
290	@:
291else
292
293installhdrs: installhdrs_mi installhdrs_md
294endif
295
296.PHONY: installhdrs_embedded
297
298installhdrs_embedded: installhdrs
299
300#
301# Install machine independent header files
302#
303
304generated_top_level_build_installhdrs_mi = $(call TOP_LEVEL_EACH_BUILD_CONFIG_BOOTSTRAP_template,build_installhdrs_mi,,setup exporthdrs_mi,,1,$(FIRST_BUILD_CONFIG))
305ifeq ($(VERBOSE),YES)
306$(warning Generate makefile fragment: $(generated_top_level_build_installhdrs_mi))
307endif
308$(eval $(generated_top_level_build_installhdrs_mi))
309
310installhdrs_mi: exporthdrs_mi build_installhdrs_mi_bootstrap
311
312#
313# Install machine dependent kernel header files 
314#
315
316generated_top_level_build_installhdrs_md = $(call TOP_LEVEL_EACH_BUILD_CONFIG_BOOTSTRAP_template,build_installhdrs_md,,setup exporthdrs_md,,$(FLOCK_SIZE),$(PRIMARY_BUILD_CONFIGS))
317ifeq ($(VERBOSE),YES)
318$(warning Generate makefile fragment: $(generated_top_level_build_installhdrs_md))
319endif
320$(eval $(generated_top_level_build_installhdrs_md))
321
322installhdrs_md: exporthdrs_md build_installhdrs_md_bootstrap
323
324#
325# Build all architectures for all Configuration/Architecture options
326#
327
328generated_top_level_build_all = $(call TOP_LEVEL_EACH_BUILD_CONFIG_BOOTSTRAP_template,build_all,,setup exporthdrs,,$(FLOCK_SIZE),$(BUILD_CONFIGS))
329ifeq ($(VERBOSE),YES)
330$(warning Generate makefile fragment: $(generated_top_level_build_all))
331endif
332$(eval $(generated_top_level_build_all))
333
334.PHONY: build
335
336build: build_all_bootstrap
337
338#
339# Post-process build results
340#
341
342generated_top_level_config_all = $(call TOP_LEVEL_EACH_BUILD_CONFIG_BOOTSTRAP_template,config_all,,setup,build_all,$(FLOCK_SIZE),$(BUILD_CONFIGS))
343ifeq ($(VERBOSE),YES)
344$(warning Generate makefile fragment: $(generated_top_level_config_all))
345endif
346$(eval $(generated_top_level_config_all))
347
348.PHONY: all
349
350all: config_all_bootstrap
351
352.PHONY: all_embedded
353
354all_embedded: all
355
356#
357# Install kernel and header files
358#
359
360generated_top_level_build_install_primary = $(call TOP_LEVEL_EACH_BUILD_CONFIG_BOOTSTRAP_template,build_install_primary,,setup,config_all,1,$(PRIMARY_BUILD_CONFIGS))
361ifeq ($(VERBOSE),YES)
362$(warning Generate makefile fragment: $(generated_top_level_build_install_primary))
363endif
364$(eval $(generated_top_level_build_install_primary))
365
366generated_top_level_build_install_non_primary = $(call TOP_LEVEL_EACH_BUILD_CONFIG_BOOTSTRAP_template,build_install_non_primary,,setup,config_all,$(FLOCK_SIZE),$(NON_PRIMARY_BUILD_CONFIGS))
367ifeq ($(VERBOSE),YES)
368$(warning Generate makefile fragment: $(generated_top_level_build_install_non_primary))
369endif
370$(eval $(generated_top_level_build_install_non_primary))
371
372
373.PHONY: install
374
375ifeq ($(RC_ProjectName),xnu_debug)
376
377install: build_install_primary_bootstrap build_install_non_primary_bootstrap
378else ifeq ($(RC_ProjectName),xnu_headers_Sim)
379install: installhdrs
380else
381
382install: all installhdrs installman build_install_primary_bootstrap build_install_non_primary_bootstrap
383endif
384
385.PHONY: install_embedded
386
387install_embedded: install
388
389#
390#  Install man pages
391#
392
393generated_top_level_build_installman = $(call TOP_LEVEL_EACH_BUILD_CONFIG_BOOTSTRAP_template,build_installman,,setup,,1,$(FIRST_BUILD_CONFIG))
394ifeq ($(VERBOSE),YES)
395$(warning Generate makefile fragment: $(generated_top_level_build_installman))
396endif
397$(eval $(generated_top_level_build_installman))
398
399.PHONY: installman
400
401installman: setup build_installman_bootstrap
402
403#
404# Install source tree
405#
406.PHONY: installsrc
407
408installsrc:
409	@echo INSTALLSRC $(SRCROOT)
410	$(_v)$(MKDIR) $(SRCROOT)
411	$(_v)($(TAR) -c --mode go=r,+X --no-ignore-case --exclude .git --exclude .svn --exclude cscope.\* --exclude BUILD --exclude \*~ -f - .) | (cd $(SRCROOT) && $(TAR) --no-same-owner -xf -)
412
413
414#
415# Clean up source tree
416#
417.PHONY: clean
418
419clean:
420	@:
421
422#
423# Build source file list for cscope database and tags
424#
425cscope.files:
426	@echo "Building file list for cscope and tags"
427	@find . -name '*.h' -type f | grep -v ^..BUILD > _cscope.files 2> /dev/null
428	@find . -name '*.defs' -type f | grep -v ^..BUILD >> _cscope.files 2> /dev/null
429	@find . -name '*.c' -type f | grep -v ^..BUILD >> _cscope.files 2> /dev/null
430	@find . -name '*.cpp' -type f | grep -v ^..BUILD >> _cscope.files 2> /dev/null
431	@find . -name '*.s' -type f | grep -v ^..BUILD >> _cscope.files 2> /dev/null
432	@find . -name '*.h.template' -type f | grep -v ^..BUILD >> _cscope.files 2> /dev/null
433	@echo -k -q -c > cscope.files 2> /dev/null
434	@sort -u < _cscope.files >> cscope.files 2> /dev/null
435	@rm -f _cscope.files _cscope.files2 2> /dev/null
436
437#
438# Build cscope database
439#
440cscope: cscope.files
441	@echo "Building cscope database"
442	@cscope -bvU 2> /dev/null
443
444#
445# Build tags
446#
447tags: cscope.files
448	@echo "Building ctags"
449	@-sed 1d cscope.files | xargs ctags -dtw 2> /dev/null || \
450		echo "Phantom files detected!" 2>&1 > /dev/null
451	@-[ -f TAGS ] || ${MAKE} -f $(firstword $(MAKEFILE_LIST)) TAGS
452
453TAGS: cscope.files
454	@echo "Building etags"
455	@-cat cscope.files | etags -l auto -S - 2> /dev/null
456
457help:
458	@cat README
459
460print_exports:
461	$(_v)printenv | sort
462
463
464generated_top_level_print_exports = $(call TOP_LEVEL_EACH_BUILD_CONFIG_BOOTSTRAP_template,print_exports,,,,1,$(FIRST_BUILD_CONFIG))
465ifeq ($(VERBOSE),YES)
466$(warning Generate makefile fragment: $(generated_top_level_print_exports))
467endif
468$(eval $(generated_top_level_print_exports))
469
470print_exports_first_build_config: print_exports_bootstrap
471