blob: 9b886d1380581d1f98033465dc5de3f60518f93c [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 Bishop15ae2502019-06-18 21:44:24 -040028 pn-overrides infodir build-deps src-uri-bad \
Patrick Williamsc124f4f2015-09-15 14:41:29 -050029 unknown-configure-option symlink-to-sysroot multilib \
Brad Bishopd89cb5f2019-04-10 09:02:41 -040030 invalid-packageconfig host-user-contaminated uppercase-pn patch-fuzz \
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 Bishop19323692019-04-05 15:28:33 -040036 license-checksum dev-elf file-rdeps configure-unsafe \
37 configure-gettext \
Patrick Williamsc124f4f2015-09-15 14:41:29 -050038 "
Brad Bishopd7bf8c12018-02-25 22:55:05 -050039# Add usrmerge QA check based on distro feature
40ERROR_QA_append = "${@bb.utils.contains('DISTRO_FEATURES', 'usrmerge', ' usrmerge', '', d)}"
41
Patrick Williamsc124f4f2015-09-15 14:41:29 -050042FAKEROOT_QA = "host-user-contaminated"
43FAKEROOT_QA[doc] = "QA tests which need to run under fakeroot. If any \
44enabled tests are listed here, the do_package_qa task will run under fakeroot."
45
46ALL_QA = "${WARN_QA} ${ERROR_QA}"
47
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050048UNKNOWN_CONFIGURE_WHITELIST ?= "--enable-nls --disable-nls --disable-silent-rules --disable-dependency-tracking --with-libtool-sysroot --disable-static"
Patrick Williamsc124f4f2015-09-15 14:41:29 -050049
Patrick Williamsc0f7c042017-02-23 20:41:17 -060050def package_qa_clean_path(path, d, pkg=None):
51 """
52 Remove redundant paths from the path for display. If pkg isn't set then
53 TMPDIR is stripped, otherwise PKGDEST/pkg is stripped.
54 """
55 if pkg:
Brad Bishop6e60e8b2018-02-01 10:27:11 -050056 path = path.replace(os.path.join(d.getVar("PKGDEST"), pkg), "/")
57 return path.replace(d.getVar("TMPDIR"), "/").replace("//", "/")
Patrick Williamsc124f4f2015-09-15 14:41:29 -050058
59def package_qa_write_error(type, error, d):
Brad Bishop6e60e8b2018-02-01 10:27:11 -050060 logfile = d.getVar('QA_LOGFILE')
Patrick Williamsc124f4f2015-09-15 14:41:29 -050061 if logfile:
Brad Bishop6e60e8b2018-02-01 10:27:11 -050062 p = d.getVar('P')
Patrick Williamsc0f7c042017-02-23 20:41:17 -060063 with open(logfile, "a+") as f:
64 f.write("%s: %s [%s]\n" % (p, error, type))
Patrick Williamsc124f4f2015-09-15 14:41:29 -050065
66def package_qa_handle_error(error_class, error_msg, d):
Brad Bishop6e60e8b2018-02-01 10:27:11 -050067 if error_class in (d.getVar("ERROR_QA") or "").split():
Brad Bishopd7bf8c12018-02-25 22:55:05 -050068 package_qa_write_error(error_class, error_msg, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050069 bb.error("QA Issue: %s [%s]" % (error_msg, error_class))
70 d.setVar("QA_SANE", False)
71 return False
Brad Bishop6e60e8b2018-02-01 10:27:11 -050072 elif error_class in (d.getVar("WARN_QA") or "").split():
Brad Bishopd7bf8c12018-02-25 22:55:05 -050073 package_qa_write_error(error_class, error_msg, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050074 bb.warn("QA Issue: %s [%s]" % (error_msg, error_class))
75 else:
76 bb.note("QA Issue: %s [%s]" % (error_msg, error_class))
77 return True
78
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050079def package_qa_add_message(messages, section, new_msg):
80 if section not in messages:
81 messages[section] = new_msg
82 else:
83 messages[section] = messages[section] + "\n" + new_msg
84
Patrick Williamsc124f4f2015-09-15 14:41:29 -050085QAPATHTEST[libexec] = "package_qa_check_libexec"
86def package_qa_check_libexec(path,name, d, elf, messages):
87
88 # Skip the case where the default is explicitly /usr/libexec
Brad Bishop6e60e8b2018-02-01 10:27:11 -050089 libexec = d.getVar('libexecdir')
Patrick Williamsc124f4f2015-09-15 14:41:29 -050090 if libexec == "/usr/libexec":
91 return True
92
93 if 'libexec' in path.split(os.path.sep):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050094 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 -050095 return False
96
97 return True
98
99QAPATHTEST[rpaths] = "package_qa_check_rpath"
100def package_qa_check_rpath(file,name, d, elf, messages):
101 """
102 Check for dangerous RPATHs
103 """
104 if not elf:
105 return
106
107 if os.path.islink(file):
108 return
109
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500110 bad_dirs = [d.getVar('BASE_WORKDIR'), d.getVar('STAGING_DIR_TARGET')]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500111
112 phdrs = elf.run_objdump("-p", d)
113
114 import re
Brad Bishop977dc1a2019-02-06 16:01:43 -0500115 rpath_re = re.compile(r"\s+RPATH\s+(.*)")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500116 for line in phdrs.split("\n"):
117 m = rpath_re.match(line)
118 if m:
119 rpath = m.group(1)
120 for dir in bad_dirs:
121 if dir in rpath:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500122 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 -0500123
124QAPATHTEST[useless-rpaths] = "package_qa_check_useless_rpaths"
125def package_qa_check_useless_rpaths(file, name, d, elf, messages):
126 """
127 Check for RPATHs that are useless but not dangerous
128 """
129 def rpath_eq(a, b):
130 return os.path.normpath(a) == os.path.normpath(b)
131
132 if not elf:
133 return
134
135 if os.path.islink(file):
136 return
137
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500138 libdir = d.getVar("libdir")
139 base_libdir = d.getVar("base_libdir")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500140
141 phdrs = elf.run_objdump("-p", d)
142
143 import re
Brad Bishop977dc1a2019-02-06 16:01:43 -0500144 rpath_re = re.compile(r"\s+RPATH\s+(.*)")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500145 for line in phdrs.split("\n"):
146 m = rpath_re.match(line)
147 if m:
148 rpath = m.group(1)
149 if rpath_eq(rpath, libdir) or rpath_eq(rpath, base_libdir):
150 # The dynamic linker searches both these places anyway. There is no point in
151 # looking there again.
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500152 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 -0500153
154QAPATHTEST[dev-so] = "package_qa_check_dev"
155def package_qa_check_dev(path, name, d, elf, messages):
156 """
157 Check for ".so" library symlinks in non-dev packages
158 """
159
160 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 -0500161 package_qa_add_message(messages, "dev-so", "non -dev/-dbg/nativesdk- package contains symlink .so: %s path '%s'" % \
162 (name, package_qa_clean_path(path,d)))
163
164QAPATHTEST[dev-elf] = "package_qa_check_dev_elf"
165def package_qa_check_dev_elf(path, name, d, elf, messages):
166 """
167 Check that -dev doesn't contain real shared libraries. The test has to
168 check that the file is not a link and is an ELF object as some recipes
169 install link-time .so files that are linker scripts.
170 """
171 if name.endswith("-dev") and path.endswith(".so") and not os.path.islink(path) and elf:
172 package_qa_add_message(messages, "dev-elf", "-dev package contains non-symlink .so: %s path '%s'" % \
173 (name, package_qa_clean_path(path,d)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500174
175QAPATHTEST[staticdev] = "package_qa_check_staticdev"
176def package_qa_check_staticdev(path, name, d, elf, messages):
177 """
178 Check for ".a" library in non-staticdev packages
179 There are a number of exceptions to this rule, -pic packages can contain
180 static libraries, the _nonshared.a belong with their -dev packages and
181 libgcc.a, libgcov.a will be skipped in their packages
182 """
183
184 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 -0500185 package_qa_add_message(messages, "staticdev", "non -staticdev package contains static .a library: %s path '%s'" % \
186 (name, package_qa_clean_path(path,d)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500187
188def package_qa_check_libdir(d):
189 """
190 Check for wrong library installation paths. For instance, catch
191 recipes installing /lib/bar.so when ${base_libdir}="lib32" or
192 installing in /usr/lib64 when ${libdir}="/usr/lib"
193 """
194 import re
195
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500196 pkgdest = d.getVar('PKGDEST')
197 base_libdir = d.getVar("base_libdir") + os.sep
198 libdir = d.getVar("libdir") + os.sep
199 libexecdir = d.getVar("libexecdir") + os.sep
200 exec_prefix = d.getVar("exec_prefix") + os.sep
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500201
202 messages = []
203
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500204 # The re's are purposely fuzzy, as some there are some .so.x.y.z files
205 # that don't follow the standard naming convention. It checks later
206 # that they are actual ELF files
Brad Bishop977dc1a2019-02-06 16:01:43 -0500207 lib_re = re.compile(r"^/lib.+\.so(\..+)?$")
208 exec_re = re.compile(r"^%s.*/lib.+\.so(\..+)?$" % exec_prefix)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500209
210 for root, dirs, files in os.walk(pkgdest):
211 if root == pkgdest:
212 # Skip subdirectories for any packages with libdir in INSANE_SKIP
213 skippackages = []
214 for package in dirs:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500215 if 'libdir' in (d.getVar('INSANE_SKIP_' + package) or "").split():
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500216 bb.note("Package %s skipping libdir QA test" % (package))
217 skippackages.append(package)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500218 elif d.getVar('PACKAGE_DEBUG_SPLIT_STYLE') == 'debug-file-directory' and package.endswith("-dbg"):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500219 bb.note("Package %s skipping libdir QA test for PACKAGE_DEBUG_SPLIT_STYLE equals debug-file-directory" % (package))
220 skippackages.append(package)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500221 for package in skippackages:
222 dirs.remove(package)
223 for file in files:
224 full_path = os.path.join(root, file)
225 rel_path = os.path.relpath(full_path, pkgdest)
226 if os.sep in rel_path:
227 package, rel_path = rel_path.split(os.sep, 1)
228 rel_path = os.sep + rel_path
229 if lib_re.match(rel_path):
230 if base_libdir not in rel_path:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500231 # make sure it's an actual ELF file
232 elf = oe.qa.ELFFile(full_path)
233 try:
234 elf.open()
235 messages.append("%s: found library in wrong location: %s" % (package, rel_path))
236 except (oe.qa.NotELFFileError):
237 pass
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500238 if exec_re.match(rel_path):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500239 if libdir not in rel_path and libexecdir not in rel_path:
240 # make sure it's an actual ELF file
241 elf = oe.qa.ELFFile(full_path)
242 try:
243 elf.open()
244 messages.append("%s: found library in wrong location: %s" % (package, rel_path))
245 except (oe.qa.NotELFFileError):
246 pass
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500247
248 if messages:
249 package_qa_handle_error("libdir", "\n".join(messages), d)
250
251QAPATHTEST[debug-files] = "package_qa_check_dbg"
252def package_qa_check_dbg(path, name, d, elf, messages):
253 """
254 Check for ".debug" files or directories outside of the dbg package
255 """
256
257 if not "-dbg" in name and not "-ptest" in name:
258 if '.debug' in path.split(os.path.sep):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500259 package_qa_add_message(messages, "debug-files", "non debug package contains .debug directory: %s path %s" % \
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500260 (name, package_qa_clean_path(path,d)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500261
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500262QAPATHTEST[arch] = "package_qa_check_arch"
263def package_qa_check_arch(path,name,d, elf, messages):
264 """
265 Check if archs are compatible
266 """
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800267 import re, oe.elf
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600268
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500269 if not elf:
270 return
271
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500272 target_os = d.getVar('TARGET_OS')
273 target_arch = d.getVar('TARGET_ARCH')
274 provides = d.getVar('PROVIDES')
275 bpn = d.getVar('BPN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500276
277 if target_arch == "allarch":
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500278 pn = d.getVar('PN')
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500279 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 -0500280 return
281
282 # FIXME: Cross package confuse this check, so just skip them
283 for s in ['cross', 'nativesdk', 'cross-canadian']:
284 if bb.data.inherits_class(s, d):
285 return
286
287 # avoid following links to /usr/bin (e.g. on udev builds)
288 # we will check the files pointed to anyway...
289 if os.path.islink(path):
290 return
291
292 #if this will throw an exception, then fix the dict above
293 (machine, osabi, abiversion, littleendian, bits) \
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800294 = oe.elf.machine_dict(d)[target_os][target_arch]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500295
296 # Check the architecture and endiannes of the binary
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600297 is_32 = (("virtual/kernel" in provides) or bb.data.inherits_class("module", d)) and \
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800298 (target_os == "linux-gnux32" or target_os == "linux-muslx32" or \
Brad Bishop977dc1a2019-02-06 16:01:43 -0500299 target_os == "linux-gnu_ilp32" or re.match(r'mips64.*32', d.getVar('DEFAULTTUNE')))
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800300 is_bpf = (oe.qa.elf_machine_to_string(elf.machine()) == "BPF")
301 if not ((machine == elf.machine()) or is_32 or is_bpf):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600302 package_qa_add_message(messages, "arch", "Architecture did not match (%s, expected %s) on %s" % \
303 (oe.qa.elf_machine_to_string(elf.machine()), oe.qa.elf_machine_to_string(machine), package_qa_clean_path(path,d)))
Brad Bishop19323692019-04-05 15:28:33 -0400304 elif not ((bits == elf.abiSize()) or is_32 or is_bpf):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500305 package_qa_add_message(messages, "arch", "Bit size did not match (%d to %d) %s on %s" % \
306 (bits, elf.abiSize(), bpn, package_qa_clean_path(path,d)))
Brad Bishop19323692019-04-05 15:28:33 -0400307 elif not ((littleendian == elf.isLittleEndian()) or is_bpf):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500308 package_qa_add_message(messages, "arch", "Endiannes did not match (%d to %d) on %s" % \
309 (littleendian, elf.isLittleEndian(), package_qa_clean_path(path,d)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500310
311QAPATHTEST[desktop] = "package_qa_check_desktop"
312def package_qa_check_desktop(path, name, d, elf, messages):
313 """
314 Run all desktop files through desktop-file-validate.
315 """
316 if path.endswith(".desktop"):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500317 desktop_file_validate = os.path.join(d.getVar('STAGING_BINDIR_NATIVE'),'desktop-file-validate')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500318 output = os.popen("%s %s" % (desktop_file_validate, path))
319 # This only produces output on errors
320 for l in output:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500321 package_qa_add_message(messages, "desktop", "Desktop file issue: " + l.strip())
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500322
323QAPATHTEST[textrel] = "package_qa_textrel"
324def package_qa_textrel(path, name, d, elf, messages):
325 """
326 Check if the binary contains relocations in .text
327 """
328
329 if not elf:
330 return
331
332 if os.path.islink(path):
333 return
334
335 phdrs = elf.run_objdump("-p", d)
336 sane = True
337
338 import re
Brad Bishop977dc1a2019-02-06 16:01:43 -0500339 textrel_re = re.compile(r"\s+TEXTREL\s+")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500340 for line in phdrs.split("\n"):
341 if textrel_re.match(line):
342 sane = False
343
344 if not sane:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500345 package_qa_add_message(messages, "textrel", "ELF binary '%s' has relocations in .text" % path)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500346
347QAPATHTEST[ldflags] = "package_qa_hash_style"
348def package_qa_hash_style(path, name, d, elf, messages):
349 """
350 Check if the binary has the right hash style...
351 """
352
353 if not elf:
354 return
355
356 if os.path.islink(path):
357 return
358
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500359 gnu_hash = "--hash-style=gnu" in d.getVar('LDFLAGS')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500360 if not gnu_hash:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500361 gnu_hash = "--hash-style=both" in d.getVar('LDFLAGS')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500362 if not gnu_hash:
363 return
364
365 sane = False
366 has_syms = False
367
368 phdrs = elf.run_objdump("-p", d)
369
370 # If this binary has symbols, we expect it to have GNU_HASH too.
371 for line in phdrs.split("\n"):
372 if "SYMTAB" in line:
373 has_syms = True
374 if "GNU_HASH" in line:
375 sane = True
376 if "[mips32]" in line or "[mips64]" in line:
377 sane = True
378
379 if has_syms and not sane:
Brad Bishopa5c52ff2018-11-23 10:55:50 +1300380 package_qa_add_message(messages, "ldflags", "No GNU_HASH in the ELF binary %s, didn't pass LDFLAGS?" % path)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500381
382
383QAPATHTEST[buildpaths] = "package_qa_check_buildpaths"
384def package_qa_check_buildpaths(path, name, d, elf, messages):
385 """
386 Check for build paths inside target files and error if not found in the whitelist
387 """
388 # Ignore .debug files, not interesting
389 if path.find(".debug") != -1:
390 return
391
392 # Ignore symlinks
393 if os.path.islink(path):
394 return
395
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500396 # Ignore ipk and deb's CONTROL dir
397 if path.find(name + "/CONTROL/") != -1 or path.find(name + "/DEBIAN/") != -1:
398 return
399
Brad Bishopd5ae7d92018-06-14 09:52:03 -0700400 tmpdir = bytes(d.getVar('TMPDIR'), encoding="utf-8")
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500401 with open(path, 'rb') as f:
Brad Bishopd5ae7d92018-06-14 09:52:03 -0700402 file_content = f.read()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500403 if tmpdir in file_content:
Brad Bishopf3fd2882019-06-21 08:06:37 -0400404 trimmed = path.replace(os.path.join (d.getVar("PKGDEST"), name), "")
405 package_qa_add_message(messages, "buildpaths", "File %s in package %s contains reference to TMPDIR" % (trimmed, name))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500406
407
408QAPATHTEST[xorg-driver-abi] = "package_qa_check_xorg_driver_abi"
409def package_qa_check_xorg_driver_abi(path, name, d, elf, messages):
410 """
411 Check that all packages containing Xorg drivers have ABI dependencies
412 """
413
414 # Skip dev, dbg or nativesdk packages
415 if name.endswith("-dev") or name.endswith("-dbg") or name.startswith("nativesdk-"):
416 return
417
418 driverdir = d.expand("${libdir}/xorg/modules/drivers/")
419 if driverdir in path and path.endswith(".so"):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500420 mlprefix = d.getVar('MLPREFIX') or ''
421 for rdep in bb.utils.explode_deps(d.getVar('RDEPENDS_' + name) or ""):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500422 if rdep.startswith("%sxorg-abi-" % mlprefix):
423 return
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500424 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 -0500425
426QAPATHTEST[infodir] = "package_qa_check_infodir"
427def package_qa_check_infodir(path, name, d, elf, messages):
428 """
429 Check that /usr/share/info/dir isn't shipped in a particular package
430 """
431 infodir = d.expand("${infodir}/dir")
432
433 if infodir in path:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500434 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 -0500435
436QAPATHTEST[symlink-to-sysroot] = "package_qa_check_symlink_to_sysroot"
437def package_qa_check_symlink_to_sysroot(path, name, d, elf, messages):
438 """
439 Check that the package doesn't contain any absolute symlinks to the sysroot.
440 """
441 if os.path.islink(path):
442 target = os.readlink(path)
443 if os.path.isabs(target):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500444 tmpdir = d.getVar('TMPDIR')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500445 if target.startswith(tmpdir):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500446 trimmed = path.replace(os.path.join (d.getVar("PKGDEST"), name), "")
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500447 package_qa_add_message(messages, "symlink-to-sysroot", "Symlink %s in %s points to TMPDIR" % (trimmed, name))
448
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600449# Check license variables
450do_populate_lic[postfuncs] += "populate_lic_qa_checksum"
451python populate_lic_qa_checksum() {
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500452 """
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600453 Check for changes in the license files.
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500454 """
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500455 sane = True
456
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500457 lic_files = d.getVar('LIC_FILES_CHKSUM') or ''
458 lic = d.getVar('LICENSE')
459 pn = d.getVar('PN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500460
461 if lic == "CLOSED":
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500462 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500463
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500464 if not lic_files and d.getVar('SRC_URI'):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800465 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 -0500466
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500467 srcdir = d.getVar('S')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500468 corebase_licensefile = d.getVar('COREBASE') + "/LICENSE"
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500469 for url in lic_files.split():
470 try:
471 (type, host, path, user, pswd, parm) = bb.fetch.decodeurl(url)
472 except bb.fetch.MalformedUrl:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800473 sane &= package_qa_handle_error("license-checksum", pn + ": LIC_FILES_CHKSUM contains an invalid URL: " + url, d)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500474 continue
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500475 srclicfile = os.path.join(srcdir, path)
476 if not os.path.isfile(srclicfile):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800477 sane &= package_qa_handle_error("license-checksum", pn + ": LIC_FILES_CHKSUM points to an invalid file: " + srclicfile, d)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500478 continue
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500479
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500480 if (srclicfile == corebase_licensefile):
481 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")
482
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500483 recipemd5 = parm.get('md5', '')
484 beginline, endline = 0, 0
485 if 'beginline' in parm:
486 beginline = int(parm['beginline'])
487 if 'endline' in parm:
488 endline = int(parm['endline'])
489
490 if (not beginline) and (not endline):
491 md5chksum = bb.utils.md5_file(srclicfile)
Brad Bishop19323692019-04-05 15:28:33 -0400492 with open(srclicfile, 'r', errors='replace') as f:
493 license = f.read().splitlines()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500494 else:
Brad Bishop19323692019-04-05 15:28:33 -0400495 with open(srclicfile, 'rb') as f:
496 import hashlib
497 lineno = 0
498 license = []
499 m = hashlib.md5()
500 for line in f:
501 lineno += 1
502 if (lineno >= beginline):
503 if ((lineno <= endline) or not endline):
504 m.update(line)
505 license.append(line.decode('utf-8', errors='replace').rstrip())
506 else:
507 break
508 md5chksum = m.hexdigest()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500509 if recipemd5 == md5chksum:
510 bb.note (pn + ": md5 checksum matched for ", url)
511 else:
512 if recipemd5:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500513 msg = pn + ": The LIC_FILES_CHKSUM does not match for " + url
514 msg = msg + "\n" + pn + ": The new md5 checksum is " + md5chksum
Brad Bishop19323692019-04-05 15:28:33 -0400515 max_lines = int(d.getVar('QA_MAX_LICENSE_LINES') or 20)
516 if not license or license[-1] != '':
517 # Ensure that our license text ends with a line break
518 # (will be added with join() below).
519 license.append('')
520 remove = len(license) - max_lines
521 if remove > 0:
522 start = max_lines // 2
523 end = start + remove - 1
524 del license[start:end]
525 license.insert(start, '...')
526 msg = msg + "\n" + pn + ": Here is the selected license text:" + \
527 "\n" + \
528 "{:v^70}".format(" beginline=%d " % beginline if beginline else "") + \
529 "\n" + "\n".join(license) + \
530 "{:^^70}".format(" endline=%d " % endline if endline else "")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500531 if beginline:
532 if endline:
533 srcfiledesc = "%s (lines %d through to %d)" % (srclicfile, beginline, endline)
534 else:
535 srcfiledesc = "%s (beginning on line %d)" % (srclicfile, beginline)
536 elif endline:
537 srcfiledesc = "%s (ending on line %d)" % (srclicfile, endline)
538 else:
539 srcfiledesc = srclicfile
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500540 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 -0500541
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500542 else:
543 msg = pn + ": LIC_FILES_CHKSUM is not specified for " + url
544 msg = msg + "\n" + pn + ": The md5 checksum is " + md5chksum
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800545 sane &= package_qa_handle_error("license-checksum", msg, d)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600546
547 if not sane:
548 bb.fatal("Fatal QA errors found, failing task.")
549}
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500550
Brad Bishop19323692019-04-05 15:28:33 -0400551def qa_check_staged(path,d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500552 """
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500553 Check staged la and pc files for common problems like references to the work
554 directory.
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500555
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500556 As this is run after every stage we should be able to find the one
557 responsible for the errors easily even if we look at every .pc and .la file.
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500558 """
559
560 sane = True
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500561 tmpdir = d.getVar('TMPDIR')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500562 workdir = os.path.join(tmpdir, "work")
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500563 recipesysroot = d.getVar("RECIPE_SYSROOT")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500564
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500565 if bb.data.inherits_class("native", d) or bb.data.inherits_class("cross", d):
566 pkgconfigcheck = workdir
567 else:
568 pkgconfigcheck = tmpdir
569
Brad Bishop19323692019-04-05 15:28:33 -0400570 skip = (d.getVar('INSANE_SKIP') or "").split()
571 skip_la = False
572 if 'la' in skip:
573 bb.note("Recipe %s skipping qa checking: la" % d.getVar('PN'))
574 skip_la = True
575
576 skip_pkgconfig = False
577 if 'pkgconfig' in skip:
578 bb.note("Recipe %s skipping qa checking: pkgconfig" % d.getVar('PN'))
579 skip_pkgconfig = True
580
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500581 # find all .la and .pc files
582 # read the content
583 # and check for stuff that looks wrong
584 for root, dirs, files in os.walk(path):
585 for file in files:
586 path = os.path.join(root,file)
Brad Bishop19323692019-04-05 15:28:33 -0400587 if file.endswith(".la") and not skip_la:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500588 with open(path) as f:
589 file_content = f.read()
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500590 file_content = file_content.replace(recipesysroot, "")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500591 if workdir in file_content:
592 error_msg = "%s failed sanity test (workdir) in path %s" % (file,root)
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800593 sane &= package_qa_handle_error("la", error_msg, d)
Brad Bishop19323692019-04-05 15:28:33 -0400594 elif file.endswith(".pc") and not skip_pkgconfig:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500595 with open(path) as f:
596 file_content = f.read()
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500597 file_content = file_content.replace(recipesysroot, "")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500598 if pkgconfigcheck in file_content:
599 error_msg = "%s failed sanity test (tmpdir) in path %s" % (file,root)
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800600 sane &= package_qa_handle_error("pkgconfig", error_msg, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500601
602 return sane
603
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500604# Run all package-wide warnfuncs and errorfuncs
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500605def package_qa_package(warnfuncs, errorfuncs, package, d):
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500606 warnings = {}
607 errors = {}
608
609 for func in warnfuncs:
610 func(package, d, warnings)
611 for func in errorfuncs:
612 func(package, d, errors)
613
614 for w in warnings:
615 package_qa_handle_error(w, warnings[w], d)
616 for e in errors:
617 package_qa_handle_error(e, errors[e], d)
618
619 return len(errors) == 0
620
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500621# Run all recipe-wide warnfuncs and errorfuncs
622def package_qa_recipe(warnfuncs, errorfuncs, pn, d):
623 warnings = {}
624 errors = {}
625
626 for func in warnfuncs:
627 func(pn, d, warnings)
628 for func in errorfuncs:
629 func(pn, d, errors)
630
631 for w in warnings:
632 package_qa_handle_error(w, warnings[w], d)
633 for e in errors:
634 package_qa_handle_error(e, errors[e], d)
635
636 return len(errors) == 0
637
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500638# Walk over all files in a directory and call func
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500639def package_qa_walk(warnfuncs, errorfuncs, package, d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500640 import oe.qa
641
642 #if this will throw an exception, then fix the dict above
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500643 target_os = d.getVar('TARGET_OS')
644 target_arch = d.getVar('TARGET_ARCH')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500645
646 warnings = {}
647 errors = {}
648 for path in pkgfiles[package]:
649 elf = oe.qa.ELFFile(path)
650 try:
651 elf.open()
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500652 except (IOError, oe.qa.NotELFFileError):
653 # IOError can happen if the packaging control files disappear,
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500654 elf = None
655 for func in warnfuncs:
656 func(path, package, d, elf, warnings)
657 for func in errorfuncs:
658 func(path, package, d, elf, errors)
659
660 for w in warnings:
661 package_qa_handle_error(w, warnings[w], d)
662 for e in errors:
663 package_qa_handle_error(e, errors[e], d)
664
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500665def package_qa_check_rdepends(pkg, pkgdest, skip, taskdeps, packages, d):
666 # Don't do this check for kernel/module recipes, there aren't too many debug/development
667 # packages and you can get false positives e.g. on kernel-module-lirc-dev
668 if bb.data.inherits_class("kernel", d) or bb.data.inherits_class("module-base", d):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500669 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500670
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500671 if not "-dbg" in pkg and not "packagegroup-" in pkg and not "-image" in pkg:
672 localdata = bb.data.createCopy(d)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500673 localdata.setVar('OVERRIDES', localdata.getVar('OVERRIDES') + ':' + pkg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500674
675 # Now check the RDEPENDS
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500676 rdepends = bb.utils.explode_deps(localdata.getVar('RDEPENDS') or "")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500677
678 # Now do the sanity check!!!
679 if "build-deps" not in skip:
680 for rdepend in rdepends:
681 if "-dbg" in rdepend and "debug-deps" not in skip:
682 error_msg = "%s rdepends on %s" % (pkg,rdepend)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500683 package_qa_handle_error("debug-deps", error_msg, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500684 if (not "-dev" in pkg and not "-staticdev" in pkg) and rdepend.endswith("-dev") and "dev-deps" not in skip:
685 error_msg = "%s rdepends on %s" % (pkg, rdepend)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500686 package_qa_handle_error("dev-deps", error_msg, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500687 if rdepend not in packages:
688 rdep_data = oe.packagedata.read_subpkgdata(rdepend, d)
689 if rdep_data and 'PN' in rdep_data and rdep_data['PN'] in taskdeps:
690 continue
691 if not rdep_data or not 'PN' in rdep_data:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500692 pkgdata_dir = d.getVar("PKGDATA_DIR")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500693 try:
694 possibles = os.listdir("%s/runtime-rprovides/%s/" % (pkgdata_dir, rdepend))
695 except OSError:
696 possibles = []
697 for p in possibles:
698 rdep_data = oe.packagedata.read_subpkgdata(p, d)
699 if rdep_data and 'PN' in rdep_data and rdep_data['PN'] in taskdeps:
700 break
701 if rdep_data and 'PN' in rdep_data and rdep_data['PN'] in taskdeps:
702 continue
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500703 if rdep_data and 'PN' in rdep_data:
704 error_msg = "%s rdepends on %s, but it isn't a build dependency, missing %s in DEPENDS or PACKAGECONFIG?" % (pkg, rdepend, rdep_data['PN'])
705 else:
706 error_msg = "%s rdepends on %s, but it isn't a build dependency?" % (pkg, rdepend)
707 package_qa_handle_error("build-deps", error_msg, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500708
709 if "file-rdeps" not in skip:
710 ignored_file_rdeps = set(['/bin/sh', '/usr/bin/env', 'rtld(GNU_HASH)'])
711 if bb.data.inherits_class('nativesdk', d):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500712 ignored_file_rdeps |= set(['/bin/bash', '/usr/bin/perl', 'perl'])
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500713 # For Saving the FILERDEPENDS
714 filerdepends = {}
715 rdep_data = oe.packagedata.read_subpkgdata(pkg, d)
716 for key in rdep_data:
717 if key.startswith("FILERDEPENDS_"):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500718 for subkey in bb.utils.explode_deps(rdep_data[key]):
719 if subkey not in ignored_file_rdeps and \
720 not subkey.startswith('perl('):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500721 # We already know it starts with FILERDEPENDS_
722 filerdepends[subkey] = key[13:]
723
724 if filerdepends:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500725 done = rdepends[:]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500726 # Add the rprovides of itself
727 if pkg not in done:
728 done.insert(0, pkg)
729
730 # The python is not a package, but python-core provides it, so
731 # skip checking /usr/bin/python if python is in the rdeps, in
732 # case there is a RDEPENDS_pkg = "python" in the recipe.
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500733 for py in [ d.getVar('MLPREFIX') + "python", "python" ]:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500734 if py in done:
735 filerdepends.pop("/usr/bin/python",None)
736 done.remove(py)
737 for rdep in done:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500738 # The file dependencies may contain package names, e.g.,
739 # perl
740 filerdepends.pop(rdep,None)
741
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500742 # For Saving the FILERPROVIDES, RPROVIDES and FILES_INFO
743 rdep_data = oe.packagedata.read_subpkgdata(rdep, d)
744 for key in rdep_data:
745 if key.startswith("FILERPROVIDES_") or key.startswith("RPROVIDES_"):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500746 for subkey in bb.utils.explode_deps(rdep_data[key]):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500747 filerdepends.pop(subkey,None)
748 # Add the files list to the rprovides
749 if key == "FILES_INFO":
750 # Use eval() to make it as a dict
751 for subkey in eval(rdep_data[key]):
752 filerdepends.pop(subkey,None)
753 if not filerdepends:
754 # Break if all the file rdepends are met
755 break
756 if filerdepends:
757 for key in filerdepends:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500758 error_msg = "%s contained in package %s requires %s, but no providers found in RDEPENDS_%s?" % \
759 (filerdepends[key].replace("_%s" % pkg, "").replace("@underscore@", "_"), pkg, key, pkg)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500760 package_qa_handle_error("file-rdeps", error_msg, d)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500761package_qa_check_rdepends[vardepsexclude] = "OVERRIDES"
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500762
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500763def package_qa_check_deps(pkg, pkgdest, d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500764
765 localdata = bb.data.createCopy(d)
766 localdata.setVar('OVERRIDES', pkg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500767
768 def check_valid_deps(var):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500769 try:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500770 rvar = bb.utils.explode_dep_versions2(localdata.getVar(var) or "")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500771 except ValueError as e:
772 bb.fatal("%s_%s: %s" % (var, pkg, e))
773 for dep in rvar:
774 for v in rvar[dep]:
775 if v and not v.startswith(('< ', '= ', '> ', '<= ', '>=')):
776 error_msg = "%s_%s is invalid: %s (%s) only comparisons <, =, >, <=, and >= are allowed" % (var, pkg, dep, v)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500777 package_qa_handle_error("dep-cmp", error_msg, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500778
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500779 check_valid_deps('RDEPENDS')
780 check_valid_deps('RRECOMMENDS')
781 check_valid_deps('RSUGGESTS')
782 check_valid_deps('RPROVIDES')
783 check_valid_deps('RREPLACES')
784 check_valid_deps('RCONFLICTS')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500785
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500786QAPKGTEST[usrmerge] = "package_qa_check_usrmerge"
787def package_qa_check_usrmerge(pkg, d, messages):
788 pkgdest = d.getVar('PKGDEST')
789 pkg_dir = pkgdest + os.sep + pkg + os.sep
790 merged_dirs = ['bin', 'sbin', 'lib'] + d.getVar('MULTILIB_VARIANTS').split()
791 for f in merged_dirs:
792 if os.path.exists(pkg_dir + f) and not os.path.islink(pkg_dir + f):
793 msg = "%s package is not obeying usrmerge distro feature. /%s should be relocated to /usr." % (pkg, f)
794 package_qa_add_message(messages, "usrmerge", msg)
795 return False
796 return True
797
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500798QAPKGTEST[expanded-d] = "package_qa_check_expanded_d"
799def package_qa_check_expanded_d(package, d, messages):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500800 """
801 Check for the expanded D (${D}) value in pkg_* and FILES
802 variables, warn the user to use it correctly.
803 """
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500804 sane = True
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500805 expanded_d = d.getVar('D')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500806
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500807 for var in 'FILES','pkg_preinst', 'pkg_postinst', 'pkg_prerm', 'pkg_postrm':
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500808 bbvar = d.getVar(var + "_" + package) or ""
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500809 if expanded_d in bbvar:
810 if var == 'FILES':
811 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)
812 sane = False
813 else:
814 package_qa_add_message(messages, "expanded-d", "%s in %s recipe contains ${D}, it should be replaced by $D instead" % (var, package))
815 sane = False
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500816 return sane
817
818def package_qa_check_encoding(keys, encode, d):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600819 def check_encoding(key, enc):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500820 sane = True
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500821 value = d.getVar(key)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500822 if value:
823 try:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600824 s = value.encode(enc)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500825 except UnicodeDecodeError as e:
826 error_msg = "%s has non %s characters" % (key,enc)
827 sane = False
828 package_qa_handle_error("invalid-chars", error_msg, d)
829 return sane
830
831 for key in keys:
832 sane = check_encoding(key, encode)
833 if not sane:
834 break
835
836HOST_USER_UID := "${@os.getuid()}"
837HOST_USER_GID := "${@os.getgid()}"
838
839QAPATHTEST[host-user-contaminated] = "package_qa_check_host_user"
840def package_qa_check_host_user(path, name, d, elf, messages):
841 """Check for paths outside of /home which are owned by the user running bitbake."""
842
843 if not os.path.lexists(path):
844 return
845
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500846 dest = d.getVar('PKGDEST')
847 pn = d.getVar('PN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500848 home = os.path.join(dest, 'home')
849 if path == home or path.startswith(home + os.sep):
850 return
851
852 try:
853 stat = os.lstat(path)
854 except OSError as exc:
855 import errno
856 if exc.errno != errno.ENOENT:
857 raise
858 else:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500859 check_uid = int(d.getVar('HOST_USER_UID'))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500860 if stat.st_uid == check_uid:
Brad Bishop96ff1982019-08-19 13:50:42 -0400861 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, package_qa_clean_path(path, d, name), check_uid))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500862 return False
863
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500864 check_gid = int(d.getVar('HOST_USER_GID'))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500865 if stat.st_gid == check_gid:
Brad Bishop96ff1982019-08-19 13:50:42 -0400866 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, package_qa_clean_path(path, d, name), check_gid))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500867 return False
868 return True
869
Brad Bishop15ae2502019-06-18 21:44:24 -0400870QARECIPETEST[src-uri-bad] = "package_qa_check_src_uri"
871def package_qa_check_src_uri(pn, d, messages):
872 import re
873
874 if "${PN}" in d.getVar("SRC_URI", False):
875 package_qa_handle_error("src-uri-bad", "%s: SRC_URI uses PN not BPN" % pn, d)
876
877 pn = d.getVar("SRC_URI")
878 if re.search(r"github\.com/.+/.+/archive/.+", pn):
879 package_qa_handle_error("src-uri-bad", "%s: SRC_URI uses unstable GitHub archives" % pn, d)
880
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500881
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500882# The PACKAGE FUNC to scan each package
883python do_package_qa () {
884 import subprocess
885 import oe.packagedata
886
887 bb.note("DO PACKAGE QA")
888
889 bb.build.exec_func("read_subpackage_metadata", d)
890
891 # Check non UTF-8 characters on recipe's metadata
892 package_qa_check_encoding(['DESCRIPTION', 'SUMMARY', 'LICENSE', 'SECTION'], 'utf-8', d)
893
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500894 logdir = d.getVar('T')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500895 pn = d.getVar('PN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500896
897 # Check the compile log for host contamination
898 compilelog = os.path.join(logdir,"log.do_compile")
899
900 if os.path.exists(compilelog):
901 statement = "grep -e 'CROSS COMPILE Badness:' -e 'is unsafe for cross-compilation' %s > /dev/null" % compilelog
902 if subprocess.call(statement, shell=True) == 0:
903 msg = "%s: The compile log indicates that host include and/or library paths were used.\n \
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500904 Please check the log '%s' for more information." % (pn, compilelog)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500905 package_qa_handle_error("compile-host-path", msg, d)
906
907 # Check the install log for host contamination
908 installlog = os.path.join(logdir,"log.do_install")
909
910 if os.path.exists(installlog):
911 statement = "grep -e 'CROSS COMPILE Badness:' -e 'is unsafe for cross-compilation' %s > /dev/null" % installlog
912 if subprocess.call(statement, shell=True) == 0:
913 msg = "%s: The install log indicates that host include and/or library paths were used.\n \
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500914 Please check the log '%s' for more information." % (pn, installlog)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500915 package_qa_handle_error("install-host-path", msg, d)
916
917 # Scan the packages...
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500918 pkgdest = d.getVar('PKGDEST')
919 packages = set((d.getVar('PACKAGES') or '').split())
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500920
921 cpath = oe.cachedpath.CachedPath()
922 global pkgfiles
923 pkgfiles = {}
924 for pkg in packages:
925 pkgfiles[pkg] = []
926 for walkroot, dirs, files in cpath.walk(pkgdest + "/" + pkg):
927 for file in files:
928 pkgfiles[pkg].append(walkroot + os.sep + file)
929
930 # no packages should be scanned
931 if not packages:
932 return
933
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500934 import re
935 # The package name matches the [a-z0-9.+-]+ regular expression
Brad Bishop977dc1a2019-02-06 16:01:43 -0500936 pkgname_pattern = re.compile(r"^[a-z0-9.+-]+$")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500937
938 taskdepdata = d.getVar("BB_TASKDEPDATA", False)
939 taskdeps = set()
940 for dep in taskdepdata:
941 taskdeps.add(taskdepdata[dep][0])
942
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500943 def parse_test_matrix(matrix_name):
944 testmatrix = d.getVarFlags(matrix_name) or {}
945 g = globals()
946 warnchecks = []
947 for w in (d.getVar("WARN_QA") or "").split():
948 if w in skip:
949 continue
950 if w in testmatrix and testmatrix[w] in g:
951 warnchecks.append(g[testmatrix[w]])
952
953 errorchecks = []
954 for e in (d.getVar("ERROR_QA") or "").split():
955 if e in skip:
956 continue
957 if e in testmatrix and testmatrix[e] in g:
958 errorchecks.append(g[testmatrix[e]])
959 return warnchecks, errorchecks
960
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500961 for package in packages:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500962 skip = set((d.getVar('INSANE_SKIP') or "").split() +
963 (d.getVar('INSANE_SKIP_' + package) or "").split())
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500964 if skip:
965 bb.note("Package %s skipping QA tests: %s" % (package, str(skip)))
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500966
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500967 bb.note("Checking Package: %s" % package)
968 # Check package name
969 if not pkgname_pattern.match(package):
970 package_qa_handle_error("pkgname",
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500971 "%s doesn't match the [a-z0-9.+-]+ regex" % package, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500972
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500973 warn_checks, error_checks = parse_test_matrix("QAPATHTEST")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500974 package_qa_walk(warn_checks, error_checks, package, d)
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500975
976 warn_checks, error_checks = parse_test_matrix("QAPKGTEST")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500977 package_qa_package(warn_checks, error_checks, package, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500978
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500979 package_qa_check_rdepends(package, pkgdest, skip, taskdeps, packages, d)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500980 package_qa_check_deps(package, pkgdest, d)
981
982 warn_checks, error_checks = parse_test_matrix("QARECIPETEST")
983 package_qa_recipe(warn_checks, error_checks, pn, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500984
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500985 if 'libdir' in d.getVar("ALL_QA").split():
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500986 package_qa_check_libdir(d)
987
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500988 qa_sane = d.getVar("QA_SANE")
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500989 if not qa_sane:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500990 bb.fatal("QA run found fatal errors. Please consider fixing them.")
991 bb.note("DONE with PACKAGE QA")
992}
993
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500994# binutils is used for most checks, so need to set as dependency
995# POPULATESYSROOTDEPS is defined in staging class.
996do_package_qa[depends] += "${POPULATESYSROOTDEPS}"
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500997do_package_qa[vardepsexclude] = "BB_TASKDEPDATA"
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500998do_package_qa[rdeptask] = "do_packagedata"
999addtask do_package_qa after do_packagedata do_package before do_build
1000
Brad Bishop19323692019-04-05 15:28:33 -04001001# Add the package specific INSANE_SKIPs to the sstate dependencies
1002python() {
1003 pkgs = (d.getVar('PACKAGES') or '').split()
1004 for pkg in pkgs:
1005 d.appendVarFlag("do_package_qa", "vardeps", " INSANE_SKIP_{}".format(pkg))
1006}
1007
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001008SSTATETASKS += "do_package_qa"
1009do_package_qa[sstate-inputdirs] = ""
1010do_package_qa[sstate-outputdirs] = ""
1011python do_package_qa_setscene () {
1012 sstate_setscene(d)
1013}
1014addtask do_package_qa_setscene
1015
1016python do_qa_staging() {
1017 bb.note("QA checking staging")
Brad Bishop19323692019-04-05 15:28:33 -04001018 if not qa_check_staged(d.expand('${SYSROOT_DESTDIR}${libdir}'), d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001019 bb.fatal("QA staging was broken by the package built above")
1020}
1021
Brad Bishopd89cb5f2019-04-10 09:02:41 -04001022python do_qa_patch() {
1023 import subprocess
1024
1025 ###########################################################################
1026 # Check patch.log for fuzz warnings
1027 #
1028 # Further information on why we check for patch fuzz warnings:
1029 # http://lists.openembedded.org/pipermail/openembedded-core/2018-March/148675.html
1030 # https://bugzilla.yoctoproject.org/show_bug.cgi?id=10450
1031 ###########################################################################
1032
1033 logdir = d.getVar('T')
1034 patchlog = os.path.join(logdir,"log.do_patch")
1035
1036 if os.path.exists(patchlog):
1037 fuzzheader = '--- Patch fuzz start ---'
1038 fuzzfooter = '--- Patch fuzz end ---'
1039 statement = "grep -e '%s' %s > /dev/null" % (fuzzheader, patchlog)
1040 if subprocess.call(statement, shell=True) == 0:
1041 msg = "Fuzz detected:\n\n"
1042 fuzzmsg = ""
1043 inFuzzInfo = False
1044 f = open(patchlog, "r")
1045 for line in f:
1046 if fuzzheader in line:
1047 inFuzzInfo = True
1048 fuzzmsg = ""
1049 elif fuzzfooter in line:
1050 fuzzmsg = fuzzmsg.replace('\n\n', '\n')
1051 msg += fuzzmsg
1052 msg += "\n"
1053 inFuzzInfo = False
1054 elif inFuzzInfo and not 'Now at patch' in line:
1055 fuzzmsg += line
1056 f.close()
1057 msg += "The context lines in the patches can be updated with devtool:\n"
1058 msg += "\n"
1059 msg += " devtool modify %s\n" % d.getVar('PN')
1060 msg += " devtool finish --force-patch-refresh %s <layer_path>\n\n" % d.getVar('PN')
1061 msg += "Don't forget to review changes done by devtool!\n"
1062 if 'patch-fuzz' in d.getVar('ERROR_QA'):
1063 bb.error(msg)
1064 elif 'patch-fuzz' in d.getVar('WARN_QA'):
1065 bb.warn(msg)
1066 msg = "Patch log indicates that patches do not apply cleanly."
1067 package_qa_handle_error("patch-fuzz", msg, d)
1068}
1069
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001070python do_qa_configure() {
1071 import subprocess
1072
1073 ###########################################################################
1074 # Check config.log for cross compile issues
1075 ###########################################################################
1076
1077 configs = []
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001078 workdir = d.getVar('WORKDIR')
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001079
Brad Bishop19323692019-04-05 15:28:33 -04001080 skip = (d.getVar('INSANE_SKIP') or "").split()
1081 skip_configure_unsafe = False
1082 if 'configure-unsafe' in skip:
1083 bb.note("Recipe %s skipping qa checking: configure-unsafe" % d.getVar('PN'))
1084 skip_configure_unsafe = True
1085
1086 if bb.data.inherits_class('autotools', d) and not skip_configure_unsafe:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001087 bb.note("Checking autotools environment for common misconfiguration")
1088 for root, dirs, files in os.walk(workdir):
1089 statement = "grep -q -F -e 'CROSS COMPILE Badness:' -e 'is unsafe for cross-compilation' %s" % \
1090 os.path.join(root,"config.log")
1091 if "config.log" in files:
1092 if subprocess.call(statement, shell=True) == 0:
Brad Bishop19323692019-04-05 15:28:33 -04001093 error_msg = """This autoconf log indicates errors, it looked at host include and/or library paths while determining system capabilities.
1094Rerun configure task after fixing this."""
1095 package_qa_handle_error("configure-unsafe", error_msg, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001096
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001097 if "configure.ac" in files:
1098 configs.append(os.path.join(root,"configure.ac"))
1099 if "configure.in" in files:
1100 configs.append(os.path.join(root, "configure.in"))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001101
1102 ###########################################################################
1103 # Check gettext configuration and dependencies are correct
1104 ###########################################################################
1105
Brad Bishop19323692019-04-05 15:28:33 -04001106 skip_configure_gettext = False
1107 if 'configure-gettext' in skip:
1108 bb.note("Recipe %s skipping qa checking: configure-gettext" % d.getVar('PN'))
1109 skip_configure_gettext = True
1110
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001111 cnf = d.getVar('EXTRA_OECONF') or ""
Brad Bishop19323692019-04-05 15:28:33 -04001112 if not ("gettext" in d.getVar('P') or "gcc-runtime" in d.getVar('P') or \
1113 "--disable-nls" in cnf or skip_configure_gettext):
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001114 ml = d.getVar("MLPREFIX") or ""
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001115 if bb.data.inherits_class('cross-canadian', d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001116 gt = "nativesdk-gettext"
1117 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001118 gt = "gettext-native"
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001119 deps = bb.utils.explode_deps(d.getVar('DEPENDS') or "")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001120 if gt not in deps:
1121 for config in configs:
1122 gnu = "grep \"^[[:space:]]*AM_GNU_GETTEXT\" %s >/dev/null" % config
1123 if subprocess.call(gnu, shell=True) == 0:
Brad Bishopd89cb5f2019-04-10 09:02:41 -04001124 error_msg = "AM_GNU_GETTEXT used but no inherit gettext"
Brad Bishop19323692019-04-05 15:28:33 -04001125 package_qa_handle_error("configure-gettext", error_msg, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001126
1127 ###########################################################################
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001128 # Check unrecognised configure options (with a white list)
1129 ###########################################################################
Brad Bishopc342db32019-05-15 21:57:59 -04001130 if bb.data.inherits_class("autotools", d) or bb.data.inherits_class("meson", d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001131 bb.note("Checking configure output for unrecognised options")
1132 try:
Brad Bishopc342db32019-05-15 21:57:59 -04001133 if bb.data.inherits_class("autotools", d):
1134 flag = "WARNING: unrecognized options:"
1135 log = os.path.join(d.getVar('B'), 'config.log')
1136 if bb.data.inherits_class("meson", d):
1137 flag = "WARNING: Unknown options:"
1138 log = os.path.join(d.getVar('T'), 'log.do_configure')
1139 output = subprocess.check_output(['grep', '-F', flag, log]).decode("utf-8").replace(', ', ' ').replace('"', '')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001140 options = set()
1141 for line in output.splitlines():
1142 options |= set(line.partition(flag)[2].split())
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001143 whitelist = set(d.getVar("UNKNOWN_CONFIGURE_WHITELIST").split())
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001144 options -= whitelist
1145 if options:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001146 pn = d.getVar('PN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001147 error_msg = pn + ": configure was passed unrecognised options: " + " ".join(options)
1148 package_qa_handle_error("unknown-configure-option", error_msg, d)
1149 except subprocess.CalledProcessError:
1150 pass
1151
1152 # Check invalid PACKAGECONFIG
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001153 pkgconfig = (d.getVar("PACKAGECONFIG") or "").split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001154 if pkgconfig:
1155 pkgconfigflags = d.getVarFlags("PACKAGECONFIG") or {}
1156 for pconfig in pkgconfig:
1157 if pconfig not in pkgconfigflags:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001158 pn = d.getVar('PN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001159 error_msg = "%s: invalid PACKAGECONFIG: %s" % (pn, pconfig)
Patrick Williamsf1e5d692016-03-30 15:21:19 -05001160 package_qa_handle_error("invalid-packageconfig", error_msg, d)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001161
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001162 qa_sane = d.getVar("QA_SANE")
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001163 if not qa_sane:
1164 bb.fatal("Fatal QA errors found, failing task.")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001165}
1166
1167python do_qa_unpack() {
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001168 src_uri = d.getVar('SRC_URI')
1169 s_dir = d.getVar('S')
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001170 if src_uri and not os.path.exists(s_dir):
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001171 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 -05001172}
1173
1174# The Staging Func, to check all staging
1175#addtask qa_staging after do_populate_sysroot before do_build
1176do_populate_sysroot[postfuncs] += "do_qa_staging "
1177
Brad Bishopd89cb5f2019-04-10 09:02:41 -04001178# Check for patch fuzz
1179do_patch[postfuncs] += "do_qa_patch "
1180
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001181# Check broken config.log files, for packages requiring Gettext which
1182# don't have it in DEPENDS.
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001183#addtask qa_configure after do_configure before do_compile
1184do_configure[postfuncs] += "do_qa_configure "
1185
1186# Check does S exist.
1187do_unpack[postfuncs] += "do_qa_unpack"
1188
1189python () {
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001190 import re
1191
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001192 tests = d.getVar('ALL_QA').split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001193 if "desktop" in tests:
1194 d.appendVar("PACKAGE_DEPENDS", " desktop-file-utils-native")
1195
1196 ###########################################################################
1197 # Check various variables
1198 ###########################################################################
1199
1200 # Checking ${FILESEXTRAPATHS}
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001201 extrapaths = (d.getVar("FILESEXTRAPATHS") or "")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001202 if '__default' not in extrapaths.split(":"):
1203 msg = "FILESEXTRAPATHS-variable, must always use _prepend (or _append)\n"
1204 msg += "type of assignment, and don't forget the colon.\n"
1205 msg += "Please assign it with the format of:\n"
1206 msg += " FILESEXTRAPATHS_append := \":${THISDIR}/Your_Files_Path\" or\n"
1207 msg += " FILESEXTRAPATHS_prepend := \"${THISDIR}/Your_Files_Path:\"\n"
1208 msg += "in your bbappend file\n\n"
1209 msg += "Your incorrect assignment is:\n"
1210 msg += "%s\n" % extrapaths
1211 bb.warn(msg)
1212
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001213 overrides = d.getVar('OVERRIDES').split(':')
1214 pn = d.getVar('PN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001215 if pn in overrides:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001216 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 -05001217 package_qa_handle_error("pn-overrides", msg, d)
Brad Bishop977dc1a2019-02-06 16:01:43 -05001218 prog = re.compile(r'[A-Z]')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001219 if prog.search(pn):
1220 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 -05001221
Brad Bishop08902b02019-08-20 09:16:51 -04001222 # Some people mistakenly use DEPENDS_${PN} instead of DEPENDS and wonder
1223 # why it doesn't work.
1224 if (d.getVar(d.expand('DEPENDS_${PN}'))):
1225 package_qa_handle_error("pkgvarcheck", "recipe uses DEPENDS_${PN}, should use DEPENDS", d)
1226
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001227 issues = []
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001228 if (d.getVar('PACKAGES') or "").split():
1229 for dep in (d.getVar('QADEPENDS') or "").split():
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001230 d.appendVarFlag('do_package_qa', 'depends', " %s:do_populate_sysroot" % dep)
1231 for var in 'RDEPENDS', 'RRECOMMENDS', 'RSUGGESTS', 'RCONFLICTS', 'RPROVIDES', 'RREPLACES', 'FILES', 'pkg_preinst', 'pkg_postinst', 'pkg_prerm', 'pkg_postrm', 'ALLOW_EMPTY':
1232 if d.getVar(var, False):
1233 issues.append(var)
1234
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001235 fakeroot_tests = d.getVar('FAKEROOT_QA').split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001236 if set(tests) & set(fakeroot_tests):
1237 d.setVarFlag('do_package_qa', 'fakeroot', '1')
1238 d.appendVarFlag('do_package_qa', 'depends', ' virtual/fakeroot-native:do_populate_sysroot')
1239 else:
1240 d.setVarFlag('do_package_qa', 'rdeptask', '')
1241 for i in issues:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001242 package_qa_handle_error("pkgvarcheck", "%s: Variable %s is set as not being package specific, please fix this." % (d.getVar("FILE"), i), d)
1243 qa_sane = d.getVar("QA_SANE")
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001244 if not qa_sane:
1245 bb.fatal("Fatal QA errors found, failing task.")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001246}