blob: 0a3b528ddb4fbe26a30060b66d26cfa032f26584 [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001# BB Class inspired by ebuild.sh
2#
3# This class will test files after installation for certain
4# security issues and other kind of issues.
5#
6# Checks we do:
7# -Check the ownership and permissions
8# -Check the RUNTIME path for the $TMPDIR
9# -Check if .la files wrongly point to workdir
10# -Check if .pc files wrongly point to workdir
11# -Check if packages contains .debug directories or .so files
12# where they should be in -dev or -dbg
13# -Check if config.log contains traces to broken autoconf tests
14# -Check invalid characters (non-utf8) on some package metadata
15# -Ensure that binaries in base_[bindir|sbindir|libdir] do not link
16# into exec_prefix
17# -Check that scripts in base_[bindir|sbindir|libdir] do not reference
18# files under exec_prefix
Brad Bishopd7bf8c12018-02-25 22:55:05 -050019# -Check if the package name is upper case
Patrick Williamsc124f4f2015-09-15 14:41:29 -050020
Patrick Williamsc124f4f2015-09-15 14:41:29 -050021QA_SANE = "True"
22
23# Elect whether a given type of error is a warning or error, they may
24# have been set by other files.
25WARN_QA ?= "ldflags useless-rpaths rpaths staticdev libdir xorg-driver-abi \
26 textrel already-stripped incompatible-license files-invalid \
27 installed-vs-shipped compile-host-path install-host-path \
Brad Bishop6e60e8b2018-02-01 10:27:11 -050028 pn-overrides infodir build-deps \
Patrick Williamsc124f4f2015-09-15 14:41:29 -050029 unknown-configure-option symlink-to-sysroot multilib \
Brad Bishopd7bf8c12018-02-25 22:55:05 -050030 invalid-packageconfig host-user-contaminated uppercase-pn \
Patrick Williamsc124f4f2015-09-15 14:41:29 -050031 "
32ERROR_QA ?= "dev-so debug-deps dev-deps debug-files arch pkgconfig la \
33 perms dep-cmp pkgvarcheck perm-config perm-line perm-link \
34 split-strip packages-list pkgv-undefined var-undefined \
35 version-going-backwards expanded-d invalid-chars \
Brad Bishop6e60e8b2018-02-01 10:27:11 -050036 license-checksum dev-elf file-rdeps \
Patrick Williamsc124f4f2015-09-15 14:41:29 -050037 "
Brad Bishopd7bf8c12018-02-25 22:55:05 -050038# Add usrmerge QA check based on distro feature
39ERROR_QA_append = "${@bb.utils.contains('DISTRO_FEATURES', 'usrmerge', ' usrmerge', '', d)}"
40
Patrick Williamsc124f4f2015-09-15 14:41:29 -050041FAKEROOT_QA = "host-user-contaminated"
42FAKEROOT_QA[doc] = "QA tests which need to run under fakeroot. If any \
43enabled tests are listed here, the do_package_qa task will run under fakeroot."
44
45ALL_QA = "${WARN_QA} ${ERROR_QA}"
46
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050047UNKNOWN_CONFIGURE_WHITELIST ?= "--enable-nls --disable-nls --disable-silent-rules --disable-dependency-tracking --with-libtool-sysroot --disable-static"
Patrick Williamsc124f4f2015-09-15 14:41:29 -050048
49#
50# dictionary for elf headers
51#
52# feel free to add and correct.
53#
54# TARGET_OS TARGET_ARCH MACHINE, OSABI, ABIVERSION, Little Endian, 32bit?
Patrick Williamsc0f7c042017-02-23 20:41:17 -060055def package_qa_get_machine_dict(d):
56 machdata = {
Patrick Williamsc124f4f2015-09-15 14:41:29 -050057 "darwin9" : {
58 "arm" : (40, 0, 0, True, 32),
59 },
60 "eabi" : {
61 "arm" : (40, 0, 0, True, 32),
62 },
63 "elf" : {
Brad Bishop37a0e4d2017-12-04 01:01:44 -050064 "aarch64" : (183, 0, 0, True, 64),
65 "aarch64_be" :(183, 0, 0, False, 64),
Patrick Williamsc124f4f2015-09-15 14:41:29 -050066 "i586" : (3, 0, 0, True, 32),
67 "x86_64": (62, 0, 0, True, 64),
68 "epiphany": (4643, 0, 0, True, 32),
Patrick Williamsc0f7c042017-02-23 20:41:17 -060069 "mips": ( 8, 0, 0, False, 32),
70 "mipsel": ( 8, 0, 0, True, 32),
Patrick Williamsc124f4f2015-09-15 14:41:29 -050071 },
72 "linux" : {
73 "aarch64" : (183, 0, 0, True, 64),
74 "aarch64_be" :(183, 0, 0, False, 64),
75 "arm" : (40, 97, 0, True, 32),
76 "armeb": (40, 97, 0, False, 32),
77 "powerpc": (20, 0, 0, False, 32),
78 "powerpc64": (21, 0, 0, False, 64),
79 "i386": ( 3, 0, 0, True, 32),
80 "i486": ( 3, 0, 0, True, 32),
81 "i586": ( 3, 0, 0, True, 32),
82 "i686": ( 3, 0, 0, True, 32),
83 "x86_64": (62, 0, 0, True, 64),
84 "ia64": (50, 0, 0, True, 64),
85 "alpha": (36902, 0, 0, True, 64),
86 "hppa": (15, 3, 0, False, 32),
87 "m68k": ( 4, 0, 0, False, 32),
88 "mips": ( 8, 0, 0, False, 32),
89 "mipsel": ( 8, 0, 0, True, 32),
90 "mips64": ( 8, 0, 0, False, 64),
91 "mips64el": ( 8, 0, 0, True, 64),
Patrick Williamsc0f7c042017-02-23 20:41:17 -060092 "mipsisa32r6": ( 8, 0, 0, False, 32),
93 "mipsisa32r6el": ( 8, 0, 0, True, 32),
94 "mipsisa64r6": ( 8, 0, 0, False, 64),
95 "mipsisa64r6el": ( 8, 0, 0, True, 64),
Patrick Williamsf1e5d692016-03-30 15:21:19 -050096 "nios2": (113, 0, 0, True, 32),
Patrick Williamsc124f4f2015-09-15 14:41:29 -050097 "s390": (22, 0, 0, False, 32),
98 "sh4": (42, 0, 0, True, 32),
99 "sparc": ( 2, 0, 0, False, 32),
100 "microblaze": (189, 0, 0, False, 32),
101 "microblazeeb":(189, 0, 0, False, 32),
102 "microblazeel":(189, 0, 0, True, 32),
103 },
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500104 "linux-musl" : {
105 "aarch64" : (183, 0, 0, True, 64),
106 "aarch64_be" :(183, 0, 0, False, 64),
107 "arm" : ( 40, 97, 0, True, 32),
108 "armeb": ( 40, 97, 0, False, 32),
109 "powerpc": ( 20, 0, 0, False, 32),
110 "i386": ( 3, 0, 0, True, 32),
111 "i486": ( 3, 0, 0, True, 32),
112 "i586": ( 3, 0, 0, True, 32),
113 "i686": ( 3, 0, 0, True, 32),
114 "x86_64": ( 62, 0, 0, True, 64),
115 "mips": ( 8, 0, 0, False, 32),
116 "mipsel": ( 8, 0, 0, True, 32),
117 "mips64": ( 8, 0, 0, False, 64),
118 "mips64el": ( 8, 0, 0, True, 64),
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500119 "microblaze": (189, 0, 0, False, 32),
120 "microblazeeb":(189, 0, 0, False, 32),
121 "microblazeel":(189, 0, 0, True, 32),
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500122 "sh4": ( 42, 0, 0, True, 32),
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500123 },
124 "uclinux-uclibc" : {
125 "bfin": ( 106, 0, 0, True, 32),
126 },
127 "linux-gnueabi" : {
128 "arm" : (40, 0, 0, True, 32),
129 "armeb" : (40, 0, 0, False, 32),
130 },
131 "linux-musleabi" : {
132 "arm" : (40, 0, 0, True, 32),
133 "armeb" : (40, 0, 0, False, 32),
134 },
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500135 "linux-gnuspe" : {
136 "powerpc": (20, 0, 0, False, 32),
137 },
138 "linux-muslspe" : {
139 "powerpc": (20, 0, 0, False, 32),
140 },
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500141 "linux-gnu" : {
142 "powerpc": (20, 0, 0, False, 32),
143 "sh4": (42, 0, 0, True, 32),
144 },
145 "linux-gnux32" : {
146 "x86_64": (62, 0, 0, True, 32),
147 },
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500148 "linux-muslx32" : {
149 "x86_64": (62, 0, 0, True, 32),
150 },
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500151 "linux-gnun32" : {
152 "mips64": ( 8, 0, 0, False, 32),
153 "mips64el": ( 8, 0, 0, True, 32),
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500154 "mipsisa64r6": ( 8, 0, 0, False, 32),
155 "mipsisa64r6el":( 8, 0, 0, True, 32),
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500156 },
157 }
158
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600159 # Add in any extra user supplied data which may come from a BSP layer, removing the
160 # need to always change this class directly
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500161 extra_machdata = (d.getVar("PACKAGEQA_EXTRA_MACHDEFFUNCS") or "").split()
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600162 for m in extra_machdata:
163 call = m + "(machdata, d)"
164 locs = { "machdata" : machdata, "d" : d}
165 machdata = bb.utils.better_eval(call, locs)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500166
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600167 return machdata
168
169
170def package_qa_clean_path(path, d, pkg=None):
171 """
172 Remove redundant paths from the path for display. If pkg isn't set then
173 TMPDIR is stripped, otherwise PKGDEST/pkg is stripped.
174 """
175 if pkg:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500176 path = path.replace(os.path.join(d.getVar("PKGDEST"), pkg), "/")
177 return path.replace(d.getVar("TMPDIR"), "/").replace("//", "/")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500178
179def package_qa_write_error(type, error, d):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500180 logfile = d.getVar('QA_LOGFILE')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500181 if logfile:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500182 p = d.getVar('P')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600183 with open(logfile, "a+") as f:
184 f.write("%s: %s [%s]\n" % (p, error, type))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500185
186def package_qa_handle_error(error_class, error_msg, d):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500187 if error_class in (d.getVar("ERROR_QA") or "").split():
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500188 package_qa_write_error(error_class, error_msg, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500189 bb.error("QA Issue: %s [%s]" % (error_msg, error_class))
190 d.setVar("QA_SANE", False)
191 return False
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500192 elif error_class in (d.getVar("WARN_QA") or "").split():
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500193 package_qa_write_error(error_class, error_msg, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500194 bb.warn("QA Issue: %s [%s]" % (error_msg, error_class))
195 else:
196 bb.note("QA Issue: %s [%s]" % (error_msg, error_class))
197 return True
198
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500199def package_qa_add_message(messages, section, new_msg):
200 if section not in messages:
201 messages[section] = new_msg
202 else:
203 messages[section] = messages[section] + "\n" + new_msg
204
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500205QAPATHTEST[libexec] = "package_qa_check_libexec"
206def package_qa_check_libexec(path,name, d, elf, messages):
207
208 # Skip the case where the default is explicitly /usr/libexec
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500209 libexec = d.getVar('libexecdir')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500210 if libexec == "/usr/libexec":
211 return True
212
213 if 'libexec' in path.split(os.path.sep):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500214 package_qa_add_message(messages, "libexec", "%s: %s is using libexec please relocate to %s" % (name, package_qa_clean_path(path, d), libexec))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500215 return False
216
217 return True
218
219QAPATHTEST[rpaths] = "package_qa_check_rpath"
220def package_qa_check_rpath(file,name, d, elf, messages):
221 """
222 Check for dangerous RPATHs
223 """
224 if not elf:
225 return
226
227 if os.path.islink(file):
228 return
229
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500230 bad_dirs = [d.getVar('BASE_WORKDIR'), d.getVar('STAGING_DIR_TARGET')]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500231
232 phdrs = elf.run_objdump("-p", d)
233
234 import re
235 rpath_re = re.compile("\s+RPATH\s+(.*)")
236 for line in phdrs.split("\n"):
237 m = rpath_re.match(line)
238 if m:
239 rpath = m.group(1)
240 for dir in bad_dirs:
241 if dir in rpath:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500242 package_qa_add_message(messages, "rpaths", "package %s contains bad RPATH %s in file %s" % (name, rpath, file))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500243
244QAPATHTEST[useless-rpaths] = "package_qa_check_useless_rpaths"
245def package_qa_check_useless_rpaths(file, name, d, elf, messages):
246 """
247 Check for RPATHs that are useless but not dangerous
248 """
249 def rpath_eq(a, b):
250 return os.path.normpath(a) == os.path.normpath(b)
251
252 if not elf:
253 return
254
255 if os.path.islink(file):
256 return
257
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500258 libdir = d.getVar("libdir")
259 base_libdir = d.getVar("base_libdir")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500260
261 phdrs = elf.run_objdump("-p", d)
262
263 import re
264 rpath_re = re.compile("\s+RPATH\s+(.*)")
265 for line in phdrs.split("\n"):
266 m = rpath_re.match(line)
267 if m:
268 rpath = m.group(1)
269 if rpath_eq(rpath, libdir) or rpath_eq(rpath, base_libdir):
270 # The dynamic linker searches both these places anyway. There is no point in
271 # looking there again.
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500272 package_qa_add_message(messages, "useless-rpaths", "%s: %s contains probably-redundant RPATH %s" % (name, package_qa_clean_path(file, d), rpath))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500273
274QAPATHTEST[dev-so] = "package_qa_check_dev"
275def package_qa_check_dev(path, name, d, elf, messages):
276 """
277 Check for ".so" library symlinks in non-dev packages
278 """
279
280 if not name.endswith("-dev") and not name.endswith("-dbg") and not name.endswith("-ptest") and not name.startswith("nativesdk-") and path.endswith(".so") and os.path.islink(path):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500281 package_qa_add_message(messages, "dev-so", "non -dev/-dbg/nativesdk- package contains symlink .so: %s path '%s'" % \
282 (name, package_qa_clean_path(path,d)))
283
284QAPATHTEST[dev-elf] = "package_qa_check_dev_elf"
285def package_qa_check_dev_elf(path, name, d, elf, messages):
286 """
287 Check that -dev doesn't contain real shared libraries. The test has to
288 check that the file is not a link and is an ELF object as some recipes
289 install link-time .so files that are linker scripts.
290 """
291 if name.endswith("-dev") and path.endswith(".so") and not os.path.islink(path) and elf:
292 package_qa_add_message(messages, "dev-elf", "-dev package contains non-symlink .so: %s path '%s'" % \
293 (name, package_qa_clean_path(path,d)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500294
295QAPATHTEST[staticdev] = "package_qa_check_staticdev"
296def package_qa_check_staticdev(path, name, d, elf, messages):
297 """
298 Check for ".a" library in non-staticdev packages
299 There are a number of exceptions to this rule, -pic packages can contain
300 static libraries, the _nonshared.a belong with their -dev packages and
301 libgcc.a, libgcov.a will be skipped in their packages
302 """
303
304 if not name.endswith("-pic") and not name.endswith("-staticdev") and not name.endswith("-ptest") and path.endswith(".a") and not path.endswith("_nonshared.a"):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500305 package_qa_add_message(messages, "staticdev", "non -staticdev package contains static .a library: %s path '%s'" % \
306 (name, package_qa_clean_path(path,d)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500307
308def package_qa_check_libdir(d):
309 """
310 Check for wrong library installation paths. For instance, catch
311 recipes installing /lib/bar.so when ${base_libdir}="lib32" or
312 installing in /usr/lib64 when ${libdir}="/usr/lib"
313 """
314 import re
315
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500316 pkgdest = d.getVar('PKGDEST')
317 base_libdir = d.getVar("base_libdir") + os.sep
318 libdir = d.getVar("libdir") + os.sep
319 libexecdir = d.getVar("libexecdir") + os.sep
320 exec_prefix = d.getVar("exec_prefix") + os.sep
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500321
322 messages = []
323
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500324 # The re's are purposely fuzzy, as some there are some .so.x.y.z files
325 # that don't follow the standard naming convention. It checks later
326 # that they are actual ELF files
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500327 lib_re = re.compile("^/lib.+\.so(\..+)?$")
328 exec_re = re.compile("^%s.*/lib.+\.so(\..+)?$" % exec_prefix)
329
330 for root, dirs, files in os.walk(pkgdest):
331 if root == pkgdest:
332 # Skip subdirectories for any packages with libdir in INSANE_SKIP
333 skippackages = []
334 for package in dirs:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500335 if 'libdir' in (d.getVar('INSANE_SKIP_' + package) or "").split():
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500336 bb.note("Package %s skipping libdir QA test" % (package))
337 skippackages.append(package)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500338 elif d.getVar('PACKAGE_DEBUG_SPLIT_STYLE') == 'debug-file-directory' and package.endswith("-dbg"):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500339 bb.note("Package %s skipping libdir QA test for PACKAGE_DEBUG_SPLIT_STYLE equals debug-file-directory" % (package))
340 skippackages.append(package)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500341 for package in skippackages:
342 dirs.remove(package)
343 for file in files:
344 full_path = os.path.join(root, file)
345 rel_path = os.path.relpath(full_path, pkgdest)
346 if os.sep in rel_path:
347 package, rel_path = rel_path.split(os.sep, 1)
348 rel_path = os.sep + rel_path
349 if lib_re.match(rel_path):
350 if base_libdir not in rel_path:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500351 # make sure it's an actual ELF file
352 elf = oe.qa.ELFFile(full_path)
353 try:
354 elf.open()
355 messages.append("%s: found library in wrong location: %s" % (package, rel_path))
356 except (oe.qa.NotELFFileError):
357 pass
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500358 if exec_re.match(rel_path):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500359 if libdir not in rel_path and libexecdir not in rel_path:
360 # make sure it's an actual ELF file
361 elf = oe.qa.ELFFile(full_path)
362 try:
363 elf.open()
364 messages.append("%s: found library in wrong location: %s" % (package, rel_path))
365 except (oe.qa.NotELFFileError):
366 pass
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500367
368 if messages:
369 package_qa_handle_error("libdir", "\n".join(messages), d)
370
371QAPATHTEST[debug-files] = "package_qa_check_dbg"
372def package_qa_check_dbg(path, name, d, elf, messages):
373 """
374 Check for ".debug" files or directories outside of the dbg package
375 """
376
377 if not "-dbg" in name and not "-ptest" in name:
378 if '.debug' in path.split(os.path.sep):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500379 package_qa_add_message(messages, "debug-files", "non debug package contains .debug directory: %s path %s" % \
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500380 (name, package_qa_clean_path(path,d)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500381
382QAPATHTEST[perms] = "package_qa_check_perm"
383def package_qa_check_perm(path,name,d, elf, messages):
384 """
385 Check the permission of files
386 """
387 return
388
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500389QAPATHTEST[arch] = "package_qa_check_arch"
390def package_qa_check_arch(path,name,d, elf, messages):
391 """
392 Check if archs are compatible
393 """
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600394 import re
395
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500396 if not elf:
397 return
398
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500399 target_os = d.getVar('TARGET_OS')
400 target_arch = d.getVar('TARGET_ARCH')
401 provides = d.getVar('PROVIDES')
402 bpn = d.getVar('BPN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500403
404 if target_arch == "allarch":
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500405 pn = d.getVar('PN')
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500406 package_qa_add_message(messages, "arch", pn + ": Recipe inherits the allarch class, but has packaged architecture-specific binaries")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500407 return
408
409 # FIXME: Cross package confuse this check, so just skip them
410 for s in ['cross', 'nativesdk', 'cross-canadian']:
411 if bb.data.inherits_class(s, d):
412 return
413
414 # avoid following links to /usr/bin (e.g. on udev builds)
415 # we will check the files pointed to anyway...
416 if os.path.islink(path):
417 return
418
419 #if this will throw an exception, then fix the dict above
420 (machine, osabi, abiversion, littleendian, bits) \
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600421 = package_qa_get_machine_dict(d)[target_os][target_arch]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500422
423 # Check the architecture and endiannes of the binary
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600424 is_32 = (("virtual/kernel" in provides) or bb.data.inherits_class("module", d)) and \
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500425 (target_os == "linux-gnux32" or target_os == "linux-muslx32" or re.match('mips64.*32', d.getVar('DEFAULTTUNE')))
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600426 if not ((machine == elf.machine()) or is_32):
427 package_qa_add_message(messages, "arch", "Architecture did not match (%s, expected %s) on %s" % \
428 (oe.qa.elf_machine_to_string(elf.machine()), oe.qa.elf_machine_to_string(machine), package_qa_clean_path(path,d)))
429 elif not ((bits == elf.abiSize()) or is_32):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500430 package_qa_add_message(messages, "arch", "Bit size did not match (%d to %d) %s on %s" % \
431 (bits, elf.abiSize(), bpn, package_qa_clean_path(path,d)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500432 elif not littleendian == elf.isLittleEndian():
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500433 package_qa_add_message(messages, "arch", "Endiannes did not match (%d to %d) on %s" % \
434 (littleendian, elf.isLittleEndian(), package_qa_clean_path(path,d)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500435
436QAPATHTEST[desktop] = "package_qa_check_desktop"
437def package_qa_check_desktop(path, name, d, elf, messages):
438 """
439 Run all desktop files through desktop-file-validate.
440 """
441 if path.endswith(".desktop"):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500442 desktop_file_validate = os.path.join(d.getVar('STAGING_BINDIR_NATIVE'),'desktop-file-validate')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500443 output = os.popen("%s %s" % (desktop_file_validate, path))
444 # This only produces output on errors
445 for l in output:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500446 package_qa_add_message(messages, "desktop", "Desktop file issue: " + l.strip())
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500447
448QAPATHTEST[textrel] = "package_qa_textrel"
449def package_qa_textrel(path, name, d, elf, messages):
450 """
451 Check if the binary contains relocations in .text
452 """
453
454 if not elf:
455 return
456
457 if os.path.islink(path):
458 return
459
460 phdrs = elf.run_objdump("-p", d)
461 sane = True
462
463 import re
464 textrel_re = re.compile("\s+TEXTREL\s+")
465 for line in phdrs.split("\n"):
466 if textrel_re.match(line):
467 sane = False
468
469 if not sane:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500470 package_qa_add_message(messages, "textrel", "ELF binary '%s' has relocations in .text" % path)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500471
472QAPATHTEST[ldflags] = "package_qa_hash_style"
473def package_qa_hash_style(path, name, d, elf, messages):
474 """
475 Check if the binary has the right hash style...
476 """
477
478 if not elf:
479 return
480
481 if os.path.islink(path):
482 return
483
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500484 gnu_hash = "--hash-style=gnu" in d.getVar('LDFLAGS')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500485 if not gnu_hash:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500486 gnu_hash = "--hash-style=both" in d.getVar('LDFLAGS')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500487 if not gnu_hash:
488 return
489
490 sane = False
491 has_syms = False
492
493 phdrs = elf.run_objdump("-p", d)
494
495 # If this binary has symbols, we expect it to have GNU_HASH too.
496 for line in phdrs.split("\n"):
497 if "SYMTAB" in line:
498 has_syms = True
499 if "GNU_HASH" in line:
500 sane = True
501 if "[mips32]" in line or "[mips64]" in line:
502 sane = True
503
504 if has_syms and not sane:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500505 package_qa_add_message(messages, "ldflags", "No GNU_HASH in the elf binary: '%s'" % path)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500506
507
508QAPATHTEST[buildpaths] = "package_qa_check_buildpaths"
509def package_qa_check_buildpaths(path, name, d, elf, messages):
510 """
511 Check for build paths inside target files and error if not found in the whitelist
512 """
513 # Ignore .debug files, not interesting
514 if path.find(".debug") != -1:
515 return
516
517 # Ignore symlinks
518 if os.path.islink(path):
519 return
520
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500521 # Ignore ipk and deb's CONTROL dir
522 if path.find(name + "/CONTROL/") != -1 or path.find(name + "/DEBIAN/") != -1:
523 return
524
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500525 tmpdir = d.getVar('TMPDIR')
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500526 with open(path, 'rb') as f:
527 file_content = f.read().decode('utf-8', errors='ignore')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500528 if tmpdir in file_content:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500529 package_qa_add_message(messages, "buildpaths", "File %s in package contained reference to tmpdir" % package_qa_clean_path(path,d))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500530
531
532QAPATHTEST[xorg-driver-abi] = "package_qa_check_xorg_driver_abi"
533def package_qa_check_xorg_driver_abi(path, name, d, elf, messages):
534 """
535 Check that all packages containing Xorg drivers have ABI dependencies
536 """
537
538 # Skip dev, dbg or nativesdk packages
539 if name.endswith("-dev") or name.endswith("-dbg") or name.startswith("nativesdk-"):
540 return
541
542 driverdir = d.expand("${libdir}/xorg/modules/drivers/")
543 if driverdir in path and path.endswith(".so"):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500544 mlprefix = d.getVar('MLPREFIX') or ''
545 for rdep in bb.utils.explode_deps(d.getVar('RDEPENDS_' + name) or ""):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500546 if rdep.startswith("%sxorg-abi-" % mlprefix):
547 return
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500548 package_qa_add_message(messages, "xorg-driver-abi", "Package %s contains Xorg driver (%s) but no xorg-abi- dependencies" % (name, os.path.basename(path)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500549
550QAPATHTEST[infodir] = "package_qa_check_infodir"
551def package_qa_check_infodir(path, name, d, elf, messages):
552 """
553 Check that /usr/share/info/dir isn't shipped in a particular package
554 """
555 infodir = d.expand("${infodir}/dir")
556
557 if infodir in path:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500558 package_qa_add_message(messages, "infodir", "The /usr/share/info/dir file is not meant to be shipped in a particular package.")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500559
560QAPATHTEST[symlink-to-sysroot] = "package_qa_check_symlink_to_sysroot"
561def package_qa_check_symlink_to_sysroot(path, name, d, elf, messages):
562 """
563 Check that the package doesn't contain any absolute symlinks to the sysroot.
564 """
565 if os.path.islink(path):
566 target = os.readlink(path)
567 if os.path.isabs(target):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500568 tmpdir = d.getVar('TMPDIR')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500569 if target.startswith(tmpdir):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500570 trimmed = path.replace(os.path.join (d.getVar("PKGDEST"), name), "")
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500571 package_qa_add_message(messages, "symlink-to-sysroot", "Symlink %s in %s points to TMPDIR" % (trimmed, name))
572
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600573# Check license variables
574do_populate_lic[postfuncs] += "populate_lic_qa_checksum"
575python populate_lic_qa_checksum() {
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500576 """
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600577 Check for changes in the license files.
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500578 """
579 import tempfile
580 sane = True
581
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500582 lic_files = d.getVar('LIC_FILES_CHKSUM') or ''
583 lic = d.getVar('LICENSE')
584 pn = d.getVar('PN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500585
586 if lic == "CLOSED":
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500587 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500588
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500589 if not lic_files and d.getVar('SRC_URI'):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600590 sane = package_qa_handle_error("license-checksum", pn + ": Recipe file fetches files and does not have license file information (LIC_FILES_CHKSUM)", d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500591
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500592 srcdir = d.getVar('S')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500593 corebase_licensefile = d.getVar('COREBASE') + "/LICENSE"
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500594 for url in lic_files.split():
595 try:
596 (type, host, path, user, pswd, parm) = bb.fetch.decodeurl(url)
597 except bb.fetch.MalformedUrl:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600598 sane = package_qa_handle_error("license-checksum", pn + ": LIC_FILES_CHKSUM contains an invalid URL: " + url, d)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500599 continue
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500600 srclicfile = os.path.join(srcdir, path)
601 if not os.path.isfile(srclicfile):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500602 package_qa_handle_error("license-checksum", pn + ": LIC_FILES_CHKSUM points to an invalid file: " + srclicfile, d)
603 continue
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500604
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500605 if (srclicfile == corebase_licensefile):
606 bb.warn("${COREBASE}/LICENSE is not a valid license file, please use '${COMMON_LICENSE_DIR}/MIT' for a MIT License file in LIC_FILES_CHKSUM. This will become an error in the future")
607
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500608 recipemd5 = parm.get('md5', '')
609 beginline, endline = 0, 0
610 if 'beginline' in parm:
611 beginline = int(parm['beginline'])
612 if 'endline' in parm:
613 endline = int(parm['endline'])
614
615 if (not beginline) and (not endline):
616 md5chksum = bb.utils.md5_file(srclicfile)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500617 with open(srclicfile, 'rb') as f:
618 license = f.read()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500619 else:
620 fi = open(srclicfile, 'rb')
621 fo = tempfile.NamedTemporaryFile(mode='wb', prefix='poky.', suffix='.tmp', delete=False)
622 tmplicfile = fo.name;
623 lineno = 0
624 linesout = 0
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500625 license = []
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500626 for line in fi:
627 lineno += 1
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600628 if (lineno >= beginline):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500629 if ((lineno <= endline) or not endline):
630 fo.write(line)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500631 license.append(line)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500632 linesout += 1
633 else:
634 break
635 fo.flush()
636 fo.close()
637 fi.close()
638 md5chksum = bb.utils.md5_file(tmplicfile)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500639 license = b''.join(license)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500640 os.unlink(tmplicfile)
641
642 if recipemd5 == md5chksum:
643 bb.note (pn + ": md5 checksum matched for ", url)
644 else:
645 if recipemd5:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500646 msg = pn + ": The LIC_FILES_CHKSUM does not match for " + url
647 msg = msg + "\n" + pn + ": The new md5 checksum is " + md5chksum
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500648 try:
649 license_lines = license.decode('utf-8').split('\n')
650 except:
651 # License text might not be valid UTF-8, in which
652 # case we don't know how to include it in our output
653 # and have to skip it.
654 pass
655 else:
656 max_lines = int(d.getVar('QA_MAX_LICENSE_LINES') or 20)
657 if not license_lines or license_lines[-1] != '':
658 # Ensure that our license text ends with a line break
659 # (will be added with join() below).
660 license_lines.append('')
661 remove = len(license_lines) - max_lines
662 if remove > 0:
663 start = max_lines // 2
664 end = start + remove - 1
665 del license_lines[start:end]
666 license_lines.insert(start, '...')
667 msg = msg + "\n" + pn + ": Here is the selected license text:" + \
668 "\n" + \
669 "{:v^70}".format(" beginline=%d " % beginline if beginline else "") + \
670 "\n" + "\n".join(license_lines) + \
671 "{:^^70}".format(" endline=%d " % endline if endline else "")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500672 if beginline:
673 if endline:
674 srcfiledesc = "%s (lines %d through to %d)" % (srclicfile, beginline, endline)
675 else:
676 srcfiledesc = "%s (beginning on line %d)" % (srclicfile, beginline)
677 elif endline:
678 srcfiledesc = "%s (ending on line %d)" % (srclicfile, endline)
679 else:
680 srcfiledesc = srclicfile
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500681 msg = msg + "\n" + pn + ": Check if the license information has changed in %s to verify that the LICENSE value \"%s\" remains valid" % (srcfiledesc, lic)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500682
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500683 else:
684 msg = pn + ": LIC_FILES_CHKSUM is not specified for " + url
685 msg = msg + "\n" + pn + ": The md5 checksum is " + md5chksum
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600686 sane = package_qa_handle_error("license-checksum", msg, d)
687
688 if not sane:
689 bb.fatal("Fatal QA errors found, failing task.")
690}
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500691
692def package_qa_check_staged(path,d):
693 """
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500694 Check staged la and pc files for common problems like references to the work
695 directory.
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500696
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500697 As this is run after every stage we should be able to find the one
698 responsible for the errors easily even if we look at every .pc and .la file.
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500699 """
700
701 sane = True
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500702 tmpdir = d.getVar('TMPDIR')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500703 workdir = os.path.join(tmpdir, "work")
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500704 recipesysroot = d.getVar("RECIPE_SYSROOT")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500705
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500706 if bb.data.inherits_class("native", d) or bb.data.inherits_class("cross", d):
707 pkgconfigcheck = workdir
708 else:
709 pkgconfigcheck = tmpdir
710
711 # find all .la and .pc files
712 # read the content
713 # and check for stuff that looks wrong
714 for root, dirs, files in os.walk(path):
715 for file in files:
716 path = os.path.join(root,file)
717 if file.endswith(".la"):
718 with open(path) as f:
719 file_content = f.read()
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500720 file_content = file_content.replace(recipesysroot, "")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500721 if workdir in file_content:
722 error_msg = "%s failed sanity test (workdir) in path %s" % (file,root)
723 sane = package_qa_handle_error("la", error_msg, d)
724 elif file.endswith(".pc"):
725 with open(path) as f:
726 file_content = f.read()
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500727 file_content = file_content.replace(recipesysroot, "")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500728 if pkgconfigcheck in file_content:
729 error_msg = "%s failed sanity test (tmpdir) in path %s" % (file,root)
730 sane = package_qa_handle_error("pkgconfig", error_msg, d)
731
732 return sane
733
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500734# Run all package-wide warnfuncs and errorfuncs
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500735def package_qa_package(warnfuncs, errorfuncs, package, d):
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500736 warnings = {}
737 errors = {}
738
739 for func in warnfuncs:
740 func(package, d, warnings)
741 for func in errorfuncs:
742 func(package, d, errors)
743
744 for w in warnings:
745 package_qa_handle_error(w, warnings[w], d)
746 for e in errors:
747 package_qa_handle_error(e, errors[e], d)
748
749 return len(errors) == 0
750
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500751# Run all recipe-wide warnfuncs and errorfuncs
752def package_qa_recipe(warnfuncs, errorfuncs, pn, d):
753 warnings = {}
754 errors = {}
755
756 for func in warnfuncs:
757 func(pn, d, warnings)
758 for func in errorfuncs:
759 func(pn, d, errors)
760
761 for w in warnings:
762 package_qa_handle_error(w, warnings[w], d)
763 for e in errors:
764 package_qa_handle_error(e, errors[e], d)
765
766 return len(errors) == 0
767
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500768# Walk over all files in a directory and call func
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500769def package_qa_walk(warnfuncs, errorfuncs, package, d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500770 import oe.qa
771
772 #if this will throw an exception, then fix the dict above
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500773 target_os = d.getVar('TARGET_OS')
774 target_arch = d.getVar('TARGET_ARCH')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500775
776 warnings = {}
777 errors = {}
778 for path in pkgfiles[package]:
779 elf = oe.qa.ELFFile(path)
780 try:
781 elf.open()
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500782 except (IOError, oe.qa.NotELFFileError):
783 # IOError can happen if the packaging control files disappear,
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500784 elf = None
785 for func in warnfuncs:
786 func(path, package, d, elf, warnings)
787 for func in errorfuncs:
788 func(path, package, d, elf, errors)
789
790 for w in warnings:
791 package_qa_handle_error(w, warnings[w], d)
792 for e in errors:
793 package_qa_handle_error(e, errors[e], d)
794
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500795def package_qa_check_rdepends(pkg, pkgdest, skip, taskdeps, packages, d):
796 # Don't do this check for kernel/module recipes, there aren't too many debug/development
797 # packages and you can get false positives e.g. on kernel-module-lirc-dev
798 if bb.data.inherits_class("kernel", d) or bb.data.inherits_class("module-base", d):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500799 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500800
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500801 if not "-dbg" in pkg and not "packagegroup-" in pkg and not "-image" in pkg:
802 localdata = bb.data.createCopy(d)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500803 localdata.setVar('OVERRIDES', localdata.getVar('OVERRIDES') + ':' + pkg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500804
805 # Now check the RDEPENDS
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500806 rdepends = bb.utils.explode_deps(localdata.getVar('RDEPENDS') or "")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500807
808 # Now do the sanity check!!!
809 if "build-deps" not in skip:
810 for rdepend in rdepends:
811 if "-dbg" in rdepend and "debug-deps" not in skip:
812 error_msg = "%s rdepends on %s" % (pkg,rdepend)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500813 package_qa_handle_error("debug-deps", error_msg, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500814 if (not "-dev" in pkg and not "-staticdev" in pkg) and rdepend.endswith("-dev") and "dev-deps" not in skip:
815 error_msg = "%s rdepends on %s" % (pkg, rdepend)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500816 package_qa_handle_error("dev-deps", error_msg, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500817 if rdepend not in packages:
818 rdep_data = oe.packagedata.read_subpkgdata(rdepend, d)
819 if rdep_data and 'PN' in rdep_data and rdep_data['PN'] in taskdeps:
820 continue
821 if not rdep_data or not 'PN' in rdep_data:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500822 pkgdata_dir = d.getVar("PKGDATA_DIR")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500823 try:
824 possibles = os.listdir("%s/runtime-rprovides/%s/" % (pkgdata_dir, rdepend))
825 except OSError:
826 possibles = []
827 for p in possibles:
828 rdep_data = oe.packagedata.read_subpkgdata(p, d)
829 if rdep_data and 'PN' in rdep_data and rdep_data['PN'] in taskdeps:
830 break
831 if rdep_data and 'PN' in rdep_data and rdep_data['PN'] in taskdeps:
832 continue
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500833 if rdep_data and 'PN' in rdep_data:
834 error_msg = "%s rdepends on %s, but it isn't a build dependency, missing %s in DEPENDS or PACKAGECONFIG?" % (pkg, rdepend, rdep_data['PN'])
835 else:
836 error_msg = "%s rdepends on %s, but it isn't a build dependency?" % (pkg, rdepend)
837 package_qa_handle_error("build-deps", error_msg, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500838
839 if "file-rdeps" not in skip:
840 ignored_file_rdeps = set(['/bin/sh', '/usr/bin/env', 'rtld(GNU_HASH)'])
841 if bb.data.inherits_class('nativesdk', d):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500842 ignored_file_rdeps |= set(['/bin/bash', '/usr/bin/perl', 'perl'])
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500843 # For Saving the FILERDEPENDS
844 filerdepends = {}
845 rdep_data = oe.packagedata.read_subpkgdata(pkg, d)
846 for key in rdep_data:
847 if key.startswith("FILERDEPENDS_"):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500848 for subkey in bb.utils.explode_deps(rdep_data[key]):
849 if subkey not in ignored_file_rdeps and \
850 not subkey.startswith('perl('):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500851 # We already know it starts with FILERDEPENDS_
852 filerdepends[subkey] = key[13:]
853
854 if filerdepends:
855 next = rdepends
856 done = rdepends[:]
857 # Find all the rdepends on the dependency chain
858 while next:
859 new = []
860 for rdep in next:
861 rdep_data = oe.packagedata.read_subpkgdata(rdep, d)
862 sub_rdeps = rdep_data.get("RDEPENDS_" + rdep)
863 if not sub_rdeps:
864 continue
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500865 for sub_rdep in bb.utils.explode_deps(sub_rdeps):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500866 if sub_rdep in done:
867 continue
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500868 if oe.packagedata.has_subpkgdata(sub_rdep, d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500869 # It's a new rdep
870 done.append(sub_rdep)
871 new.append(sub_rdep)
872 next = new
873
874 # Add the rprovides of itself
875 if pkg not in done:
876 done.insert(0, pkg)
877
878 # The python is not a package, but python-core provides it, so
879 # skip checking /usr/bin/python if python is in the rdeps, in
880 # case there is a RDEPENDS_pkg = "python" in the recipe.
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500881 for py in [ d.getVar('MLPREFIX') + "python", "python" ]:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500882 if py in done:
883 filerdepends.pop("/usr/bin/python",None)
884 done.remove(py)
885 for rdep in done:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500886 # The file dependencies may contain package names, e.g.,
887 # perl
888 filerdepends.pop(rdep,None)
889
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500890 # For Saving the FILERPROVIDES, RPROVIDES and FILES_INFO
891 rdep_data = oe.packagedata.read_subpkgdata(rdep, d)
892 for key in rdep_data:
893 if key.startswith("FILERPROVIDES_") or key.startswith("RPROVIDES_"):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500894 for subkey in bb.utils.explode_deps(rdep_data[key]):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500895 filerdepends.pop(subkey,None)
896 # Add the files list to the rprovides
897 if key == "FILES_INFO":
898 # Use eval() to make it as a dict
899 for subkey in eval(rdep_data[key]):
900 filerdepends.pop(subkey,None)
901 if not filerdepends:
902 # Break if all the file rdepends are met
903 break
904 if filerdepends:
905 for key in filerdepends:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500906 error_msg = "%s contained in package %s requires %s, but no providers found in RDEPENDS_%s?" % \
907 (filerdepends[key].replace("_%s" % pkg, "").replace("@underscore@", "_"), pkg, key, pkg)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500908 package_qa_handle_error("file-rdeps", error_msg, d)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500909package_qa_check_rdepends[vardepsexclude] = "OVERRIDES"
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500910
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500911def package_qa_check_deps(pkg, pkgdest, d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500912
913 localdata = bb.data.createCopy(d)
914 localdata.setVar('OVERRIDES', pkg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500915
916 def check_valid_deps(var):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500917 try:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500918 rvar = bb.utils.explode_dep_versions2(localdata.getVar(var) or "")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500919 except ValueError as e:
920 bb.fatal("%s_%s: %s" % (var, pkg, e))
921 for dep in rvar:
922 for v in rvar[dep]:
923 if v and not v.startswith(('< ', '= ', '> ', '<= ', '>=')):
924 error_msg = "%s_%s is invalid: %s (%s) only comparisons <, =, >, <=, and >= are allowed" % (var, pkg, dep, v)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500925 package_qa_handle_error("dep-cmp", error_msg, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500926
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500927 check_valid_deps('RDEPENDS')
928 check_valid_deps('RRECOMMENDS')
929 check_valid_deps('RSUGGESTS')
930 check_valid_deps('RPROVIDES')
931 check_valid_deps('RREPLACES')
932 check_valid_deps('RCONFLICTS')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500933
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500934QAPKGTEST[usrmerge] = "package_qa_check_usrmerge"
935def package_qa_check_usrmerge(pkg, d, messages):
936 pkgdest = d.getVar('PKGDEST')
937 pkg_dir = pkgdest + os.sep + pkg + os.sep
938 merged_dirs = ['bin', 'sbin', 'lib'] + d.getVar('MULTILIB_VARIANTS').split()
939 for f in merged_dirs:
940 if os.path.exists(pkg_dir + f) and not os.path.islink(pkg_dir + f):
941 msg = "%s package is not obeying usrmerge distro feature. /%s should be relocated to /usr." % (pkg, f)
942 package_qa_add_message(messages, "usrmerge", msg)
943 return False
944 return True
945
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500946QAPKGTEST[expanded-d] = "package_qa_check_expanded_d"
947def package_qa_check_expanded_d(package, d, messages):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500948 """
949 Check for the expanded D (${D}) value in pkg_* and FILES
950 variables, warn the user to use it correctly.
951 """
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500952 sane = True
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500953 expanded_d = d.getVar('D')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500954
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500955 for var in 'FILES','pkg_preinst', 'pkg_postinst', 'pkg_prerm', 'pkg_postrm':
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500956 bbvar = d.getVar(var + "_" + package) or ""
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500957 if expanded_d in bbvar:
958 if var == 'FILES':
959 package_qa_add_message(messages, "expanded-d", "FILES in %s recipe should not contain the ${D} variable as it references the local build directory not the target filesystem, best solution is to remove the ${D} reference" % package)
960 sane = False
961 else:
962 package_qa_add_message(messages, "expanded-d", "%s in %s recipe contains ${D}, it should be replaced by $D instead" % (var, package))
963 sane = False
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500964 return sane
965
966def package_qa_check_encoding(keys, encode, d):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600967 def check_encoding(key, enc):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500968 sane = True
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500969 value = d.getVar(key)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500970 if value:
971 try:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600972 s = value.encode(enc)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500973 except UnicodeDecodeError as e:
974 error_msg = "%s has non %s characters" % (key,enc)
975 sane = False
976 package_qa_handle_error("invalid-chars", error_msg, d)
977 return sane
978
979 for key in keys:
980 sane = check_encoding(key, encode)
981 if not sane:
982 break
983
984HOST_USER_UID := "${@os.getuid()}"
985HOST_USER_GID := "${@os.getgid()}"
986
987QAPATHTEST[host-user-contaminated] = "package_qa_check_host_user"
988def package_qa_check_host_user(path, name, d, elf, messages):
989 """Check for paths outside of /home which are owned by the user running bitbake."""
990
991 if not os.path.lexists(path):
992 return
993
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500994 dest = d.getVar('PKGDEST')
995 pn = d.getVar('PN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500996 home = os.path.join(dest, 'home')
997 if path == home or path.startswith(home + os.sep):
998 return
999
1000 try:
1001 stat = os.lstat(path)
1002 except OSError as exc:
1003 import errno
1004 if exc.errno != errno.ENOENT:
1005 raise
1006 else:
Patrick Williamsf1e5d692016-03-30 15:21:19 -05001007 rootfs_path = path[len(dest):]
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001008 check_uid = int(d.getVar('HOST_USER_UID'))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001009 if stat.st_uid == check_uid:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001010 package_qa_add_message(messages, "host-user-contaminated", "%s: %s is owned by uid %d, which is the same as the user running bitbake. This may be due to host contamination" % (pn, rootfs_path, check_uid))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001011 return False
1012
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001013 check_gid = int(d.getVar('HOST_USER_GID'))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001014 if stat.st_gid == check_gid:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001015 package_qa_add_message(messages, "host-user-contaminated", "%s: %s is owned by gid %d, which is the same as the user running bitbake. This may be due to host contamination" % (pn, rootfs_path, check_gid))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001016 return False
1017 return True
1018
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001019
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001020# The PACKAGE FUNC to scan each package
1021python do_package_qa () {
1022 import subprocess
1023 import oe.packagedata
1024
1025 bb.note("DO PACKAGE QA")
1026
1027 bb.build.exec_func("read_subpackage_metadata", d)
1028
1029 # Check non UTF-8 characters on recipe's metadata
1030 package_qa_check_encoding(['DESCRIPTION', 'SUMMARY', 'LICENSE', 'SECTION'], 'utf-8', d)
1031
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001032 logdir = d.getVar('T')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001033 pn = d.getVar('PN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001034
1035 # Check the compile log for host contamination
1036 compilelog = os.path.join(logdir,"log.do_compile")
1037
1038 if os.path.exists(compilelog):
1039 statement = "grep -e 'CROSS COMPILE Badness:' -e 'is unsafe for cross-compilation' %s > /dev/null" % compilelog
1040 if subprocess.call(statement, shell=True) == 0:
1041 msg = "%s: The compile log indicates that host include and/or library paths were used.\n \
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001042 Please check the log '%s' for more information." % (pn, compilelog)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001043 package_qa_handle_error("compile-host-path", msg, d)
1044
1045 # Check the install log for host contamination
1046 installlog = os.path.join(logdir,"log.do_install")
1047
1048 if os.path.exists(installlog):
1049 statement = "grep -e 'CROSS COMPILE Badness:' -e 'is unsafe for cross-compilation' %s > /dev/null" % installlog
1050 if subprocess.call(statement, shell=True) == 0:
1051 msg = "%s: The install log indicates that host include and/or library paths were used.\n \
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001052 Please check the log '%s' for more information." % (pn, installlog)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001053 package_qa_handle_error("install-host-path", msg, d)
1054
1055 # Scan the packages...
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001056 pkgdest = d.getVar('PKGDEST')
1057 packages = set((d.getVar('PACKAGES') or '').split())
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001058
1059 cpath = oe.cachedpath.CachedPath()
1060 global pkgfiles
1061 pkgfiles = {}
1062 for pkg in packages:
1063 pkgfiles[pkg] = []
1064 for walkroot, dirs, files in cpath.walk(pkgdest + "/" + pkg):
1065 for file in files:
1066 pkgfiles[pkg].append(walkroot + os.sep + file)
1067
1068 # no packages should be scanned
1069 if not packages:
1070 return
1071
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001072 import re
1073 # The package name matches the [a-z0-9.+-]+ regular expression
1074 pkgname_pattern = re.compile("^[a-z0-9.+-]+$")
1075
1076 taskdepdata = d.getVar("BB_TASKDEPDATA", False)
1077 taskdeps = set()
1078 for dep in taskdepdata:
1079 taskdeps.add(taskdepdata[dep][0])
1080
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001081 def parse_test_matrix(matrix_name):
1082 testmatrix = d.getVarFlags(matrix_name) or {}
1083 g = globals()
1084 warnchecks = []
1085 for w in (d.getVar("WARN_QA") or "").split():
1086 if w in skip:
1087 continue
1088 if w in testmatrix and testmatrix[w] in g:
1089 warnchecks.append(g[testmatrix[w]])
1090
1091 errorchecks = []
1092 for e in (d.getVar("ERROR_QA") or "").split():
1093 if e in skip:
1094 continue
1095 if e in testmatrix and testmatrix[e] in g:
1096 errorchecks.append(g[testmatrix[e]])
1097 return warnchecks, errorchecks
1098
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001099 for package in packages:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001100 skip = set((d.getVar('INSANE_SKIP') or "").split() +
1101 (d.getVar('INSANE_SKIP_' + package) or "").split())
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001102 if skip:
1103 bb.note("Package %s skipping QA tests: %s" % (package, str(skip)))
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001104
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001105 bb.note("Checking Package: %s" % package)
1106 # Check package name
1107 if not pkgname_pattern.match(package):
1108 package_qa_handle_error("pkgname",
Patrick Williamsf1e5d692016-03-30 15:21:19 -05001109 "%s doesn't match the [a-z0-9.+-]+ regex" % package, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001110
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001111 warn_checks, error_checks = parse_test_matrix("QAPATHTEST")
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001112 package_qa_walk(warn_checks, error_checks, package, d)
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001113
1114 warn_checks, error_checks = parse_test_matrix("QAPKGTEST")
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001115 package_qa_package(warn_checks, error_checks, package, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001116
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001117 package_qa_check_rdepends(package, pkgdest, skip, taskdeps, packages, d)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001118 package_qa_check_deps(package, pkgdest, d)
1119
1120 warn_checks, error_checks = parse_test_matrix("QARECIPETEST")
1121 package_qa_recipe(warn_checks, error_checks, pn, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001122
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001123 if 'libdir' in d.getVar("ALL_QA").split():
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001124 package_qa_check_libdir(d)
1125
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001126 qa_sane = d.getVar("QA_SANE")
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001127 if not qa_sane:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001128 bb.fatal("QA run found fatal errors. Please consider fixing them.")
1129 bb.note("DONE with PACKAGE QA")
1130}
1131
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001132# binutils is used for most checks, so need to set as dependency
1133# POPULATESYSROOTDEPS is defined in staging class.
1134do_package_qa[depends] += "${POPULATESYSROOTDEPS}"
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001135do_package_qa[vardepsexclude] = "BB_TASKDEPDATA"
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001136do_package_qa[rdeptask] = "do_packagedata"
1137addtask do_package_qa after do_packagedata do_package before do_build
1138
1139SSTATETASKS += "do_package_qa"
1140do_package_qa[sstate-inputdirs] = ""
1141do_package_qa[sstate-outputdirs] = ""
1142python do_package_qa_setscene () {
1143 sstate_setscene(d)
1144}
1145addtask do_package_qa_setscene
1146
1147python do_qa_staging() {
1148 bb.note("QA checking staging")
1149
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001150 if not package_qa_check_staged(d.expand('${SYSROOT_DESTDIR}${libdir}'), d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001151 bb.fatal("QA staging was broken by the package built above")
1152}
1153
1154python do_qa_configure() {
1155 import subprocess
1156
1157 ###########################################################################
1158 # Check config.log for cross compile issues
1159 ###########################################################################
1160
1161 configs = []
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001162 workdir = d.getVar('WORKDIR')
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001163
1164 if bb.data.inherits_class('autotools', d):
1165 bb.note("Checking autotools environment for common misconfiguration")
1166 for root, dirs, files in os.walk(workdir):
1167 statement = "grep -q -F -e 'CROSS COMPILE Badness:' -e 'is unsafe for cross-compilation' %s" % \
1168 os.path.join(root,"config.log")
1169 if "config.log" in files:
1170 if subprocess.call(statement, shell=True) == 0:
1171 bb.fatal("""This autoconf log indicates errors, it looked at host include and/or library paths while determining system capabilities.
Patrick Williamsf1e5d692016-03-30 15:21:19 -05001172Rerun configure task after fixing this.""")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001173
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001174 if "configure.ac" in files:
1175 configs.append(os.path.join(root,"configure.ac"))
1176 if "configure.in" in files:
1177 configs.append(os.path.join(root, "configure.in"))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001178
1179 ###########################################################################
1180 # Check gettext configuration and dependencies are correct
1181 ###########################################################################
1182
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001183 cnf = d.getVar('EXTRA_OECONF') or ""
1184 if "gettext" not in d.getVar('P') and "gcc-runtime" not in d.getVar('P') and "--disable-nls" not in cnf:
1185 ml = d.getVar("MLPREFIX") or ""
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001186 if bb.data.inherits_class('cross-canadian', d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001187 gt = "nativesdk-gettext"
1188 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001189 gt = "gettext-native"
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001190 deps = bb.utils.explode_deps(d.getVar('DEPENDS') or "")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001191 if gt not in deps:
1192 for config in configs:
1193 gnu = "grep \"^[[:space:]]*AM_GNU_GETTEXT\" %s >/dev/null" % config
1194 if subprocess.call(gnu, shell=True) == 0:
1195 bb.fatal("""%s required but not in DEPENDS for file %s.
1196Missing inherit gettext?""" % (gt, config))
1197
1198 ###########################################################################
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001199 # Check unrecognised configure options (with a white list)
1200 ###########################################################################
1201 if bb.data.inherits_class("autotools", d):
1202 bb.note("Checking configure output for unrecognised options")
1203 try:
1204 flag = "WARNING: unrecognized options:"
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001205 log = os.path.join(d.getVar('B'), 'config.log')
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001206 output = subprocess.check_output(['grep', '-F', flag, log]).decode("utf-8").replace(', ', ' ')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001207 options = set()
1208 for line in output.splitlines():
1209 options |= set(line.partition(flag)[2].split())
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001210 whitelist = set(d.getVar("UNKNOWN_CONFIGURE_WHITELIST").split())
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001211 options -= whitelist
1212 if options:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001213 pn = d.getVar('PN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001214 error_msg = pn + ": configure was passed unrecognised options: " + " ".join(options)
1215 package_qa_handle_error("unknown-configure-option", error_msg, d)
1216 except subprocess.CalledProcessError:
1217 pass
1218
1219 # Check invalid PACKAGECONFIG
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001220 pkgconfig = (d.getVar("PACKAGECONFIG") or "").split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001221 if pkgconfig:
1222 pkgconfigflags = d.getVarFlags("PACKAGECONFIG") or {}
1223 for pconfig in pkgconfig:
1224 if pconfig not in pkgconfigflags:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001225 pn = d.getVar('PN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001226 error_msg = "%s: invalid PACKAGECONFIG: %s" % (pn, pconfig)
Patrick Williamsf1e5d692016-03-30 15:21:19 -05001227 package_qa_handle_error("invalid-packageconfig", error_msg, d)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001228
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001229 qa_sane = d.getVar("QA_SANE")
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001230 if not qa_sane:
1231 bb.fatal("Fatal QA errors found, failing task.")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001232}
1233
1234python do_qa_unpack() {
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001235 src_uri = d.getVar('SRC_URI')
1236 s_dir = d.getVar('S')
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001237 if src_uri and not os.path.exists(s_dir):
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001238 bb.warn('%s: the directory %s (%s) pointed to by the S variable doesn\'t exist - please set S within the recipe to point to where the source has been unpacked to' % (d.getVar('PN'), d.getVar('S', False), s_dir))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001239}
1240
1241# The Staging Func, to check all staging
1242#addtask qa_staging after do_populate_sysroot before do_build
1243do_populate_sysroot[postfuncs] += "do_qa_staging "
1244
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001245# Check broken config.log files, for packages requiring Gettext which
1246# don't have it in DEPENDS.
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001247#addtask qa_configure after do_configure before do_compile
1248do_configure[postfuncs] += "do_qa_configure "
1249
1250# Check does S exist.
1251do_unpack[postfuncs] += "do_qa_unpack"
1252
1253python () {
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001254 import re
1255
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001256 tests = d.getVar('ALL_QA').split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001257 if "desktop" in tests:
1258 d.appendVar("PACKAGE_DEPENDS", " desktop-file-utils-native")
1259
1260 ###########################################################################
1261 # Check various variables
1262 ###########################################################################
1263
1264 # Checking ${FILESEXTRAPATHS}
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001265 extrapaths = (d.getVar("FILESEXTRAPATHS") or "")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001266 if '__default' not in extrapaths.split(":"):
1267 msg = "FILESEXTRAPATHS-variable, must always use _prepend (or _append)\n"
1268 msg += "type of assignment, and don't forget the colon.\n"
1269 msg += "Please assign it with the format of:\n"
1270 msg += " FILESEXTRAPATHS_append := \":${THISDIR}/Your_Files_Path\" or\n"
1271 msg += " FILESEXTRAPATHS_prepend := \"${THISDIR}/Your_Files_Path:\"\n"
1272 msg += "in your bbappend file\n\n"
1273 msg += "Your incorrect assignment is:\n"
1274 msg += "%s\n" % extrapaths
1275 bb.warn(msg)
1276
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001277 overrides = d.getVar('OVERRIDES').split(':')
1278 pn = d.getVar('PN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001279 if pn in overrides:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001280 msg = 'Recipe %s has PN of "%s" which is in OVERRIDES, this can result in unexpected behaviour.' % (d.getVar("FILE"), pn)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001281 package_qa_handle_error("pn-overrides", msg, d)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001282 prog = re.compile('[A-Z]')
1283 if prog.search(pn):
1284 package_qa_handle_error("uppercase-pn", 'PN: %s is upper case, this can result in unexpected behavior.' % pn, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001285
1286 issues = []
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001287 if (d.getVar('PACKAGES') or "").split():
1288 for dep in (d.getVar('QADEPENDS') or "").split():
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001289 d.appendVarFlag('do_package_qa', 'depends', " %s:do_populate_sysroot" % dep)
1290 for var in 'RDEPENDS', 'RRECOMMENDS', 'RSUGGESTS', 'RCONFLICTS', 'RPROVIDES', 'RREPLACES', 'FILES', 'pkg_preinst', 'pkg_postinst', 'pkg_prerm', 'pkg_postrm', 'ALLOW_EMPTY':
1291 if d.getVar(var, False):
1292 issues.append(var)
1293
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001294 fakeroot_tests = d.getVar('FAKEROOT_QA').split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001295 if set(tests) & set(fakeroot_tests):
1296 d.setVarFlag('do_package_qa', 'fakeroot', '1')
1297 d.appendVarFlag('do_package_qa', 'depends', ' virtual/fakeroot-native:do_populate_sysroot')
1298 else:
1299 d.setVarFlag('do_package_qa', 'rdeptask', '')
1300 for i in issues:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001301 package_qa_handle_error("pkgvarcheck", "%s: Variable %s is set as not being package specific, please fix this." % (d.getVar("FILE"), i), d)
1302 qa_sane = d.getVar("QA_SANE")
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001303 if not qa_sane:
1304 bb.fatal("Fatal QA errors found, failing task.")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001305}