blob: eb2d96711e18545a97758b735e2f326b46e1ddb0 [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),
Brad Bishop316dfdd2018-06-25 12:45:53 -040071 "microblaze": (189, 0, 0, False, 32),
72 "microblazeeb":(189, 0, 0, False, 32),
73 "microblazeel":(189, 0, 0, True, 32),
74 "riscv32": (243, 0, 0, True, 32),
75 "riscv64": (243, 0, 0, True, 64),
Patrick Williamsc124f4f2015-09-15 14:41:29 -050076 },
77 "linux" : {
78 "aarch64" : (183, 0, 0, True, 64),
79 "aarch64_be" :(183, 0, 0, False, 64),
80 "arm" : (40, 97, 0, True, 32),
81 "armeb": (40, 97, 0, False, 32),
82 "powerpc": (20, 0, 0, False, 32),
83 "powerpc64": (21, 0, 0, False, 64),
84 "i386": ( 3, 0, 0, True, 32),
85 "i486": ( 3, 0, 0, True, 32),
86 "i586": ( 3, 0, 0, True, 32),
87 "i686": ( 3, 0, 0, True, 32),
88 "x86_64": (62, 0, 0, True, 64),
89 "ia64": (50, 0, 0, True, 64),
90 "alpha": (36902, 0, 0, True, 64),
91 "hppa": (15, 3, 0, False, 32),
92 "m68k": ( 4, 0, 0, False, 32),
93 "mips": ( 8, 0, 0, False, 32),
94 "mipsel": ( 8, 0, 0, True, 32),
95 "mips64": ( 8, 0, 0, False, 64),
96 "mips64el": ( 8, 0, 0, True, 64),
Patrick Williamsc0f7c042017-02-23 20:41:17 -060097 "mipsisa32r6": ( 8, 0, 0, False, 32),
98 "mipsisa32r6el": ( 8, 0, 0, True, 32),
99 "mipsisa64r6": ( 8, 0, 0, False, 64),
100 "mipsisa64r6el": ( 8, 0, 0, True, 64),
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500101 "nios2": (113, 0, 0, True, 32),
Brad Bishop316dfdd2018-06-25 12:45:53 -0400102 "riscv32": (243, 0, 0, True, 32),
103 "riscv64": (243, 0, 0, True, 64),
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500104 "s390": (22, 0, 0, False, 32),
105 "sh4": (42, 0, 0, True, 32),
106 "sparc": ( 2, 0, 0, False, 32),
107 "microblaze": (189, 0, 0, False, 32),
108 "microblazeeb":(189, 0, 0, False, 32),
109 "microblazeel":(189, 0, 0, True, 32),
110 },
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500111 "linux-musl" : {
112 "aarch64" : (183, 0, 0, True, 64),
113 "aarch64_be" :(183, 0, 0, False, 64),
114 "arm" : ( 40, 97, 0, True, 32),
115 "armeb": ( 40, 97, 0, False, 32),
116 "powerpc": ( 20, 0, 0, False, 32),
117 "i386": ( 3, 0, 0, True, 32),
118 "i486": ( 3, 0, 0, True, 32),
119 "i586": ( 3, 0, 0, True, 32),
120 "i686": ( 3, 0, 0, True, 32),
121 "x86_64": ( 62, 0, 0, True, 64),
122 "mips": ( 8, 0, 0, False, 32),
123 "mipsel": ( 8, 0, 0, True, 32),
124 "mips64": ( 8, 0, 0, False, 64),
125 "mips64el": ( 8, 0, 0, True, 64),
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500126 "microblaze": (189, 0, 0, False, 32),
127 "microblazeeb":(189, 0, 0, False, 32),
128 "microblazeel":(189, 0, 0, True, 32),
Brad Bishop316dfdd2018-06-25 12:45:53 -0400129 "riscv32": (243, 0, 0, True, 32),
130 "riscv64": (243, 0, 0, True, 64),
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500131 "sh4": ( 42, 0, 0, True, 32),
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500132 },
133 "uclinux-uclibc" : {
134 "bfin": ( 106, 0, 0, True, 32),
135 },
136 "linux-gnueabi" : {
137 "arm" : (40, 0, 0, True, 32),
138 "armeb" : (40, 0, 0, False, 32),
139 },
140 "linux-musleabi" : {
141 "arm" : (40, 0, 0, True, 32),
142 "armeb" : (40, 0, 0, False, 32),
143 },
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500144 "linux-gnuspe" : {
145 "powerpc": (20, 0, 0, False, 32),
146 },
147 "linux-muslspe" : {
148 "powerpc": (20, 0, 0, False, 32),
149 },
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500150 "linux-gnu" : {
151 "powerpc": (20, 0, 0, False, 32),
152 "sh4": (42, 0, 0, True, 32),
153 },
Brad Bishop316dfdd2018-06-25 12:45:53 -0400154 "linux-gnu_ilp32" : {
155 "aarch64" : (183, 0, 0, True, 32),
156 },
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500157 "linux-gnux32" : {
158 "x86_64": (62, 0, 0, True, 32),
159 },
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500160 "linux-muslx32" : {
161 "x86_64": (62, 0, 0, True, 32),
162 },
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500163 "linux-gnun32" : {
164 "mips64": ( 8, 0, 0, False, 32),
165 "mips64el": ( 8, 0, 0, True, 32),
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500166 "mipsisa64r6": ( 8, 0, 0, False, 32),
167 "mipsisa64r6el":( 8, 0, 0, True, 32),
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500168 },
169 }
170
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600171 # Add in any extra user supplied data which may come from a BSP layer, removing the
172 # need to always change this class directly
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500173 extra_machdata = (d.getVar("PACKAGEQA_EXTRA_MACHDEFFUNCS") or "").split()
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600174 for m in extra_machdata:
175 call = m + "(machdata, d)"
176 locs = { "machdata" : machdata, "d" : d}
177 machdata = bb.utils.better_eval(call, locs)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500178
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600179 return machdata
180
181
182def package_qa_clean_path(path, d, pkg=None):
183 """
184 Remove redundant paths from the path for display. If pkg isn't set then
185 TMPDIR is stripped, otherwise PKGDEST/pkg is stripped.
186 """
187 if pkg:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500188 path = path.replace(os.path.join(d.getVar("PKGDEST"), pkg), "/")
189 return path.replace(d.getVar("TMPDIR"), "/").replace("//", "/")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500190
191def package_qa_write_error(type, error, d):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500192 logfile = d.getVar('QA_LOGFILE')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500193 if logfile:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500194 p = d.getVar('P')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600195 with open(logfile, "a+") as f:
196 f.write("%s: %s [%s]\n" % (p, error, type))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500197
198def package_qa_handle_error(error_class, error_msg, d):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500199 if error_class in (d.getVar("ERROR_QA") or "").split():
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500200 package_qa_write_error(error_class, error_msg, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500201 bb.error("QA Issue: %s [%s]" % (error_msg, error_class))
202 d.setVar("QA_SANE", False)
203 return False
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500204 elif error_class in (d.getVar("WARN_QA") or "").split():
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500205 package_qa_write_error(error_class, error_msg, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500206 bb.warn("QA Issue: %s [%s]" % (error_msg, error_class))
207 else:
208 bb.note("QA Issue: %s [%s]" % (error_msg, error_class))
209 return True
210
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500211def package_qa_add_message(messages, section, new_msg):
212 if section not in messages:
213 messages[section] = new_msg
214 else:
215 messages[section] = messages[section] + "\n" + new_msg
216
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500217QAPATHTEST[libexec] = "package_qa_check_libexec"
218def package_qa_check_libexec(path,name, d, elf, messages):
219
220 # Skip the case where the default is explicitly /usr/libexec
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500221 libexec = d.getVar('libexecdir')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500222 if libexec == "/usr/libexec":
223 return True
224
225 if 'libexec' in path.split(os.path.sep):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500226 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 -0500227 return False
228
229 return True
230
231QAPATHTEST[rpaths] = "package_qa_check_rpath"
232def package_qa_check_rpath(file,name, d, elf, messages):
233 """
234 Check for dangerous RPATHs
235 """
236 if not elf:
237 return
238
239 if os.path.islink(file):
240 return
241
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500242 bad_dirs = [d.getVar('BASE_WORKDIR'), d.getVar('STAGING_DIR_TARGET')]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500243
244 phdrs = elf.run_objdump("-p", d)
245
246 import re
247 rpath_re = re.compile("\s+RPATH\s+(.*)")
248 for line in phdrs.split("\n"):
249 m = rpath_re.match(line)
250 if m:
251 rpath = m.group(1)
252 for dir in bad_dirs:
253 if dir in rpath:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500254 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 -0500255
256QAPATHTEST[useless-rpaths] = "package_qa_check_useless_rpaths"
257def package_qa_check_useless_rpaths(file, name, d, elf, messages):
258 """
259 Check for RPATHs that are useless but not dangerous
260 """
261 def rpath_eq(a, b):
262 return os.path.normpath(a) == os.path.normpath(b)
263
264 if not elf:
265 return
266
267 if os.path.islink(file):
268 return
269
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500270 libdir = d.getVar("libdir")
271 base_libdir = d.getVar("base_libdir")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500272
273 phdrs = elf.run_objdump("-p", d)
274
275 import re
276 rpath_re = re.compile("\s+RPATH\s+(.*)")
277 for line in phdrs.split("\n"):
278 m = rpath_re.match(line)
279 if m:
280 rpath = m.group(1)
281 if rpath_eq(rpath, libdir) or rpath_eq(rpath, base_libdir):
282 # The dynamic linker searches both these places anyway. There is no point in
283 # looking there again.
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500284 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 -0500285
286QAPATHTEST[dev-so] = "package_qa_check_dev"
287def package_qa_check_dev(path, name, d, elf, messages):
288 """
289 Check for ".so" library symlinks in non-dev packages
290 """
291
292 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 -0500293 package_qa_add_message(messages, "dev-so", "non -dev/-dbg/nativesdk- package contains symlink .so: %s path '%s'" % \
294 (name, package_qa_clean_path(path,d)))
295
296QAPATHTEST[dev-elf] = "package_qa_check_dev_elf"
297def package_qa_check_dev_elf(path, name, d, elf, messages):
298 """
299 Check that -dev doesn't contain real shared libraries. The test has to
300 check that the file is not a link and is an ELF object as some recipes
301 install link-time .so files that are linker scripts.
302 """
303 if name.endswith("-dev") and path.endswith(".so") and not os.path.islink(path) and elf:
304 package_qa_add_message(messages, "dev-elf", "-dev package contains non-symlink .so: %s path '%s'" % \
305 (name, package_qa_clean_path(path,d)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500306
307QAPATHTEST[staticdev] = "package_qa_check_staticdev"
308def package_qa_check_staticdev(path, name, d, elf, messages):
309 """
310 Check for ".a" library in non-staticdev packages
311 There are a number of exceptions to this rule, -pic packages can contain
312 static libraries, the _nonshared.a belong with their -dev packages and
313 libgcc.a, libgcov.a will be skipped in their packages
314 """
315
316 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 -0500317 package_qa_add_message(messages, "staticdev", "non -staticdev package contains static .a library: %s path '%s'" % \
318 (name, package_qa_clean_path(path,d)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500319
320def package_qa_check_libdir(d):
321 """
322 Check for wrong library installation paths. For instance, catch
323 recipes installing /lib/bar.so when ${base_libdir}="lib32" or
324 installing in /usr/lib64 when ${libdir}="/usr/lib"
325 """
326 import re
327
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500328 pkgdest = d.getVar('PKGDEST')
329 base_libdir = d.getVar("base_libdir") + os.sep
330 libdir = d.getVar("libdir") + os.sep
331 libexecdir = d.getVar("libexecdir") + os.sep
332 exec_prefix = d.getVar("exec_prefix") + os.sep
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500333
334 messages = []
335
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500336 # The re's are purposely fuzzy, as some there are some .so.x.y.z files
337 # that don't follow the standard naming convention. It checks later
338 # that they are actual ELF files
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500339 lib_re = re.compile("^/lib.+\.so(\..+)?$")
340 exec_re = re.compile("^%s.*/lib.+\.so(\..+)?$" % exec_prefix)
341
342 for root, dirs, files in os.walk(pkgdest):
343 if root == pkgdest:
344 # Skip subdirectories for any packages with libdir in INSANE_SKIP
345 skippackages = []
346 for package in dirs:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500347 if 'libdir' in (d.getVar('INSANE_SKIP_' + package) or "").split():
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500348 bb.note("Package %s skipping libdir QA test" % (package))
349 skippackages.append(package)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500350 elif d.getVar('PACKAGE_DEBUG_SPLIT_STYLE') == 'debug-file-directory' and package.endswith("-dbg"):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500351 bb.note("Package %s skipping libdir QA test for PACKAGE_DEBUG_SPLIT_STYLE equals debug-file-directory" % (package))
352 skippackages.append(package)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500353 for package in skippackages:
354 dirs.remove(package)
355 for file in files:
356 full_path = os.path.join(root, file)
357 rel_path = os.path.relpath(full_path, pkgdest)
358 if os.sep in rel_path:
359 package, rel_path = rel_path.split(os.sep, 1)
360 rel_path = os.sep + rel_path
361 if lib_re.match(rel_path):
362 if base_libdir not in rel_path:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500363 # make sure it's an actual ELF file
364 elf = oe.qa.ELFFile(full_path)
365 try:
366 elf.open()
367 messages.append("%s: found library in wrong location: %s" % (package, rel_path))
368 except (oe.qa.NotELFFileError):
369 pass
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500370 if exec_re.match(rel_path):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500371 if libdir not in rel_path and libexecdir not in rel_path:
372 # make sure it's an actual ELF file
373 elf = oe.qa.ELFFile(full_path)
374 try:
375 elf.open()
376 messages.append("%s: found library in wrong location: %s" % (package, rel_path))
377 except (oe.qa.NotELFFileError):
378 pass
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500379
380 if messages:
381 package_qa_handle_error("libdir", "\n".join(messages), d)
382
383QAPATHTEST[debug-files] = "package_qa_check_dbg"
384def package_qa_check_dbg(path, name, d, elf, messages):
385 """
386 Check for ".debug" files or directories outside of the dbg package
387 """
388
389 if not "-dbg" in name and not "-ptest" in name:
390 if '.debug' in path.split(os.path.sep):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500391 package_qa_add_message(messages, "debug-files", "non debug package contains .debug directory: %s path %s" % \
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500392 (name, package_qa_clean_path(path,d)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500393
394QAPATHTEST[perms] = "package_qa_check_perm"
395def package_qa_check_perm(path,name,d, elf, messages):
396 """
397 Check the permission of files
398 """
399 return
400
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500401QAPATHTEST[arch] = "package_qa_check_arch"
402def package_qa_check_arch(path,name,d, elf, messages):
403 """
404 Check if archs are compatible
405 """
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600406 import re
407
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500408 if not elf:
409 return
410
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500411 target_os = d.getVar('TARGET_OS')
412 target_arch = d.getVar('TARGET_ARCH')
413 provides = d.getVar('PROVIDES')
414 bpn = d.getVar('BPN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500415
416 if target_arch == "allarch":
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500417 pn = d.getVar('PN')
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500418 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 -0500419 return
420
421 # FIXME: Cross package confuse this check, so just skip them
422 for s in ['cross', 'nativesdk', 'cross-canadian']:
423 if bb.data.inherits_class(s, d):
424 return
425
426 # avoid following links to /usr/bin (e.g. on udev builds)
427 # we will check the files pointed to anyway...
428 if os.path.islink(path):
429 return
430
431 #if this will throw an exception, then fix the dict above
432 (machine, osabi, abiversion, littleendian, bits) \
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600433 = package_qa_get_machine_dict(d)[target_os][target_arch]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500434
435 # Check the architecture and endiannes of the binary
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600436 is_32 = (("virtual/kernel" in provides) or bb.data.inherits_class("module", d)) and \
Brad Bishop316dfdd2018-06-25 12:45:53 -0400437 (target_os == "linux-gnux32" or target_os == "linux-muslx32" or target_os == "linux-gnu_ilp32" or re.match('mips64.*32', d.getVar('DEFAULTTUNE')))
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600438 if not ((machine == elf.machine()) or is_32):
439 package_qa_add_message(messages, "arch", "Architecture did not match (%s, expected %s) on %s" % \
440 (oe.qa.elf_machine_to_string(elf.machine()), oe.qa.elf_machine_to_string(machine), package_qa_clean_path(path,d)))
441 elif not ((bits == elf.abiSize()) or is_32):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500442 package_qa_add_message(messages, "arch", "Bit size did not match (%d to %d) %s on %s" % \
443 (bits, elf.abiSize(), bpn, package_qa_clean_path(path,d)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500444 elif not littleendian == elf.isLittleEndian():
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500445 package_qa_add_message(messages, "arch", "Endiannes did not match (%d to %d) on %s" % \
446 (littleendian, elf.isLittleEndian(), package_qa_clean_path(path,d)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500447
448QAPATHTEST[desktop] = "package_qa_check_desktop"
449def package_qa_check_desktop(path, name, d, elf, messages):
450 """
451 Run all desktop files through desktop-file-validate.
452 """
453 if path.endswith(".desktop"):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500454 desktop_file_validate = os.path.join(d.getVar('STAGING_BINDIR_NATIVE'),'desktop-file-validate')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500455 output = os.popen("%s %s" % (desktop_file_validate, path))
456 # This only produces output on errors
457 for l in output:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500458 package_qa_add_message(messages, "desktop", "Desktop file issue: " + l.strip())
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500459
460QAPATHTEST[textrel] = "package_qa_textrel"
461def package_qa_textrel(path, name, d, elf, messages):
462 """
463 Check if the binary contains relocations in .text
464 """
465
466 if not elf:
467 return
468
469 if os.path.islink(path):
470 return
471
472 phdrs = elf.run_objdump("-p", d)
473 sane = True
474
475 import re
476 textrel_re = re.compile("\s+TEXTREL\s+")
477 for line in phdrs.split("\n"):
478 if textrel_re.match(line):
479 sane = False
480
481 if not sane:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500482 package_qa_add_message(messages, "textrel", "ELF binary '%s' has relocations in .text" % path)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500483
484QAPATHTEST[ldflags] = "package_qa_hash_style"
485def package_qa_hash_style(path, name, d, elf, messages):
486 """
487 Check if the binary has the right hash style...
488 """
489
490 if not elf:
491 return
492
493 if os.path.islink(path):
494 return
495
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500496 gnu_hash = "--hash-style=gnu" in d.getVar('LDFLAGS')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500497 if not gnu_hash:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500498 gnu_hash = "--hash-style=both" in d.getVar('LDFLAGS')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500499 if not gnu_hash:
500 return
501
502 sane = False
503 has_syms = False
504
505 phdrs = elf.run_objdump("-p", d)
506
507 # If this binary has symbols, we expect it to have GNU_HASH too.
508 for line in phdrs.split("\n"):
509 if "SYMTAB" in line:
510 has_syms = True
511 if "GNU_HASH" in line:
512 sane = True
513 if "[mips32]" in line or "[mips64]" in line:
514 sane = True
515
516 if has_syms and not sane:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500517 package_qa_add_message(messages, "ldflags", "No GNU_HASH in the elf binary: '%s'" % path)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500518
519
520QAPATHTEST[buildpaths] = "package_qa_check_buildpaths"
521def package_qa_check_buildpaths(path, name, d, elf, messages):
522 """
523 Check for build paths inside target files and error if not found in the whitelist
524 """
525 # Ignore .debug files, not interesting
526 if path.find(".debug") != -1:
527 return
528
529 # Ignore symlinks
530 if os.path.islink(path):
531 return
532
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500533 # Ignore ipk and deb's CONTROL dir
534 if path.find(name + "/CONTROL/") != -1 or path.find(name + "/DEBIAN/") != -1:
535 return
536
Brad Bishopd5ae7d92018-06-14 09:52:03 -0700537 tmpdir = bytes(d.getVar('TMPDIR'), encoding="utf-8")
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500538 with open(path, 'rb') as f:
Brad Bishopd5ae7d92018-06-14 09:52:03 -0700539 file_content = f.read()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500540 if tmpdir in file_content:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500541 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 -0500542
543
544QAPATHTEST[xorg-driver-abi] = "package_qa_check_xorg_driver_abi"
545def package_qa_check_xorg_driver_abi(path, name, d, elf, messages):
546 """
547 Check that all packages containing Xorg drivers have ABI dependencies
548 """
549
550 # Skip dev, dbg or nativesdk packages
551 if name.endswith("-dev") or name.endswith("-dbg") or name.startswith("nativesdk-"):
552 return
553
554 driverdir = d.expand("${libdir}/xorg/modules/drivers/")
555 if driverdir in path and path.endswith(".so"):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500556 mlprefix = d.getVar('MLPREFIX') or ''
557 for rdep in bb.utils.explode_deps(d.getVar('RDEPENDS_' + name) or ""):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500558 if rdep.startswith("%sxorg-abi-" % mlprefix):
559 return
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500560 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 -0500561
562QAPATHTEST[infodir] = "package_qa_check_infodir"
563def package_qa_check_infodir(path, name, d, elf, messages):
564 """
565 Check that /usr/share/info/dir isn't shipped in a particular package
566 """
567 infodir = d.expand("${infodir}/dir")
568
569 if infodir in path:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500570 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 -0500571
572QAPATHTEST[symlink-to-sysroot] = "package_qa_check_symlink_to_sysroot"
573def package_qa_check_symlink_to_sysroot(path, name, d, elf, messages):
574 """
575 Check that the package doesn't contain any absolute symlinks to the sysroot.
576 """
577 if os.path.islink(path):
578 target = os.readlink(path)
579 if os.path.isabs(target):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500580 tmpdir = d.getVar('TMPDIR')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500581 if target.startswith(tmpdir):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500582 trimmed = path.replace(os.path.join (d.getVar("PKGDEST"), name), "")
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500583 package_qa_add_message(messages, "symlink-to-sysroot", "Symlink %s in %s points to TMPDIR" % (trimmed, name))
584
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600585# Check license variables
586do_populate_lic[postfuncs] += "populate_lic_qa_checksum"
587python populate_lic_qa_checksum() {
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500588 """
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600589 Check for changes in the license files.
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500590 """
591 import tempfile
592 sane = True
593
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500594 lic_files = d.getVar('LIC_FILES_CHKSUM') or ''
595 lic = d.getVar('LICENSE')
596 pn = d.getVar('PN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500597
598 if lic == "CLOSED":
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500599 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500600
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500601 if not lic_files and d.getVar('SRC_URI'):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600602 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 -0500603
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500604 srcdir = d.getVar('S')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500605 corebase_licensefile = d.getVar('COREBASE') + "/LICENSE"
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500606 for url in lic_files.split():
607 try:
608 (type, host, path, user, pswd, parm) = bb.fetch.decodeurl(url)
609 except bb.fetch.MalformedUrl:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600610 sane = package_qa_handle_error("license-checksum", pn + ": LIC_FILES_CHKSUM contains an invalid URL: " + url, d)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500611 continue
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500612 srclicfile = os.path.join(srcdir, path)
613 if not os.path.isfile(srclicfile):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500614 package_qa_handle_error("license-checksum", pn + ": LIC_FILES_CHKSUM points to an invalid file: " + srclicfile, d)
615 continue
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500616
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500617 if (srclicfile == corebase_licensefile):
618 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")
619
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500620 recipemd5 = parm.get('md5', '')
621 beginline, endline = 0, 0
622 if 'beginline' in parm:
623 beginline = int(parm['beginline'])
624 if 'endline' in parm:
625 endline = int(parm['endline'])
626
627 if (not beginline) and (not endline):
628 md5chksum = bb.utils.md5_file(srclicfile)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500629 with open(srclicfile, 'rb') as f:
630 license = f.read()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500631 else:
632 fi = open(srclicfile, 'rb')
633 fo = tempfile.NamedTemporaryFile(mode='wb', prefix='poky.', suffix='.tmp', delete=False)
634 tmplicfile = fo.name;
635 lineno = 0
636 linesout = 0
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500637 license = []
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500638 for line in fi:
639 lineno += 1
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600640 if (lineno >= beginline):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500641 if ((lineno <= endline) or not endline):
642 fo.write(line)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500643 license.append(line)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500644 linesout += 1
645 else:
646 break
647 fo.flush()
648 fo.close()
649 fi.close()
650 md5chksum = bb.utils.md5_file(tmplicfile)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500651 license = b''.join(license)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500652 os.unlink(tmplicfile)
653
654 if recipemd5 == md5chksum:
655 bb.note (pn + ": md5 checksum matched for ", url)
656 else:
657 if recipemd5:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500658 msg = pn + ": The LIC_FILES_CHKSUM does not match for " + url
659 msg = msg + "\n" + pn + ": The new md5 checksum is " + md5chksum
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500660 try:
661 license_lines = license.decode('utf-8').split('\n')
662 except:
663 # License text might not be valid UTF-8, in which
664 # case we don't know how to include it in our output
665 # and have to skip it.
666 pass
667 else:
668 max_lines = int(d.getVar('QA_MAX_LICENSE_LINES') or 20)
669 if not license_lines or license_lines[-1] != '':
670 # Ensure that our license text ends with a line break
671 # (will be added with join() below).
672 license_lines.append('')
673 remove = len(license_lines) - max_lines
674 if remove > 0:
675 start = max_lines // 2
676 end = start + remove - 1
677 del license_lines[start:end]
678 license_lines.insert(start, '...')
679 msg = msg + "\n" + pn + ": Here is the selected license text:" + \
680 "\n" + \
681 "{:v^70}".format(" beginline=%d " % beginline if beginline else "") + \
682 "\n" + "\n".join(license_lines) + \
683 "{:^^70}".format(" endline=%d " % endline if endline else "")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500684 if beginline:
685 if endline:
686 srcfiledesc = "%s (lines %d through to %d)" % (srclicfile, beginline, endline)
687 else:
688 srcfiledesc = "%s (beginning on line %d)" % (srclicfile, beginline)
689 elif endline:
690 srcfiledesc = "%s (ending on line %d)" % (srclicfile, endline)
691 else:
692 srcfiledesc = srclicfile
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500693 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 -0500694
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500695 else:
696 msg = pn + ": LIC_FILES_CHKSUM is not specified for " + url
697 msg = msg + "\n" + pn + ": The md5 checksum is " + md5chksum
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600698 sane = package_qa_handle_error("license-checksum", msg, d)
699
700 if not sane:
701 bb.fatal("Fatal QA errors found, failing task.")
702}
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500703
704def package_qa_check_staged(path,d):
705 """
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500706 Check staged la and pc files for common problems like references to the work
707 directory.
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500708
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500709 As this is run after every stage we should be able to find the one
710 responsible for the errors easily even if we look at every .pc and .la file.
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500711 """
712
713 sane = True
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500714 tmpdir = d.getVar('TMPDIR')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500715 workdir = os.path.join(tmpdir, "work")
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500716 recipesysroot = d.getVar("RECIPE_SYSROOT")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500717
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500718 if bb.data.inherits_class("native", d) or bb.data.inherits_class("cross", d):
719 pkgconfigcheck = workdir
720 else:
721 pkgconfigcheck = tmpdir
722
723 # find all .la and .pc files
724 # read the content
725 # and check for stuff that looks wrong
726 for root, dirs, files in os.walk(path):
727 for file in files:
728 path = os.path.join(root,file)
729 if file.endswith(".la"):
730 with open(path) as f:
731 file_content = f.read()
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500732 file_content = file_content.replace(recipesysroot, "")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500733 if workdir in file_content:
734 error_msg = "%s failed sanity test (workdir) in path %s" % (file,root)
735 sane = package_qa_handle_error("la", error_msg, d)
736 elif file.endswith(".pc"):
737 with open(path) as f:
738 file_content = f.read()
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500739 file_content = file_content.replace(recipesysroot, "")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500740 if pkgconfigcheck in file_content:
741 error_msg = "%s failed sanity test (tmpdir) in path %s" % (file,root)
742 sane = package_qa_handle_error("pkgconfig", error_msg, d)
743
744 return sane
745
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500746# Run all package-wide warnfuncs and errorfuncs
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500747def package_qa_package(warnfuncs, errorfuncs, package, d):
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500748 warnings = {}
749 errors = {}
750
751 for func in warnfuncs:
752 func(package, d, warnings)
753 for func in errorfuncs:
754 func(package, d, errors)
755
756 for w in warnings:
757 package_qa_handle_error(w, warnings[w], d)
758 for e in errors:
759 package_qa_handle_error(e, errors[e], d)
760
761 return len(errors) == 0
762
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500763# Run all recipe-wide warnfuncs and errorfuncs
764def package_qa_recipe(warnfuncs, errorfuncs, pn, d):
765 warnings = {}
766 errors = {}
767
768 for func in warnfuncs:
769 func(pn, d, warnings)
770 for func in errorfuncs:
771 func(pn, d, errors)
772
773 for w in warnings:
774 package_qa_handle_error(w, warnings[w], d)
775 for e in errors:
776 package_qa_handle_error(e, errors[e], d)
777
778 return len(errors) == 0
779
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500780# Walk over all files in a directory and call func
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500781def package_qa_walk(warnfuncs, errorfuncs, package, d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500782 import oe.qa
783
784 #if this will throw an exception, then fix the dict above
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500785 target_os = d.getVar('TARGET_OS')
786 target_arch = d.getVar('TARGET_ARCH')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500787
788 warnings = {}
789 errors = {}
790 for path in pkgfiles[package]:
791 elf = oe.qa.ELFFile(path)
792 try:
793 elf.open()
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500794 except (IOError, oe.qa.NotELFFileError):
795 # IOError can happen if the packaging control files disappear,
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500796 elf = None
797 for func in warnfuncs:
798 func(path, package, d, elf, warnings)
799 for func in errorfuncs:
800 func(path, package, d, elf, errors)
801
802 for w in warnings:
803 package_qa_handle_error(w, warnings[w], d)
804 for e in errors:
805 package_qa_handle_error(e, errors[e], d)
806
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500807def package_qa_check_rdepends(pkg, pkgdest, skip, taskdeps, packages, d):
808 # Don't do this check for kernel/module recipes, there aren't too many debug/development
809 # packages and you can get false positives e.g. on kernel-module-lirc-dev
810 if bb.data.inherits_class("kernel", d) or bb.data.inherits_class("module-base", d):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500811 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500812
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500813 if not "-dbg" in pkg and not "packagegroup-" in pkg and not "-image" in pkg:
814 localdata = bb.data.createCopy(d)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500815 localdata.setVar('OVERRIDES', localdata.getVar('OVERRIDES') + ':' + pkg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500816
817 # Now check the RDEPENDS
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500818 rdepends = bb.utils.explode_deps(localdata.getVar('RDEPENDS') or "")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500819
820 # Now do the sanity check!!!
821 if "build-deps" not in skip:
822 for rdepend in rdepends:
823 if "-dbg" in rdepend and "debug-deps" not in skip:
824 error_msg = "%s rdepends on %s" % (pkg,rdepend)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500825 package_qa_handle_error("debug-deps", error_msg, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500826 if (not "-dev" in pkg and not "-staticdev" in pkg) and rdepend.endswith("-dev") and "dev-deps" not in skip:
827 error_msg = "%s rdepends on %s" % (pkg, rdepend)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500828 package_qa_handle_error("dev-deps", error_msg, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500829 if rdepend not in packages:
830 rdep_data = oe.packagedata.read_subpkgdata(rdepend, d)
831 if rdep_data and 'PN' in rdep_data and rdep_data['PN'] in taskdeps:
832 continue
833 if not rdep_data or not 'PN' in rdep_data:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500834 pkgdata_dir = d.getVar("PKGDATA_DIR")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500835 try:
836 possibles = os.listdir("%s/runtime-rprovides/%s/" % (pkgdata_dir, rdepend))
837 except OSError:
838 possibles = []
839 for p in possibles:
840 rdep_data = oe.packagedata.read_subpkgdata(p, d)
841 if rdep_data and 'PN' in rdep_data and rdep_data['PN'] in taskdeps:
842 break
843 if rdep_data and 'PN' in rdep_data and rdep_data['PN'] in taskdeps:
844 continue
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500845 if rdep_data and 'PN' in rdep_data:
846 error_msg = "%s rdepends on %s, but it isn't a build dependency, missing %s in DEPENDS or PACKAGECONFIG?" % (pkg, rdepend, rdep_data['PN'])
847 else:
848 error_msg = "%s rdepends on %s, but it isn't a build dependency?" % (pkg, rdepend)
849 package_qa_handle_error("build-deps", error_msg, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500850
851 if "file-rdeps" not in skip:
852 ignored_file_rdeps = set(['/bin/sh', '/usr/bin/env', 'rtld(GNU_HASH)'])
853 if bb.data.inherits_class('nativesdk', d):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500854 ignored_file_rdeps |= set(['/bin/bash', '/usr/bin/perl', 'perl'])
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500855 # For Saving the FILERDEPENDS
856 filerdepends = {}
857 rdep_data = oe.packagedata.read_subpkgdata(pkg, d)
858 for key in rdep_data:
859 if key.startswith("FILERDEPENDS_"):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500860 for subkey in bb.utils.explode_deps(rdep_data[key]):
861 if subkey not in ignored_file_rdeps and \
862 not subkey.startswith('perl('):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500863 # We already know it starts with FILERDEPENDS_
864 filerdepends[subkey] = key[13:]
865
866 if filerdepends:
867 next = rdepends
868 done = rdepends[:]
869 # Find all the rdepends on the dependency chain
870 while next:
871 new = []
872 for rdep in next:
873 rdep_data = oe.packagedata.read_subpkgdata(rdep, d)
874 sub_rdeps = rdep_data.get("RDEPENDS_" + rdep)
875 if not sub_rdeps:
876 continue
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500877 for sub_rdep in bb.utils.explode_deps(sub_rdeps):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500878 if sub_rdep in done:
879 continue
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500880 if oe.packagedata.has_subpkgdata(sub_rdep, d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500881 # It's a new rdep
882 done.append(sub_rdep)
883 new.append(sub_rdep)
884 next = new
885
886 # Add the rprovides of itself
887 if pkg not in done:
888 done.insert(0, pkg)
889
890 # The python is not a package, but python-core provides it, so
891 # skip checking /usr/bin/python if python is in the rdeps, in
892 # case there is a RDEPENDS_pkg = "python" in the recipe.
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500893 for py in [ d.getVar('MLPREFIX') + "python", "python" ]:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500894 if py in done:
895 filerdepends.pop("/usr/bin/python",None)
896 done.remove(py)
897 for rdep in done:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500898 # The file dependencies may contain package names, e.g.,
899 # perl
900 filerdepends.pop(rdep,None)
901
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500902 # For Saving the FILERPROVIDES, RPROVIDES and FILES_INFO
903 rdep_data = oe.packagedata.read_subpkgdata(rdep, d)
904 for key in rdep_data:
905 if key.startswith("FILERPROVIDES_") or key.startswith("RPROVIDES_"):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500906 for subkey in bb.utils.explode_deps(rdep_data[key]):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500907 filerdepends.pop(subkey,None)
908 # Add the files list to the rprovides
909 if key == "FILES_INFO":
910 # Use eval() to make it as a dict
911 for subkey in eval(rdep_data[key]):
912 filerdepends.pop(subkey,None)
913 if not filerdepends:
914 # Break if all the file rdepends are met
915 break
916 if filerdepends:
917 for key in filerdepends:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500918 error_msg = "%s contained in package %s requires %s, but no providers found in RDEPENDS_%s?" % \
919 (filerdepends[key].replace("_%s" % pkg, "").replace("@underscore@", "_"), pkg, key, pkg)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500920 package_qa_handle_error("file-rdeps", error_msg, d)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500921package_qa_check_rdepends[vardepsexclude] = "OVERRIDES"
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500922
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500923def package_qa_check_deps(pkg, pkgdest, d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500924
925 localdata = bb.data.createCopy(d)
926 localdata.setVar('OVERRIDES', pkg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500927
928 def check_valid_deps(var):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500929 try:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500930 rvar = bb.utils.explode_dep_versions2(localdata.getVar(var) or "")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500931 except ValueError as e:
932 bb.fatal("%s_%s: %s" % (var, pkg, e))
933 for dep in rvar:
934 for v in rvar[dep]:
935 if v and not v.startswith(('< ', '= ', '> ', '<= ', '>=')):
936 error_msg = "%s_%s is invalid: %s (%s) only comparisons <, =, >, <=, and >= are allowed" % (var, pkg, dep, v)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500937 package_qa_handle_error("dep-cmp", error_msg, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500938
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500939 check_valid_deps('RDEPENDS')
940 check_valid_deps('RRECOMMENDS')
941 check_valid_deps('RSUGGESTS')
942 check_valid_deps('RPROVIDES')
943 check_valid_deps('RREPLACES')
944 check_valid_deps('RCONFLICTS')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500945
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500946QAPKGTEST[usrmerge] = "package_qa_check_usrmerge"
947def package_qa_check_usrmerge(pkg, d, messages):
948 pkgdest = d.getVar('PKGDEST')
949 pkg_dir = pkgdest + os.sep + pkg + os.sep
950 merged_dirs = ['bin', 'sbin', 'lib'] + d.getVar('MULTILIB_VARIANTS').split()
951 for f in merged_dirs:
952 if os.path.exists(pkg_dir + f) and not os.path.islink(pkg_dir + f):
953 msg = "%s package is not obeying usrmerge distro feature. /%s should be relocated to /usr." % (pkg, f)
954 package_qa_add_message(messages, "usrmerge", msg)
955 return False
956 return True
957
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500958QAPKGTEST[expanded-d] = "package_qa_check_expanded_d"
959def package_qa_check_expanded_d(package, d, messages):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500960 """
961 Check for the expanded D (${D}) value in pkg_* and FILES
962 variables, warn the user to use it correctly.
963 """
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500964 sane = True
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500965 expanded_d = d.getVar('D')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500966
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500967 for var in 'FILES','pkg_preinst', 'pkg_postinst', 'pkg_prerm', 'pkg_postrm':
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500968 bbvar = d.getVar(var + "_" + package) or ""
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500969 if expanded_d in bbvar:
970 if var == 'FILES':
971 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)
972 sane = False
973 else:
974 package_qa_add_message(messages, "expanded-d", "%s in %s recipe contains ${D}, it should be replaced by $D instead" % (var, package))
975 sane = False
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500976 return sane
977
978def package_qa_check_encoding(keys, encode, d):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600979 def check_encoding(key, enc):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500980 sane = True
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500981 value = d.getVar(key)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500982 if value:
983 try:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600984 s = value.encode(enc)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500985 except UnicodeDecodeError as e:
986 error_msg = "%s has non %s characters" % (key,enc)
987 sane = False
988 package_qa_handle_error("invalid-chars", error_msg, d)
989 return sane
990
991 for key in keys:
992 sane = check_encoding(key, encode)
993 if not sane:
994 break
995
996HOST_USER_UID := "${@os.getuid()}"
997HOST_USER_GID := "${@os.getgid()}"
998
999QAPATHTEST[host-user-contaminated] = "package_qa_check_host_user"
1000def package_qa_check_host_user(path, name, d, elf, messages):
1001 """Check for paths outside of /home which are owned by the user running bitbake."""
1002
1003 if not os.path.lexists(path):
1004 return
1005
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001006 dest = d.getVar('PKGDEST')
1007 pn = d.getVar('PN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001008 home = os.path.join(dest, 'home')
1009 if path == home or path.startswith(home + os.sep):
1010 return
1011
1012 try:
1013 stat = os.lstat(path)
1014 except OSError as exc:
1015 import errno
1016 if exc.errno != errno.ENOENT:
1017 raise
1018 else:
Patrick Williamsf1e5d692016-03-30 15:21:19 -05001019 rootfs_path = path[len(dest):]
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001020 check_uid = int(d.getVar('HOST_USER_UID'))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001021 if stat.st_uid == check_uid:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001022 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 -05001023 return False
1024
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001025 check_gid = int(d.getVar('HOST_USER_GID'))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001026 if stat.st_gid == check_gid:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001027 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 -05001028 return False
1029 return True
1030
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001031
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001032# The PACKAGE FUNC to scan each package
1033python do_package_qa () {
1034 import subprocess
1035 import oe.packagedata
1036
1037 bb.note("DO PACKAGE QA")
1038
1039 bb.build.exec_func("read_subpackage_metadata", d)
1040
1041 # Check non UTF-8 characters on recipe's metadata
1042 package_qa_check_encoding(['DESCRIPTION', 'SUMMARY', 'LICENSE', 'SECTION'], 'utf-8', d)
1043
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001044 logdir = d.getVar('T')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001045 pn = d.getVar('PN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001046
1047 # Check the compile log for host contamination
1048 compilelog = os.path.join(logdir,"log.do_compile")
1049
1050 if os.path.exists(compilelog):
1051 statement = "grep -e 'CROSS COMPILE Badness:' -e 'is unsafe for cross-compilation' %s > /dev/null" % compilelog
1052 if subprocess.call(statement, shell=True) == 0:
1053 msg = "%s: The compile log indicates that host include and/or library paths were used.\n \
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001054 Please check the log '%s' for more information." % (pn, compilelog)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001055 package_qa_handle_error("compile-host-path", msg, d)
1056
1057 # Check the install log for host contamination
1058 installlog = os.path.join(logdir,"log.do_install")
1059
1060 if os.path.exists(installlog):
1061 statement = "grep -e 'CROSS COMPILE Badness:' -e 'is unsafe for cross-compilation' %s > /dev/null" % installlog
1062 if subprocess.call(statement, shell=True) == 0:
1063 msg = "%s: The install log indicates that host include and/or library paths were used.\n \
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001064 Please check the log '%s' for more information." % (pn, installlog)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001065 package_qa_handle_error("install-host-path", msg, d)
1066
1067 # Scan the packages...
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001068 pkgdest = d.getVar('PKGDEST')
1069 packages = set((d.getVar('PACKAGES') or '').split())
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001070
1071 cpath = oe.cachedpath.CachedPath()
1072 global pkgfiles
1073 pkgfiles = {}
1074 for pkg in packages:
1075 pkgfiles[pkg] = []
1076 for walkroot, dirs, files in cpath.walk(pkgdest + "/" + pkg):
1077 for file in files:
1078 pkgfiles[pkg].append(walkroot + os.sep + file)
1079
1080 # no packages should be scanned
1081 if not packages:
1082 return
1083
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001084 import re
1085 # The package name matches the [a-z0-9.+-]+ regular expression
1086 pkgname_pattern = re.compile("^[a-z0-9.+-]+$")
1087
1088 taskdepdata = d.getVar("BB_TASKDEPDATA", False)
1089 taskdeps = set()
1090 for dep in taskdepdata:
1091 taskdeps.add(taskdepdata[dep][0])
1092
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001093 def parse_test_matrix(matrix_name):
1094 testmatrix = d.getVarFlags(matrix_name) or {}
1095 g = globals()
1096 warnchecks = []
1097 for w in (d.getVar("WARN_QA") or "").split():
1098 if w in skip:
1099 continue
1100 if w in testmatrix and testmatrix[w] in g:
1101 warnchecks.append(g[testmatrix[w]])
1102
1103 errorchecks = []
1104 for e in (d.getVar("ERROR_QA") or "").split():
1105 if e in skip:
1106 continue
1107 if e in testmatrix and testmatrix[e] in g:
1108 errorchecks.append(g[testmatrix[e]])
1109 return warnchecks, errorchecks
1110
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001111 for package in packages:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001112 skip = set((d.getVar('INSANE_SKIP') or "").split() +
1113 (d.getVar('INSANE_SKIP_' + package) or "").split())
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001114 if skip:
1115 bb.note("Package %s skipping QA tests: %s" % (package, str(skip)))
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001116
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001117 bb.note("Checking Package: %s" % package)
1118 # Check package name
1119 if not pkgname_pattern.match(package):
1120 package_qa_handle_error("pkgname",
Patrick Williamsf1e5d692016-03-30 15:21:19 -05001121 "%s doesn't match the [a-z0-9.+-]+ regex" % package, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001122
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001123 warn_checks, error_checks = parse_test_matrix("QAPATHTEST")
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001124 package_qa_walk(warn_checks, error_checks, package, d)
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001125
1126 warn_checks, error_checks = parse_test_matrix("QAPKGTEST")
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001127 package_qa_package(warn_checks, error_checks, package, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001128
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001129 package_qa_check_rdepends(package, pkgdest, skip, taskdeps, packages, d)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001130 package_qa_check_deps(package, pkgdest, d)
1131
1132 warn_checks, error_checks = parse_test_matrix("QARECIPETEST")
1133 package_qa_recipe(warn_checks, error_checks, pn, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001134
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001135 if 'libdir' in d.getVar("ALL_QA").split():
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001136 package_qa_check_libdir(d)
1137
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001138 qa_sane = d.getVar("QA_SANE")
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001139 if not qa_sane:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001140 bb.fatal("QA run found fatal errors. Please consider fixing them.")
1141 bb.note("DONE with PACKAGE QA")
1142}
1143
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001144# binutils is used for most checks, so need to set as dependency
1145# POPULATESYSROOTDEPS is defined in staging class.
1146do_package_qa[depends] += "${POPULATESYSROOTDEPS}"
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001147do_package_qa[vardepsexclude] = "BB_TASKDEPDATA"
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001148do_package_qa[rdeptask] = "do_packagedata"
1149addtask do_package_qa after do_packagedata do_package before do_build
1150
1151SSTATETASKS += "do_package_qa"
1152do_package_qa[sstate-inputdirs] = ""
1153do_package_qa[sstate-outputdirs] = ""
1154python do_package_qa_setscene () {
1155 sstate_setscene(d)
1156}
1157addtask do_package_qa_setscene
1158
1159python do_qa_staging() {
1160 bb.note("QA checking staging")
1161
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001162 if not package_qa_check_staged(d.expand('${SYSROOT_DESTDIR}${libdir}'), d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001163 bb.fatal("QA staging was broken by the package built above")
1164}
1165
1166python do_qa_configure() {
1167 import subprocess
1168
1169 ###########################################################################
1170 # Check config.log for cross compile issues
1171 ###########################################################################
1172
1173 configs = []
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001174 workdir = d.getVar('WORKDIR')
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001175
1176 if bb.data.inherits_class('autotools', d):
1177 bb.note("Checking autotools environment for common misconfiguration")
1178 for root, dirs, files in os.walk(workdir):
1179 statement = "grep -q -F -e 'CROSS COMPILE Badness:' -e 'is unsafe for cross-compilation' %s" % \
1180 os.path.join(root,"config.log")
1181 if "config.log" in files:
1182 if subprocess.call(statement, shell=True) == 0:
1183 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 -05001184Rerun configure task after fixing this.""")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001185
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001186 if "configure.ac" in files:
1187 configs.append(os.path.join(root,"configure.ac"))
1188 if "configure.in" in files:
1189 configs.append(os.path.join(root, "configure.in"))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001190
1191 ###########################################################################
1192 # Check gettext configuration and dependencies are correct
1193 ###########################################################################
1194
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001195 cnf = d.getVar('EXTRA_OECONF') or ""
1196 if "gettext" not in d.getVar('P') and "gcc-runtime" not in d.getVar('P') and "--disable-nls" not in cnf:
1197 ml = d.getVar("MLPREFIX") or ""
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001198 if bb.data.inherits_class('cross-canadian', d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001199 gt = "nativesdk-gettext"
1200 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001201 gt = "gettext-native"
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001202 deps = bb.utils.explode_deps(d.getVar('DEPENDS') or "")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001203 if gt not in deps:
1204 for config in configs:
1205 gnu = "grep \"^[[:space:]]*AM_GNU_GETTEXT\" %s >/dev/null" % config
1206 if subprocess.call(gnu, shell=True) == 0:
1207 bb.fatal("""%s required but not in DEPENDS for file %s.
1208Missing inherit gettext?""" % (gt, config))
1209
1210 ###########################################################################
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001211 # Check unrecognised configure options (with a white list)
1212 ###########################################################################
1213 if bb.data.inherits_class("autotools", d):
1214 bb.note("Checking configure output for unrecognised options")
1215 try:
1216 flag = "WARNING: unrecognized options:"
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001217 log = os.path.join(d.getVar('B'), 'config.log')
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001218 output = subprocess.check_output(['grep', '-F', flag, log]).decode("utf-8").replace(', ', ' ')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001219 options = set()
1220 for line in output.splitlines():
1221 options |= set(line.partition(flag)[2].split())
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001222 whitelist = set(d.getVar("UNKNOWN_CONFIGURE_WHITELIST").split())
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001223 options -= whitelist
1224 if options:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001225 pn = d.getVar('PN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001226 error_msg = pn + ": configure was passed unrecognised options: " + " ".join(options)
1227 package_qa_handle_error("unknown-configure-option", error_msg, d)
1228 except subprocess.CalledProcessError:
1229 pass
1230
1231 # Check invalid PACKAGECONFIG
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001232 pkgconfig = (d.getVar("PACKAGECONFIG") or "").split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001233 if pkgconfig:
1234 pkgconfigflags = d.getVarFlags("PACKAGECONFIG") or {}
1235 for pconfig in pkgconfig:
1236 if pconfig not in pkgconfigflags:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001237 pn = d.getVar('PN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001238 error_msg = "%s: invalid PACKAGECONFIG: %s" % (pn, pconfig)
Patrick Williamsf1e5d692016-03-30 15:21:19 -05001239 package_qa_handle_error("invalid-packageconfig", error_msg, d)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001240
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001241 qa_sane = d.getVar("QA_SANE")
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001242 if not qa_sane:
1243 bb.fatal("Fatal QA errors found, failing task.")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001244}
1245
1246python do_qa_unpack() {
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001247 src_uri = d.getVar('SRC_URI')
1248 s_dir = d.getVar('S')
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001249 if src_uri and not os.path.exists(s_dir):
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001250 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 -05001251}
1252
1253# The Staging Func, to check all staging
1254#addtask qa_staging after do_populate_sysroot before do_build
1255do_populate_sysroot[postfuncs] += "do_qa_staging "
1256
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001257# Check broken config.log files, for packages requiring Gettext which
1258# don't have it in DEPENDS.
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001259#addtask qa_configure after do_configure before do_compile
1260do_configure[postfuncs] += "do_qa_configure "
1261
1262# Check does S exist.
1263do_unpack[postfuncs] += "do_qa_unpack"
1264
1265python () {
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001266 import re
1267
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001268 tests = d.getVar('ALL_QA').split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001269 if "desktop" in tests:
1270 d.appendVar("PACKAGE_DEPENDS", " desktop-file-utils-native")
1271
1272 ###########################################################################
1273 # Check various variables
1274 ###########################################################################
1275
1276 # Checking ${FILESEXTRAPATHS}
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001277 extrapaths = (d.getVar("FILESEXTRAPATHS") or "")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001278 if '__default' not in extrapaths.split(":"):
1279 msg = "FILESEXTRAPATHS-variable, must always use _prepend (or _append)\n"
1280 msg += "type of assignment, and don't forget the colon.\n"
1281 msg += "Please assign it with the format of:\n"
1282 msg += " FILESEXTRAPATHS_append := \":${THISDIR}/Your_Files_Path\" or\n"
1283 msg += " FILESEXTRAPATHS_prepend := \"${THISDIR}/Your_Files_Path:\"\n"
1284 msg += "in your bbappend file\n\n"
1285 msg += "Your incorrect assignment is:\n"
1286 msg += "%s\n" % extrapaths
1287 bb.warn(msg)
1288
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001289 overrides = d.getVar('OVERRIDES').split(':')
1290 pn = d.getVar('PN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001291 if pn in overrides:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001292 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 -05001293 package_qa_handle_error("pn-overrides", msg, d)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001294 prog = re.compile('[A-Z]')
1295 if prog.search(pn):
1296 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 -05001297
1298 issues = []
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001299 if (d.getVar('PACKAGES') or "").split():
1300 for dep in (d.getVar('QADEPENDS') or "").split():
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001301 d.appendVarFlag('do_package_qa', 'depends', " %s:do_populate_sysroot" % dep)
1302 for var in 'RDEPENDS', 'RRECOMMENDS', 'RSUGGESTS', 'RCONFLICTS', 'RPROVIDES', 'RREPLACES', 'FILES', 'pkg_preinst', 'pkg_postinst', 'pkg_prerm', 'pkg_postrm', 'ALLOW_EMPTY':
1303 if d.getVar(var, False):
1304 issues.append(var)
1305
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001306 fakeroot_tests = d.getVar('FAKEROOT_QA').split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001307 if set(tests) & set(fakeroot_tests):
1308 d.setVarFlag('do_package_qa', 'fakeroot', '1')
1309 d.appendVarFlag('do_package_qa', 'depends', ' virtual/fakeroot-native:do_populate_sysroot')
1310 else:
1311 d.setVarFlag('do_package_qa', 'rdeptask', '')
1312 for i in issues:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001313 package_qa_handle_error("pkgvarcheck", "%s: Variable %s is set as not being package specific, please fix this." % (d.getVar("FILE"), i), d)
1314 qa_sane = d.getVar("QA_SANE")
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001315 if not qa_sane:
1316 bb.fatal("Fatal QA errors found, failing task.")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001317}