summaryrefslogtreecommitdiffstats
path: root/src/build/mkrules/dist.rules.mk
blob: 7cfcd40f63e2f5134e6b4579cc972dc3f00a1f92 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
# IBM_PROLOG_BEGIN_TAG
# This is an automatically generated prolog.
#
# $Source: src/build/mkrules/dist.rules.mk $
#
# OpenPOWER HostBoot Project
#
# COPYRIGHT International Business Machines Corp. 2012,2014
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied. See the License for the specific language governing
# permissions and limitations under the License.
#
# IBM_PROLOG_END_TAG

#
# Makefile rules defining all the actions for the Hostboot content delivery.
#
# Note: White-space is important for make.  An attempt to make these readable
#       and within the 80-character guidelines was done but in a few cases
#       this was not possible.
#


# Default target to 'ALL' which is equivalent to a release.  ALL will
# build all of the targets as subdirectories within the TARGET_DIR.
.DEFAULT_GOAL := ALL
.PHONY: ALL
ALL: $(addsuffix _TARGET_AS_SUBDIR, $(VALID_TARGETS))

# Dummy target to force building of some ODE mk directives.
.PHONY: FORCE_ALWAYS
FORCE_ALWAYS:

# Comma has special meaning to make function-calls, so need it defined as a
# variable for when you want to concatenate or search against a comma.
COMMA = ,

# ------------- '--test' target directives ---------------------
#
# UNDERSCORE_TEST is set to _test when hbDistribute is called with --test
# and set to the empty string otherwise.
#
# TESTVAR_CHANGED_FILE is a file (.hostboot_testvar_changed) which will hold
# 0 or 1 indicating the --test status for the last execution.  This allows
# us to rebuild a lot of targets when someone switches between test and not.
#
# TESTVAR_CHANGED is a 'function' that will return "changed" or "no-changed"
# depending on the value of the .hostboot_testvar_changed file.  This is used
# to force the TESTVAR_CHANGED_FILE to get rebuilt, which causes anything
# depending on it to also get rebuilt, if the --test parameter has changed.
# The forcing is done via the .PHONY directive.
#
UNDERSCORE_TEST = $(if $(TARGET_TEST),_test)
TESTVAR_CHANGED_FILE = $(TARGET_DIR)/.hostboot_testvar_changed
TESTVAR_CHANGED = $(if $(wildcard $(TESTVAR_CHANGED_FILE)),\
			    $(if $(findstring $(if $(TARGET_TEST),1,0),\
					$(shell cat $(TESTVAR_CHANGED_FILE))),\
					no-change,changed),\
			    changed)
ifeq (changed,$(findstring changed,$(TESTVAR_CHANGED)))
    .PHONY: $(TESTVAR_CHANGED_FILE)
endif
$(TESTVAR_CHANGED_FILE):
	@echo $(if $(TARGET_TEST),1,0) > $@

# ------------- File searching directives ----------------------
# ROOTPATH_WILDCARD and ROOTPATH_WILDCARD_RECURSIVE are useful functions
# for defining targets (in dist.targets.mk) where a .../path/* is wanted.
#
# ROOTPATH_WILDCARD takes a file-path-pattern relative to the ROOTPATH and
# returns all the files matching it.  (Ex. src/build/debug/Hostboot/*.pm).
#
# ROOTPATH_WILDCARD_RECURSIVE takes a file-path relative to the ROOTPATH and
# returns all the files beneith it.  (Ex. src/usr/targeting/common)
#
#
# The utility functions _RECURSIVE_WILDCARD and RECURSIVE_WILDCARD are used
# to perform the searching. _RECURSIVE_WILDCARD finds all files inside a
# specific directory. RECURSIVE_WILDCARD finds all non-directory entities
# inside a specific directory.
#
_RECURSIVE_WILDCARD = $(wildcard $(addsuffix /*,$(1)))
RECURSIVE_WILDCARD = $(if $(call _RECURSIVE_WILDCARD, $(1)),\
			$(foreach path,$(call _RECURSIVE_WILDCARD, $(1)), \
			          $(call RECURSIVE_WILDCARD, $(path))), \
			$(1))

ROOTPATH_WILDCARD = $(subst $(ROOTPATH)/,,$(wildcard $(ROOTPATH)/$(1)))
ROOTPATH_WILDCARD_RECURSIVE = $(subst $(ROOTPATH)/,,\
				$(call RECURSIVE_WILDCARD, $(ROOTPATH)/$(1)))

# ------------- ODE sandbox directives ----------------------
# If we are trying to build the FSP target and SANDBOXROOT/SANDBOXNAME
# is part of the destination directory then we are trying to populate an
# ODE sandbox.  Therefore, we need to define some variables to allow
# running commands in the sandbox.  Otherwise, we'll define a simple echo
# that tells the user what we would have done.
#
# EXECUTE_IN_SANDBOX is the define command for running something in a
# sandbox.  We have to create a small shell script containing what we
# want to run in the sandbox and then point 'workon' at it.
#
ifeq ($(MAKECMDGOALS),fsp_TARGET)
ifdef SANDBOXROOT
ifdef SANDBOXNAME
HB_SANDBOX = $(SANDBOXROOT)/$(SANDBOXNAME)
HB_SANDBOXRC = $(SANDBOXROOT)/hbsandboxrc
HB_SANDBOX_CMD = $(HB_SANDBOX)/src/.sandbox_execute_cmd
ifneq (,$(findstring $(HB_SANDBOX), $(TARGET_DIR)))
HB_FOUND_A_SANDBOX = yes
EXECUTE_IN_SANDBOX = echo "$(strip $(1))" > $(HB_SANDBOX_CMD) && \
		     chmod 700 $(HB_SANDBOX_CMD) && \
		     workon -rc $(HB_SANDBOXRC) -m $(2) -sb $(SANDBOXNAME) \
			    -c $(HB_SANDBOX_CMD) && \
		     rm $(HB_SANDBOX_CMD)
endif
endif
endif
endif

ifndef HB_FOUND_A_SANDBOX
HB_FOUND_A_SANDBOX = no
EXECUTE_IN_SANDBOX = echo "    [CONTEXT=$(strip $(2))] $(1)"
endif

#
# __SOURCE_FOR_TARGET utility function takes a three-tuple of
# [ 1=target, 2=source, 3=comma-separated-targets ].
#
# If the current target (1) is in the list (3) then the source is returned.
# If the list (3) contains 'all' then the source is returned, unless the
# current target (1) is 'tools'.
#
# Ex:
#     __SOURCE_FOR_TARGET("fsp", "foobar", "vpo,tools") => ""
#     __SOURCE_FOR_TARGET("fsp", "foobar", "fsp,vpo") => "foobar"
#     __SOURCE_FOR_TARGET("fsp", "foobar", "all") => "foobar"
#     __SOURCE_FOR_TARGET("tools", "foobar", "all") => ""
#
__SOURCE_FOR_TARGET = $(if $(findstring tools,$(1)), \
			   $(if $(findstring $(1),$(3)),$(2)),\
			   $(if $(or $(findstring $(1),$(3)),\
			             $(findstring all,$(3))\
			         ),\
			         $(2)) \
		       )
# ------------- COPY_FILE directives ----------------------
# COPY_FILES format is <source file>:<comma separated targets>
#
# For each file in COPY_FILES and target, we need to create a recipe of:
# $(TARGET_DIR)$(TARGET)/$(FILE) depends on $(ROOTPATH)/$(FILE)
#
# Since we don't have a $(TARGET) sub-directory when building a single
# target, there is also a recipe for the root $(TARGET_DIR)/$(FILE).
#
# __COPY_TARGET_RULE is a function that creates a single recipe from
#                    parameters (1=filepath, 2=target).
#
# COPY_TARGET_RULE is a function that creates a recipe for each target
#                  from parameter (1=filepath).
#
# Finally, a for-loop is done over every file in COPY_FILES to
# instantiate their recipes.
#
define __COPY_TARGET_RULE
$(TARGET_DIR)$(2)/$(notdir $(1)): $(ROOTPATH)/$(1) $(TESTVAR_CHANGED_FILE)
	@mkdir -p $$(dir $$@)
	@echo "    CP $$(notdir $$@)" && cp -r $$< $$@
endef
define COPY_TARGET_RULE
$(call __COPY_TARGET_RULE,$(1))
$(foreach targ,$(VALID_TARGETS), \
    $(eval $(call __COPY_TARGET_RULE,$(1),/$(targ))))
endef
$(foreach targ,$(COPY_FILES), \
    $(eval $(call COPY_TARGET_RULE,$(firstword $(subst :, ,$(targ))))))

# ------------- COPY_RENAME_FILE directives ----------------------
# COPY_RENAME_FILES format is:
#     <dest file>:<source file>:<comma separated targets>
#
# For each file in COPY_RENAME_FILES and target, we need to create a recipe:
# $(TARGET_DIR)$(TARGET)/$(DEST) depends on $(ROOTPATH)/$(SOURCE)
#
# Since we don't have a $(TARGET) sub-directory when building a single
# target, there is also a recipe for the root $(TARGET_DIR)/$(DEST).
#
# __COPY_RENAME_TARGET_RULE is a function that creates a single recipe from
#                           parameters (1=dest, 2=source, 3=target).
#
# COPY_RENAME_TARGET_RULE is a function that creates a recipe for each target
#                         from parameter (1=dest, 2=source).
#
# Finally, a for-loop is done over every file in COPY_RENAME_FILES to
# instantiate their recipes.
#
define __COPY_RENAME_TARGET_RULE
$(TARGET_DIR)$(3)/$(1): $(ROOTPATH)/$(2) $(TESTVAR_CHANGED_FILE)
	@mkdir -p $$(dir $$@)
	@echo "    CP-RENAME $$(notdir $$<) $$(notdir $$@)" && cp -r $$< $$@
endef
define COPY_RENAME_TARGET_RULE
$(call __COPY_RENAME_TARGET_RULE,$(1),$(2))
$(foreach targ,$(VALID_TARGETS), \
    $(eval $(call __COPY_RENAME_TARGET_RULE,$(1),$(2),/$(targ))))
endef
$(foreach targ,$(COPY_RENAME_FILES), \
    $(eval $(call COPY_RENAME_TARGET_RULE,$(firstword $(subst :, ,$(targ))),$(word 2,$(subst :, ,$(targ))))))

# ------------- LINK_FILE directives ----------------------
# LINK_FILES format is:
#     <dest link>:<source file>:<comma separated targets>
#
# For each file in LINK_FILES and target, we need to create a recipe:
# $(TARGET_DIR)$(TARGET)/$(DEST) depends on $(TARGET_DIR)$(TARGET)/$(SOURCE)
#
# Since we don't have a $(TARGET) sub-directory when building a single
# target, there is also a recipe for the root $(TARGET_DIR)/$(DEST).
#
# __LINK_TARGET_RULE is a function that creates a single recipe from
#                    parameters (1=dest, 2=source, 3=target).
#
# LINK_TARGET_RULE is a function that creates a recipe for each target
#                  from parameter (1=dest, 2=source).
#
# Finally, a for-loop is done over every file in LINK_FILES to
# instantiate their recipes.
#
define __LINK_TARGET_RULE
$(TARGET_DIR)$(3)/$(1): $(TARGET_DIR)$(3)/$(2) $(TESTVAR_CHANGED_FILE)
	@mkdir -p $$(dir $$@)
	@echo "    LINK $$(notdir $$<) $$(notdir $$@)" && \
	    ln -sf $$(notdir $$<) $$@
endef
define LINK_TARGET_RULE
$(call __LINK_TARGET_RULE,$(1),$(2))
$(foreach targ,$(VALID_TARGETS), \
    $(eval $(call __LINK_TARGET_RULE,$(1),$(2),/$(targ))))
endef
$(foreach targ,$(LINK_FILES), \
    $(eval $(call LINK_TARGET_RULE,$(firstword $(subst :, ,$(targ))),$(word 2,$(subst :, ,$(targ))))))

# ------------- TAR file directives ----------------------
# <TARFILE>_CONTENTS format is:
#     <file>[:<kept root of path>]
#
# For each file in TAR_FILES and target, we need to create a recipe:
# $(TARGET_DIR)$(TARGET)/$(TARFILE) depends on [a bunch of content].
#
# The content is determined by iterating through all of the files listed
# in <TARFILE>_CONTENTS and calling TAR_CONTENT_SOURCEFILE.
#
# Since there is potential renaming going on as part of the TAR creation
# process, the recipe template for creating a TAR is longer than the others.
# We need to create a temporary directory, populate it with the content,
# create the TAR file, and then remove the temporary directory.
#
# Since we don't have a $(TARGET) sub-directory when building a single
# target, there is also a recipe for the root $(TARGET_DIR)/$(DEST).
#
# TAR_CONTENT_SOURCEFILE / DESTFILE are functions for extrapolating the
# source / dest names from a line in the <TARFILE>_CONTENTS.  The source
# is simply $(ROOTPATH)/$(FILE).  The dest is relative to the root of the
# TAR file.  When the file in _CONTENTS doesn't have the optional parameter
# then the destination is just the filename, otherwise we have to strip
# everything before the optional parameter from the source path.
#
# __TAR_TARGET_RULE is a function that creates a single recipe from
#                    parameters (1=tar file, 2=target).
#
# TAR_TARGET_RULE is a function that creates a recipe for each target
#                  from parameter (1=tar file).
#
# Finally, a for-loop is done over every file in TAR_FILES to
# instantiate their recipes.
#
TAR_CONTENT_SOURCEFILE = \
    $(addprefix $(ROOTPATH)/,$(firstword $(subst :, ,$(1))))
TAR_CONTENT_DESTFILE = \
    $(addprefix $(word 2, $(subst :, ,$(1))), \
	$(if $(word 2, $(subst :, ,$(1))),\
	    $(lastword $(subst $(word 2, $(subst :, ,$(1))), , \
			   $(firstword $(subst :, ,$(1))))), \
	    $(notdir $(1))\
	 )\
     )

define __TAR_TARGET_RULE
$(TARGET_DIR)$(2)/$(1): TAR_TEMP_DIR:=$$(shell mktemp -du)
$(TARGET_DIR)$(2)/$(1): $$(foreach file, $$($(1)_CONTENTS), \
			    $$(call TAR_CONTENT_SOURCEFILE, $$(file))) \
			$(TESTVAR_CHANGED_FILE)
	@echo "    TAR $$(notdir $$@)"
	@mkdir $$(TAR_TEMP_DIR)
	@$$(foreach file, $$($(1)_CONTENTS), \
	    echo "        ADD-FILE" $$(call TAR_CONTENT_DESTFILE,$$(file)) ; \
	    mkdir -p $$(TAR_TEMP_DIR)/$$(dir \
		    $$(call TAR_CONTENT_DESTFILE, $$(file))) ;\
	    cp $$(call TAR_CONTENT_SOURCEFILE, $$(file)) \
	       $$(addprefix $$(TAR_TEMP_DIR)/, \
	           $$(subst $$(UNDERSCORE_TEST),,\
		       $$(call TAR_CONTENT_DESTFILE, $$(file)))) ;\
	    )
	@tar --create --file $$@ -C $$(TAR_TEMP_DIR)/ .
	@touch $$@
	@rm -rf $$(TAR_TEMP_DIR)
endef
define TAR_TARGET_RULE
$(call __TAR_TARGET_RULE,$(1))
$(foreach targ,$(VALID_TARGETS), \
    $(eval $(call __TAR_TARGET_RULE,$(1),/$(targ))))
endef
$(foreach targ,$(TAR_FILES), \
    $(eval $(call TAR_TARGET_RULE,$(firstword $(subst :, ,$(targ))))))

# ------------- ODE_REMAKE directives ----------------------
# <TARGET>_ODE_REMAKES format is:
#     <fsp dir>:<mk target>:<context>:<dependency>.
#
# For each directive in <TARGET>_ODE_REMAKES, we need to create a recipe
# that calls into the ODE sandbox and performs a 'mk' operation.  In
# order to reduce the number of 'mk' calls done we allow the ODE_REMAKE
# directives to be dependent upon something created for the target (such
# as a tarfile).  __ODE_REMAKE_TARGET is a function that creates a
# filename to touch based on the sandbox subdirectory and context where the
# 'mk' operation is being performed.
#
# The recipes override the environment variable MAKEFLAGS because ODE 'mk'
# interprets this in bad ways.  (Error about not knowing how to build target
# "rR".)
#
# The recipes are defined as ".NOTPARALLEL" as a safe-guard to ensure we only
# call into the sandbox one at a time even if someone were to call this
# makefile with '-j'.
#
# ODE_REMAKE_RULE is a function called when instantiating a target
# (see _ODE_REMAKE_DEPS below) to instantiate the ODE remake receipe and
# return the __ODE_REMAKE_TARGET filename for the ODE directive.
#
__ODE_REMAKE_TARGET = .ode_built_$(subst /,_,$(firstword $(subst :, ,$(1)))__$(word 2,$(subst :, ,$(1))))
define __ODE_REMAKE_RULE
.NOTPARALLEL : $(TARGET_DIR)/$(1)$(call __ODE_REMAKE_TARGET,$(2))
$(TARGET_DIR)/$(1)$(call __ODE_REMAKE_TARGET, $(2)) : MAKEFLAGS=
$(TARGET_DIR)/$(1)$(call __ODE_REMAKE_TARGET, $(2)) : \
    $(lastword $(subst :, ,$(2)))
	@echo ODE_MK $(firstword $(subst :, ,$(2)))
	@$$(call EXECUTE_IN_SANDBOX,\
	    mkdir -p $(firstword $(subst :, ,$(2))) && \
	    cd $(firstword $(subst :, ,$(2))) && \
	    mk -O1 -j8 -a $(subst NOTARGET,,$(word 2, $(subst :, ,$(2)))),\
	    $(word 3, $(subst :, ,$(2))))
	@touch $$@
endef
ODE_REMAKE_RULE = $(eval $(call __ODE_REMAKE_RULE,,$(2)))\
		  $(call __ODE_REMAKE_TARGET,$(2))

# ------------- Global target directives ----------------------
# The INSTANTIATE_TARGET function is where all of the top-level
# directives (called directly by 'make' or 'make fsp_TARGET') are
# created.
#
# For each possible target, we need to instantiate a recipe for how
# to create target when we are only making the target and one for when
# we are building all targets (a release).  This is the _TARGET and
# _TARGET_AS_SUBDIR recipe templates.
#
# Within a template we need to determine what to build, which is
# determined by the global actions like COPY_FILES, TAR_FILES, etc.
# The variables <TARGET>_<ACTION> are determined here by filtering the
# global <ACTION> variable for matches against the <TARGET> name.
# (__SOURCE_FOR_TARGET from above is used as the filtering mechanism).
#
# Building a target is 3 simple stages:
#     1) Print a "Starting <TARGET>" message.
#     2) Build all of the target dependencies
#             (based on the <TARGET>_<ACTION> variables).
#     3) Print a "Completed <TARGET>" message.
#
# At the end we loop over all VALID_TARGETS to call INSTANTIATE_TARGET
# against them.
#
define INSTANTIATE_TARGET
$(1)_COPY_FILE += $$(foreach file, $$(COPY_FILES), \
		     $$(call __SOURCE_FOR_TARGET,$(1), \
			    $$(firstword $$(subst :, ,$$(file))), \
			    $$(lastword $$(subst :, ,$$(file))) \
			) \
		    )

$(1)_COPY_RENAME_FILE += $$(foreach file, $$(COPY_RENAME_FILES), \
				$$(call __SOURCE_FOR_TARGET,$(1), \
				    $$(firstword $$(subst :, ,$$(file))), \
				    $$(lastword $$(subst :, ,$$(file))) \
				  ) \
			   )

$(1)_LINK_FILE += $$(foreach file, $$(LINK_FILES), \
			$$(call __SOURCE_FOR_TARGET,$(1), \
			    $$(firstword $$(subst :, ,$$(file))), \
			    $$(lastword $$(subst :, ,$$(file))) \
			  ) \
		    )

$(1)_TAR_FILE += $$(foreach file, $$(TAR_FILES), \
			$$(call __SOURCE_FOR_TARGET,$(1), \
			    $$(firstword $$(subst :, ,$$(file))), \
			    $$(lastword $$(subst :, ,$$(file))) \
			  ) \
		   )

$(1)_ODE_REMAKE_DEPS += $$(foreach file, $$($(1)_ODE_REMAKES), \
				$$(call ODE_REMAKE_RULE,$(1),$$(file)))

.PHONY: $(1)_TARGET $(1)_TARGET_AS_SUBDIR
$(1)_TARGET: \
    $(1)_TARGET_ECHO_START \
    $$(addprefix $$(TARGET_DIR)/,$$(notdir $$($(1)_COPY_FILE))) \
    $$(addprefix $$(TARGET_DIR)/,$$($(1)_COPY_RENAME_FILE)) \
    $$(addprefix $$(TARGET_DIR)/,$$($(1)_LINK_FILE)) \
    $$(addprefix $$(TARGET_DIR)/,$$($(1)_TAR_FILE)) \
    $$(addprefix $$(TARGET_DIR)/,$$($(1)_ODE_REMAKE_DEPS))
	@echo TARGET $(1) complete.

$(1)_TARGET_AS_SUBDIR: \
    $(1)_TARGET_ECHO_START \
    $$(addprefix $$(TARGET_DIR)/$(1)/,$$(notdir $$($(1)_COPY_FILE))) \
    $$(addprefix $$(TARGET_DIR)/$(1)/,$$($(1)_COPY_RENAME_FILE)) \
    $$(addprefix $$(TARGET_DIR)/$(1)/,$$($(1)_LINK_FILE)) \
    $$(addprefix $$(TARGET_DIR)/$(1)/,$$($(1)_TAR_FILE))
	@echo TARGET $(1) complete.

$(1)_TARGET_ECHO_START:
	@echo TARGET $(1) start...

endef
$(foreach targ,$(VALID_TARGETS),$(eval $(call INSTANTIATE_TARGET,$(targ))))

OpenPOWER on IntegriCloud