1################################################################################
2#
3# This file contains various utility functions used by the package
4# infrastructure, or by the packages themselves.
5#
6################################################################################
7
8#
9# Manipulation of .config files based on the Kconfig
10# infrastructure. Used by the BusyBox package, the Linux kernel
11# package, and more.
12#
13
14# KCONFIG_DOT_CONFIG ([file])
15# Returns the path to the .config file that should be used, which will
16# be $(1) if provided, or the current package .config file otherwise.
17KCONFIG_DOT_CONFIG = $(strip \
18	$(if $(strip $(1)), $(1), \
19		$($(PKG)_BUILDDIR)/$($(PKG)_KCONFIG_DOTCONFIG) \
20	) \
21)
22
23# KCONFIG_MUNGE_DOT_CONFIG (option, newline [, file])
24define KCONFIG_MUNGE_DOT_CONFIG
25	$(SED) '/^\(# \)\?$(strip $(1))\>/d' $(call KCONFIG_DOT_CONFIG,$(3)) && \
26	echo '$(strip $(2))' >> $(call KCONFIG_DOT_CONFIG,$(3))
27endef
28
29# KCONFIG_ENABLE_OPT (option [, file])
30# If the option is already set to =m or =y, ignore.
31define KCONFIG_ENABLE_OPT
32	$(Q)if ! grep -q '^$(strip $(1))=[my]' $(call KCONFIG_DOT_CONFIG,$(2)); then \
33		$(call KCONFIG_MUNGE_DOT_CONFIG, $(1), $(1)=y, $(2)); \
34	fi
35endef
36# KCONFIG_SET_OPT (option, value [, file])
37KCONFIG_SET_OPT     = $(Q)$(call KCONFIG_MUNGE_DOT_CONFIG, $(1), $(1)=$(2), $(3))
38# KCONFIG_DISABLE_OPT  (option [, file])
39KCONFIG_DISABLE_OPT = $(Q)$(call KCONFIG_MUNGE_DOT_CONFIG, $(1), $(SHARP_SIGN) $(1) is not set, $(2))
40
41# Helper functions to determine the name of a package and its
42# directory from its makefile directory, using the $(MAKEFILE_LIST)
43# variable provided by make. This is used by the *-package macros to
44# automagically find where the package is located.
45pkgdir = $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST))))
46pkgname = $(lastword $(subst /, ,$(pkgdir)))
47
48# Helper to build the extension for a package archive, based on various
49# conditions.
50# $(1): upper-case package name
51pkg_source_ext = $(BR_FMT_VERSION_$($(1)_SITE_METHOD))$(BR_FMT_VERSION_$($(1)_DOWNLOAD_POST_PROCESS)).tar.gz
52
53# Define extractors for different archive suffixes
54INFLATE.bz2  = $(BZCAT)
55INFLATE.gz   = $(ZCAT)
56INFLATE.lz   = $(LZCAT)
57INFLATE.lzma = $(XZCAT)
58INFLATE.tbz  = $(BZCAT)
59INFLATE.tbz2 = $(BZCAT)
60INFLATE.tgz  = $(ZCAT)
61INFLATE.xz   = $(XZCAT)
62INFLATE.tar  = cat
63# suitable-extractor(filename): returns extractor based on suffix
64suitable-extractor = $(INFLATE$(suffix $(1)))
65
66EXTRACTOR_PKG_DEPENDENCY.lzma = $(BR2_XZCAT_HOST_DEPENDENCY)
67EXTRACTOR_PKG_DEPENDENCY.xz   = $(BR2_XZCAT_HOST_DEPENDENCY)
68EXTRACTOR_PKG_DEPENDENCY.lz   = $(BR2_LZIP_HOST_DEPENDENCY)
69
70# extractor-pkg-dependency(filename): returns a Buildroot package
71# dependency needed to extract file based on suffix
72extractor-pkg-dependency = $(EXTRACTOR_PKG_DEPENDENCY$(suffix $(1)))
73
74# extractor-system-dependency(filename): returns the name of the tool
75# needed to extract 'filename', and is meant to be used with
76# DL_TOOLS_DEPENDENCIES, in order to check that the necesary tool is
77# provided by the system Buildroot runs on.
78#
79# $(firstword) is used here because the extractor can have arguments,
80# like ZCAT="gzip -d -c", and to check for the dependency we only want
81# 'gzip'.
82extractor-system-dependency = $(if $(EXTRACTOR_PKG_DEPENDENCY$(suffix $(1))),,\
83	$(firstword $(INFLATE$(suffix $(1)))))
84
85# check-deprecated-variable -- throw an error on deprecated variables
86# example:
87#   $(eval $(call check-deprecated-variable,FOO_MAKE_OPT,FOO_MAKE_OPTS))
88define check-deprecated-variable # (deprecated var, new var)
89ifneq ($$(origin $(1)),undefined)
90$$(error Package error: use $(2) instead of $(1). Please fix your .mk file)
91endif
92endef
93
94# $(1): YES or NO
95define yesno-to-bool
96	$(subst NO,false,$(subst YES,true,$(1)))
97endef
98
99# json-info -- return package or filesystem metadata formatted as an entry
100#              of a JSON dictionnary
101# $(1): upper-case package or filesystem name
102define json-info
103	"$($(1)_NAME)": {
104		"type": $(call mk-json-str,$($(1)_TYPE)),
105		$(if $(filter rootfs,$($(1)_TYPE)), \
106			$(call _json-info-fs,$(1)), \
107			$(call _json-info-pkg,$(1)), \
108		)
109	}
110endef
111
112# _json-info-pkg, _json-info-pkg-details, _json-info-fs: private helpers
113# for json-info, above
114define _json-info-pkg
115	"name": $(call mk-json-str,$($(1)_RAWNAME)),
116	$(if $($(1)_IS_VIRTUAL), \
117		"virtual": true$(comma),
118		"virtual": false$(comma)
119		$(call _json-info-pkg-details,$(1)) \
120	)
121	"stamp_dir": $(call mk-json-str,$(patsubst $(CONFIG_DIR)/%,%,$($(1)_DIR))),
122	"source_dir": $(call mk-json-str,$(patsubst $(CONFIG_DIR)/%,%,$($(1)_DIR))),
123	"build_dir": $(call mk-json-str,$(patsubst $(CONFIG_DIR)/%,%,$($(1)_BUILDDIR))),
124	$(if $(filter target,$($(1)_TYPE)), \
125		"install_target": $(call yesno-to-bool,$($(1)_INSTALL_TARGET))$(comma) \
126		"install_staging": $(call yesno-to-bool,$($(1)_INSTALL_STAGING))$(comma) \
127		"install_images": $(call yesno-to-bool,$($(1)_INSTALL_IMAGES))$(comma) \
128	)
129	"dependencies": [
130		$(call make-comma-list, \
131			$(foreach dep,$(sort $($(1)_FINAL_ALL_DEPENDENCIES)), \
132				$(call mk-json-str,$(dep)) \
133			) \
134		)
135	],
136	"reverse_dependencies": [
137		$(call make-comma-list, \
138			$(foreach dep,$(sort $($(1)_RDEPENDENCIES)), \
139				$(call mk-json-str,$(dep)) \
140			) \
141		)
142	]
143	$(if $($(1)_CPE_ID_VALID), \
144		$(comma) "cpe-id": $(call mk-json-str,$($(1)_CPE_ID)) \
145	)
146	$(if $($(1)_IGNORE_CVES),
147		$(comma) "ignore_cves": [
148			$(call make-comma-list, \
149				$(foreach cve,$(sort $($(1)_IGNORE_CVES)), \
150					$(call mk-json-str,$(cve)) \
151				) \
152			)
153		]
154	)
155endef
156
157define _json-info-pkg-details
158	"version": $(call mk-json-str,$($(1)_DL_VERSION)),
159	"licenses": $(call mk-json-str,$($(1)_LICENSE)),
160	"license_files": [
161		$(foreach f, $($(1)_LICENSE_FILES),$(call mk-json-str,$(f))$(comma))
162	],
163	"redistributable": $(if $(filter NO,$($(1)_REDISTRIBUTE)),false,true),
164	"dl_dir": $(call mk-json-str,$($(1)_DL_SUBDIR)),
165	"downloads": [
166	$(foreach dl,$(sort $($(1)_ALL_DOWNLOADS)),
167		{
168			"source": $(call mk-json-str,$(notdir $(dl))),
169			"uris": [
170				$(call make-comma-list, \
171					$(foreach uri,$(call DOWNLOAD_URIS,$(dl),$(1)), \
172						$(call mk-json-str,$(subst \|,|,$(uri))) \
173					) \
174				)
175			]
176		},
177	)
178	],
179endef
180
181define _json-info-fs
182	"image_name": $(if $($(1)_FINAL_IMAGE_NAME), \
183				$(call mk-json-str,$($(1)_FINAL_IMAGE_NAME)), \
184				null \
185			),
186	"dependencies": [
187		$(call make-comma-list, \
188			$(foreach dep,$(sort $($(1)_DEPENDENCIES)), \
189				$(call mk-json-str,$(dep)) \
190			) \
191		)
192	]
193endef
194
195# clean-json -- cleanup pseudo-json into clean json:
196#  - remove commas before closing ] and }
197#  - minify with $(strip)
198clean-json = $(strip \
199	$(subst $(comma)},}, $(subst $(comma)$(space)},$(space)}, \
200	$(subst $(comma)],], $(subst $(comma)$(space)],$(space)], \
201		$(strip $(1)) \
202	)))) \
203)
204
205# mk-json-str -- escape and double-quote a string to make it a valid json string
206#  - escape \
207#  - escape "
208#  - escape \n
209#  - escape \t
210#  - escape ESC
211#  - escape SPACE (so that we can $(strip) a JSON blurb without squashing multiple spaces)
212# This unfortunately has to be on a single line...
213mk-json-str = "$(subst $(space),\u0020,$(subst $(escape),\u001b,$(subst $(tab),\t,$(subst $(sep),\n,$(subst ",\",$(subst \,\\,$(1)))))))"
214# )))))" # Syntax colouring
215
216ifeq ($(BR2_PER_PACKAGE_DIRECTORIES),y)
217# rsync the contents of per-package directories
218# $1: space-separated list of packages to rsync from
219# $2: 'host' or 'target'
220# $3: destination directory
221# $4: literal "copy" or "hardlink" to copy or hardlink files from src to dest
222define per-package-rsync
223	mkdir -p $(3)
224	$(foreach pkg,$(1),\
225		rsync -a \
226			--hard-links \
227			$(if $(filter hardlink,$(4)), \
228				--link-dest=$(PER_PACKAGE_DIR)/$(pkg)/$(2)/, \
229				$(if $(filter copy,$(4)), \
230					$(empty), \
231					$(error per-package-rsync can only "copy" or "hardlink", not "$(4)") \
232				) \
233			) \
234			$(PER_PACKAGE_DIR)/$(pkg)/$(2)/ \
235			$(3)$(sep))
236endef
237
238# prepares the per-package HOST_DIR and TARGET_DIR of the current
239# package, by rsync the host and target directories of the
240# dependencies of this package. The list of dependencies is passed as
241# argument, so that this function can be used to prepare with
242# different set of dependencies (download, extract, configure, etc.)
243#
244# $1: space-separated list of packages to rsync from
245define prepare-per-package-directory
246	$(call per-package-rsync,$(1),host,$(HOST_DIR),hardlink)
247	$(call per-package-rsync,$(1),target,$(TARGET_DIR),hardlink)
248endef
249
250# Ensure files like .la, .pc, .pri, .cmake, and so on, point to the
251# proper staging and host directories for the current package: find
252# all text files that contain the PPD root, and replace it with the
253# current package's PPD.
254# $1: destination root directory containing host and staging
255define ppd-fixup-paths
256	$(Q)grep --binary-files=without-match -lrZ '$(PER_PACKAGE_DIR)/[^/]\+/' $(HOST_DIR) \
257	|while read -d '' f; do \
258		file -b --mime-type "$${f}" | grep -q '^text/' || continue; \
259		printf '%s\0' "$${f}"; \
260	done \
261	|xargs -0 --no-run-if-empty \
262		$(SED) 's:$(PER_PACKAGE_DIR)/[^/]\+/:$(1)/:g'
263endef
264endif
265
266#
267# legal-info helper functions
268#
269LEGAL_INFO_SEPARATOR = "::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::"
270
271define legal-warning # text
272	echo "WARNING: $(1)" >>$(LEGAL_WARNINGS)
273endef
274
275define legal-warning-pkg # pkg, text
276	echo "WARNING: $(1): $(2)" >>$(LEGAL_WARNINGS)
277endef
278
279define legal-warning-nosource # pkg, {local|override}
280	$(call legal-warning-pkg,$(1),sources not saved ($(2) packages not handled))
281endef
282
283define legal-manifest # {HOST|TARGET}, pkg, version, license, license-files, source, url, dependencies
284	echo '"$(2)","$(3)","$(4)","$(5)","$(6)","$(7)","$(8)"' >>$(LEGAL_MANIFEST_CSV_$(1))
285endef
286
287define legal-license-file # {HOST|TARGET}, pkgname, pkgname-pkgver, filename, file-fullpath, pkg-hashfiles
288	mkdir -p $(LICENSE_FILES_DIR_$(1))/$(3)/$(dir $(4)) && \
289	{ \
290		support/download/check-hash $(5) $(4) $(6); \
291		case $${?} in (0|3) ;; (*) exit 1;; esac; \
292	} && \
293	cp $(5) $(LICENSE_FILES_DIR_$(1))/$(3)/$(4)
294endef
295
296non-virtual-deps = $(foreach p,$(1),$(if $($(call UPPERCASE,$(p))_IS_VIRTUAL),,$(p)))
297
298# Returns the list of recursive dependencies and their licensing terms
299# for the package specified in parameter (in lowercase). If that
300# package is a target package, remove host packages from the list.
301legal-deps = \
302    $(foreach p,\
303        $(filter-out $(if $(1:host-%=),host-%),\
304            $(call non-virtual-deps,\
305                $($(call UPPERCASE,$(1))_FINAL_RECURSIVE_DEPENDENCIES))),$(p) [$($(call UPPERCASE,$(p))_LICENSE)])
306
307# Helper for self-extracting binaries distributed by NXP, and
308# formerlly Freescale.
309#
310# The --force option makes sure it doesn't fail if the source
311# directory already exists. The --auto-accept skips the license check,
312# as it is not needed in Buildroot because we have legal-info. Since
313# there's a EULA in the binary file, we extract it in this macro, and
314# it should therefore be added to the LICENSE_FILES variable of
315# packages using this macro. Also, remember to set REDISTRIBUTE to
316# "NO". Indeed, this is a legal minefield: the EULA specifies that the
317# Board Support Package includes software and hardware (sic!) for
318# which a separate license is needed...
319#
320# $(1): full path to the archive file
321#
322define NXP_EXTRACT_HELPER
323	awk 'BEGIN      { start = 0; } \
324	     /^EOEULA/  { start = 0; } \
325	                { if (start) print; } \
326	     /<<EOEULA/ { start = 1; }' \
327	    $(1) > $(@D)/EULA
328	cd $(@D) && sh $(1) --force --auto-accept
329	find $(@D)/$(basename $(notdir $(1))) -mindepth 1 -maxdepth 1 -exec mv {} $(@D) \;
330	rmdir $(@D)/$(basename $(notdir $(1)))
331endef
332