blob: 0c11c365837601a3a8e93cc9525ad612028f92ee [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
19
20
21# unsafe-references-in-binaries requires prelink-rtld from
22# prelink-native, but we don't want this DEPENDS for -native builds
23QADEPENDS = "prelink-native"
24QADEPENDS_class-native = ""
25QADEPENDS_class-nativesdk = ""
26QA_SANE = "True"
27
28# Elect whether a given type of error is a warning or error, they may
29# have been set by other files.
30WARN_QA ?= "ldflags useless-rpaths rpaths staticdev libdir xorg-driver-abi \
31 textrel already-stripped incompatible-license files-invalid \
32 installed-vs-shipped compile-host-path install-host-path \
Brad Bishop6e60e8b2018-02-01 10:27:11 -050033 pn-overrides infodir build-deps \
Patrick Williamsc124f4f2015-09-15 14:41:29 -050034 unknown-configure-option symlink-to-sysroot multilib \
Patrick Williamsf1e5d692016-03-30 15:21:19 -050035 invalid-packageconfig host-user-contaminated \
Patrick Williamsc124f4f2015-09-15 14:41:29 -050036 "
37ERROR_QA ?= "dev-so debug-deps dev-deps debug-files arch pkgconfig la \
38 perms dep-cmp pkgvarcheck perm-config perm-line perm-link \
39 split-strip packages-list pkgv-undefined var-undefined \
40 version-going-backwards expanded-d invalid-chars \
Brad Bishop6e60e8b2018-02-01 10:27:11 -050041 license-checksum dev-elf file-rdeps \
Patrick Williamsc124f4f2015-09-15 14:41:29 -050042 "
43FAKEROOT_QA = "host-user-contaminated"
44FAKEROOT_QA[doc] = "QA tests which need to run under fakeroot. If any \
45enabled tests are listed here, the do_package_qa task will run under fakeroot."
46
47ALL_QA = "${WARN_QA} ${ERROR_QA}"
48
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050049UNKNOWN_CONFIGURE_WHITELIST ?= "--enable-nls --disable-nls --disable-silent-rules --disable-dependency-tracking --with-libtool-sysroot --disable-static"
Patrick Williamsc124f4f2015-09-15 14:41:29 -050050
51#
52# dictionary for elf headers
53#
54# feel free to add and correct.
55#
56# TARGET_OS TARGET_ARCH MACHINE, OSABI, ABIVERSION, Little Endian, 32bit?
Patrick Williamsc0f7c042017-02-23 20:41:17 -060057def package_qa_get_machine_dict(d):
58 machdata = {
Patrick Williamsc124f4f2015-09-15 14:41:29 -050059 "darwin9" : {
60 "arm" : (40, 0, 0, True, 32),
61 },
62 "eabi" : {
63 "arm" : (40, 0, 0, True, 32),
64 },
65 "elf" : {
Brad Bishop37a0e4d2017-12-04 01:01:44 -050066 "aarch64" : (183, 0, 0, True, 64),
67 "aarch64_be" :(183, 0, 0, False, 64),
Patrick Williamsc124f4f2015-09-15 14:41:29 -050068 "i586" : (3, 0, 0, True, 32),
69 "x86_64": (62, 0, 0, True, 64),
70 "epiphany": (4643, 0, 0, True, 32),
Patrick Williamsc0f7c042017-02-23 20:41:17 -060071 "mips": ( 8, 0, 0, False, 32),
72 "mipsel": ( 8, 0, 0, True, 32),
Patrick Williamsc124f4f2015-09-15 14:41:29 -050073 },
74 "linux" : {
75 "aarch64" : (183, 0, 0, True, 64),
76 "aarch64_be" :(183, 0, 0, False, 64),
77 "arm" : (40, 97, 0, True, 32),
78 "armeb": (40, 97, 0, False, 32),
79 "powerpc": (20, 0, 0, False, 32),
80 "powerpc64": (21, 0, 0, False, 64),
81 "i386": ( 3, 0, 0, True, 32),
82 "i486": ( 3, 0, 0, True, 32),
83 "i586": ( 3, 0, 0, True, 32),
84 "i686": ( 3, 0, 0, True, 32),
85 "x86_64": (62, 0, 0, True, 64),
86 "ia64": (50, 0, 0, True, 64),
87 "alpha": (36902, 0, 0, True, 64),
88 "hppa": (15, 3, 0, False, 32),
89 "m68k": ( 4, 0, 0, False, 32),
90 "mips": ( 8, 0, 0, False, 32),
91 "mipsel": ( 8, 0, 0, True, 32),
92 "mips64": ( 8, 0, 0, False, 64),
93 "mips64el": ( 8, 0, 0, True, 64),
Patrick Williamsc0f7c042017-02-23 20:41:17 -060094 "mipsisa32r6": ( 8, 0, 0, False, 32),
95 "mipsisa32r6el": ( 8, 0, 0, True, 32),
96 "mipsisa64r6": ( 8, 0, 0, False, 64),
97 "mipsisa64r6el": ( 8, 0, 0, True, 64),
Patrick Williamsf1e5d692016-03-30 15:21:19 -050098 "nios2": (113, 0, 0, True, 32),
Patrick Williamsc124f4f2015-09-15 14:41:29 -050099 "s390": (22, 0, 0, False, 32),
100 "sh4": (42, 0, 0, True, 32),
101 "sparc": ( 2, 0, 0, False, 32),
102 "microblaze": (189, 0, 0, False, 32),
103 "microblazeeb":(189, 0, 0, False, 32),
104 "microblazeel":(189, 0, 0, True, 32),
105 },
106 "linux-uclibc" : {
107 "arm" : ( 40, 97, 0, True, 32),
108 "armeb": ( 40, 97, 0, False, 32),
109 "powerpc": ( 20, 0, 0, False, 32),
110 "i386": ( 3, 0, 0, True, 32),
111 "i486": ( 3, 0, 0, True, 32),
112 "i586": ( 3, 0, 0, True, 32),
113 "i686": ( 3, 0, 0, True, 32),
114 "x86_64": ( 62, 0, 0, True, 64),
115 "mips": ( 8, 0, 0, False, 32),
116 "mipsel": ( 8, 0, 0, True, 32),
117 "mips64": ( 8, 0, 0, False, 64),
118 "mips64el": ( 8, 0, 0, True, 64),
119 "avr32": (6317, 0, 0, False, 32),
120 "sh4": (42, 0, 0, True, 32),
121
122 },
123 "linux-musl" : {
124 "aarch64" : (183, 0, 0, True, 64),
125 "aarch64_be" :(183, 0, 0, False, 64),
126 "arm" : ( 40, 97, 0, True, 32),
127 "armeb": ( 40, 97, 0, False, 32),
128 "powerpc": ( 20, 0, 0, False, 32),
129 "i386": ( 3, 0, 0, True, 32),
130 "i486": ( 3, 0, 0, True, 32),
131 "i586": ( 3, 0, 0, True, 32),
132 "i686": ( 3, 0, 0, True, 32),
133 "x86_64": ( 62, 0, 0, True, 64),
134 "mips": ( 8, 0, 0, False, 32),
135 "mipsel": ( 8, 0, 0, True, 32),
136 "mips64": ( 8, 0, 0, False, 64),
137 "mips64el": ( 8, 0, 0, True, 64),
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500138 "microblaze": (189, 0, 0, False, 32),
139 "microblazeeb":(189, 0, 0, False, 32),
140 "microblazeel":(189, 0, 0, True, 32),
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500141 "sh4": ( 42, 0, 0, True, 32),
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500142 },
143 "uclinux-uclibc" : {
144 "bfin": ( 106, 0, 0, True, 32),
145 },
146 "linux-gnueabi" : {
147 "arm" : (40, 0, 0, True, 32),
148 "armeb" : (40, 0, 0, False, 32),
149 },
150 "linux-musleabi" : {
151 "arm" : (40, 0, 0, True, 32),
152 "armeb" : (40, 0, 0, False, 32),
153 },
154 "linux-uclibceabi" : {
155 "arm" : (40, 0, 0, True, 32),
156 "armeb" : (40, 0, 0, False, 32),
157 },
158 "linux-gnuspe" : {
159 "powerpc": (20, 0, 0, False, 32),
160 },
161 "linux-muslspe" : {
162 "powerpc": (20, 0, 0, False, 32),
163 },
164 "linux-uclibcspe" : {
165 "powerpc": (20, 0, 0, False, 32),
166 },
167 "linux-gnu" : {
168 "powerpc": (20, 0, 0, False, 32),
169 "sh4": (42, 0, 0, True, 32),
170 },
171 "linux-gnux32" : {
172 "x86_64": (62, 0, 0, True, 32),
173 },
174 "linux-gnun32" : {
175 "mips64": ( 8, 0, 0, False, 32),
176 "mips64el": ( 8, 0, 0, True, 32),
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500177 "mipsisa64r6": ( 8, 0, 0, False, 32),
178 "mipsisa64r6el":( 8, 0, 0, True, 32),
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500179 },
180 }
181
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600182 # Add in any extra user supplied data which may come from a BSP layer, removing the
183 # need to always change this class directly
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500184 extra_machdata = (d.getVar("PACKAGEQA_EXTRA_MACHDEFFUNCS") or "").split()
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600185 for m in extra_machdata:
186 call = m + "(machdata, d)"
187 locs = { "machdata" : machdata, "d" : d}
188 machdata = bb.utils.better_eval(call, locs)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500189
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600190 return machdata
191
192
193def package_qa_clean_path(path, d, pkg=None):
194 """
195 Remove redundant paths from the path for display. If pkg isn't set then
196 TMPDIR is stripped, otherwise PKGDEST/pkg is stripped.
197 """
198 if pkg:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500199 path = path.replace(os.path.join(d.getVar("PKGDEST"), pkg), "/")
200 return path.replace(d.getVar("TMPDIR"), "/").replace("//", "/")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500201
202def package_qa_write_error(type, error, d):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500203 logfile = d.getVar('QA_LOGFILE')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500204 if logfile:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500205 p = d.getVar('P')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600206 with open(logfile, "a+") as f:
207 f.write("%s: %s [%s]\n" % (p, error, type))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500208
209def package_qa_handle_error(error_class, error_msg, d):
210 package_qa_write_error(error_class, error_msg, d)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500211 if error_class in (d.getVar("ERROR_QA") or "").split():
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500212 bb.error("QA Issue: %s [%s]" % (error_msg, error_class))
213 d.setVar("QA_SANE", False)
214 return False
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500215 elif error_class in (d.getVar("WARN_QA") or "").split():
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500216 bb.warn("QA Issue: %s [%s]" % (error_msg, error_class))
217 else:
218 bb.note("QA Issue: %s [%s]" % (error_msg, error_class))
219 return True
220
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500221def package_qa_add_message(messages, section, new_msg):
222 if section not in messages:
223 messages[section] = new_msg
224 else:
225 messages[section] = messages[section] + "\n" + new_msg
226
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500227QAPATHTEST[libexec] = "package_qa_check_libexec"
228def package_qa_check_libexec(path,name, d, elf, messages):
229
230 # Skip the case where the default is explicitly /usr/libexec
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500231 libexec = d.getVar('libexecdir')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500232 if libexec == "/usr/libexec":
233 return True
234
235 if 'libexec' in path.split(os.path.sep):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500236 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 -0500237 return False
238
239 return True
240
241QAPATHTEST[rpaths] = "package_qa_check_rpath"
242def package_qa_check_rpath(file,name, d, elf, messages):
243 """
244 Check for dangerous RPATHs
245 """
246 if not elf:
247 return
248
249 if os.path.islink(file):
250 return
251
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500252 bad_dirs = [d.getVar('BASE_WORKDIR'), d.getVar('STAGING_DIR_TARGET')]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500253
254 phdrs = elf.run_objdump("-p", d)
255
256 import re
257 rpath_re = re.compile("\s+RPATH\s+(.*)")
258 for line in phdrs.split("\n"):
259 m = rpath_re.match(line)
260 if m:
261 rpath = m.group(1)
262 for dir in bad_dirs:
263 if dir in rpath:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500264 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 -0500265
266QAPATHTEST[useless-rpaths] = "package_qa_check_useless_rpaths"
267def package_qa_check_useless_rpaths(file, name, d, elf, messages):
268 """
269 Check for RPATHs that are useless but not dangerous
270 """
271 def rpath_eq(a, b):
272 return os.path.normpath(a) == os.path.normpath(b)
273
274 if not elf:
275 return
276
277 if os.path.islink(file):
278 return
279
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500280 libdir = d.getVar("libdir")
281 base_libdir = d.getVar("base_libdir")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500282
283 phdrs = elf.run_objdump("-p", d)
284
285 import re
286 rpath_re = re.compile("\s+RPATH\s+(.*)")
287 for line in phdrs.split("\n"):
288 m = rpath_re.match(line)
289 if m:
290 rpath = m.group(1)
291 if rpath_eq(rpath, libdir) or rpath_eq(rpath, base_libdir):
292 # The dynamic linker searches both these places anyway. There is no point in
293 # looking there again.
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500294 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 -0500295
296QAPATHTEST[dev-so] = "package_qa_check_dev"
297def package_qa_check_dev(path, name, d, elf, messages):
298 """
299 Check for ".so" library symlinks in non-dev packages
300 """
301
302 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 -0500303 package_qa_add_message(messages, "dev-so", "non -dev/-dbg/nativesdk- package contains symlink .so: %s path '%s'" % \
304 (name, package_qa_clean_path(path,d)))
305
306QAPATHTEST[dev-elf] = "package_qa_check_dev_elf"
307def package_qa_check_dev_elf(path, name, d, elf, messages):
308 """
309 Check that -dev doesn't contain real shared libraries. The test has to
310 check that the file is not a link and is an ELF object as some recipes
311 install link-time .so files that are linker scripts.
312 """
313 if name.endswith("-dev") and path.endswith(".so") and not os.path.islink(path) and elf:
314 package_qa_add_message(messages, "dev-elf", "-dev package contains non-symlink .so: %s path '%s'" % \
315 (name, package_qa_clean_path(path,d)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500316
317QAPATHTEST[staticdev] = "package_qa_check_staticdev"
318def package_qa_check_staticdev(path, name, d, elf, messages):
319 """
320 Check for ".a" library in non-staticdev packages
321 There are a number of exceptions to this rule, -pic packages can contain
322 static libraries, the _nonshared.a belong with their -dev packages and
323 libgcc.a, libgcov.a will be skipped in their packages
324 """
325
326 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 -0500327 package_qa_add_message(messages, "staticdev", "non -staticdev package contains static .a library: %s path '%s'" % \
328 (name, package_qa_clean_path(path,d)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500329
330def package_qa_check_libdir(d):
331 """
332 Check for wrong library installation paths. For instance, catch
333 recipes installing /lib/bar.so when ${base_libdir}="lib32" or
334 installing in /usr/lib64 when ${libdir}="/usr/lib"
335 """
336 import re
337
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500338 pkgdest = d.getVar('PKGDEST')
339 base_libdir = d.getVar("base_libdir") + os.sep
340 libdir = d.getVar("libdir") + os.sep
341 libexecdir = d.getVar("libexecdir") + os.sep
342 exec_prefix = d.getVar("exec_prefix") + os.sep
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500343
344 messages = []
345
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500346 # The re's are purposely fuzzy, as some there are some .so.x.y.z files
347 # that don't follow the standard naming convention. It checks later
348 # that they are actual ELF files
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500349 lib_re = re.compile("^/lib.+\.so(\..+)?$")
350 exec_re = re.compile("^%s.*/lib.+\.so(\..+)?$" % exec_prefix)
351
352 for root, dirs, files in os.walk(pkgdest):
353 if root == pkgdest:
354 # Skip subdirectories for any packages with libdir in INSANE_SKIP
355 skippackages = []
356 for package in dirs:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500357 if 'libdir' in (d.getVar('INSANE_SKIP_' + package) or "").split():
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500358 bb.note("Package %s skipping libdir QA test" % (package))
359 skippackages.append(package)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500360 elif d.getVar('PACKAGE_DEBUG_SPLIT_STYLE') == 'debug-file-directory' and package.endswith("-dbg"):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500361 bb.note("Package %s skipping libdir QA test for PACKAGE_DEBUG_SPLIT_STYLE equals debug-file-directory" % (package))
362 skippackages.append(package)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500363 for package in skippackages:
364 dirs.remove(package)
365 for file in files:
366 full_path = os.path.join(root, file)
367 rel_path = os.path.relpath(full_path, pkgdest)
368 if os.sep in rel_path:
369 package, rel_path = rel_path.split(os.sep, 1)
370 rel_path = os.sep + rel_path
371 if lib_re.match(rel_path):
372 if base_libdir not in rel_path:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500373 # make sure it's an actual ELF file
374 elf = oe.qa.ELFFile(full_path)
375 try:
376 elf.open()
377 messages.append("%s: found library in wrong location: %s" % (package, rel_path))
378 except (oe.qa.NotELFFileError):
379 pass
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500380 if exec_re.match(rel_path):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500381 if libdir not in rel_path and libexecdir not in rel_path:
382 # make sure it's an actual ELF file
383 elf = oe.qa.ELFFile(full_path)
384 try:
385 elf.open()
386 messages.append("%s: found library in wrong location: %s" % (package, rel_path))
387 except (oe.qa.NotELFFileError):
388 pass
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500389
390 if messages:
391 package_qa_handle_error("libdir", "\n".join(messages), d)
392
393QAPATHTEST[debug-files] = "package_qa_check_dbg"
394def package_qa_check_dbg(path, name, d, elf, messages):
395 """
396 Check for ".debug" files or directories outside of the dbg package
397 """
398
399 if not "-dbg" in name and not "-ptest" in name:
400 if '.debug' in path.split(os.path.sep):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500401 package_qa_add_message(messages, "debug-files", "non debug package contains .debug directory: %s path %s" % \
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500402 (name, package_qa_clean_path(path,d)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500403
404QAPATHTEST[perms] = "package_qa_check_perm"
405def package_qa_check_perm(path,name,d, elf, messages):
406 """
407 Check the permission of files
408 """
409 return
410
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500411QAPATHTEST[unsafe-references-in-scripts] = "package_qa_check_unsafe_references_in_scripts"
412def package_qa_check_unsafe_references_in_scripts(path, name, d, elf, messages):
413 """
414 Warn if scripts in base_[bindir|sbindir|libdir] reference files under exec_prefix
415 """
416 if unsafe_references_skippable(path, name, d):
417 return
418
419 if not elf:
420 import stat
421 import subprocess
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500422 pn = d.getVar('PN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500423
424 # Ensure we're checking an executable script
425 statinfo = os.stat(path)
426 if bool(statinfo.st_mode & stat.S_IXUSR):
427 # grep shell scripts for possible references to /exec_prefix/
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500428 exec_prefix = d.getVar('exec_prefix')
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500429 statement = "grep -e '%s/[^ :]\{1,\}/[^ :]\{1,\}' %s > /dev/null" % (exec_prefix, path)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500430 if subprocess.call(statement, shell=True) == 0:
431 error_msg = pn + ": Found a reference to %s/ in %s" % (exec_prefix, path)
432 package_qa_handle_error("unsafe-references-in-scripts", error_msg, d)
433 error_msg = "Shell scripts in base_bindir and base_sbindir should not reference anything in exec_prefix"
434 package_qa_handle_error("unsafe-references-in-scripts", error_msg, d)
435
436def unsafe_references_skippable(path, name, d):
437 if bb.data.inherits_class('native', d) or bb.data.inherits_class('nativesdk', d):
438 return True
439
440 if "-dbg" in name or "-dev" in name:
441 return True
442
443 # Other package names to skip:
444 if name.startswith("kernel-module-"):
445 return True
446
447 # Skip symlinks
448 if os.path.islink(path):
449 return True
450
451 # Skip unusual rootfs layouts which make these tests irrelevant
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500452 exec_prefix = d.getVar('exec_prefix')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500453 if exec_prefix == "":
454 return True
455
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500456 pkgdest = d.getVar('PKGDEST')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500457 pkgdest = pkgdest + "/" + name
458 pkgdest = os.path.abspath(pkgdest)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500459 base_bindir = pkgdest + d.getVar('base_bindir')
460 base_sbindir = pkgdest + d.getVar('base_sbindir')
461 base_libdir = pkgdest + d.getVar('base_libdir')
462 bindir = pkgdest + d.getVar('bindir')
463 sbindir = pkgdest + d.getVar('sbindir')
464 libdir = pkgdest + d.getVar('libdir')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500465
466 if base_bindir == bindir and base_sbindir == sbindir and base_libdir == libdir:
467 return True
468
469 # Skip files not in base_[bindir|sbindir|libdir]
470 path = os.path.abspath(path)
471 if not (base_bindir in path or base_sbindir in path or base_libdir in path):
472 return True
473
474 return False
475
476QAPATHTEST[arch] = "package_qa_check_arch"
477def package_qa_check_arch(path,name,d, elf, messages):
478 """
479 Check if archs are compatible
480 """
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600481 import re
482
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500483 if not elf:
484 return
485
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500486 target_os = d.getVar('TARGET_OS')
487 target_arch = d.getVar('TARGET_ARCH')
488 provides = d.getVar('PROVIDES')
489 bpn = d.getVar('BPN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500490
491 if target_arch == "allarch":
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500492 pn = d.getVar('PN')
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500493 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 -0500494 return
495
496 # FIXME: Cross package confuse this check, so just skip them
497 for s in ['cross', 'nativesdk', 'cross-canadian']:
498 if bb.data.inherits_class(s, d):
499 return
500
501 # avoid following links to /usr/bin (e.g. on udev builds)
502 # we will check the files pointed to anyway...
503 if os.path.islink(path):
504 return
505
506 #if this will throw an exception, then fix the dict above
507 (machine, osabi, abiversion, littleendian, bits) \
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600508 = package_qa_get_machine_dict(d)[target_os][target_arch]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500509
510 # Check the architecture and endiannes of the binary
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600511 is_32 = (("virtual/kernel" in provides) or bb.data.inherits_class("module", d)) and \
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500512 (target_os == "linux-gnux32" or re.match('mips64.*32', d.getVar('DEFAULTTUNE')))
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600513 if not ((machine == elf.machine()) or is_32):
514 package_qa_add_message(messages, "arch", "Architecture did not match (%s, expected %s) on %s" % \
515 (oe.qa.elf_machine_to_string(elf.machine()), oe.qa.elf_machine_to_string(machine), package_qa_clean_path(path,d)))
516 elif not ((bits == elf.abiSize()) or is_32):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500517 package_qa_add_message(messages, "arch", "Bit size did not match (%d to %d) %s on %s" % \
518 (bits, elf.abiSize(), bpn, package_qa_clean_path(path,d)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500519 elif not littleendian == elf.isLittleEndian():
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500520 package_qa_add_message(messages, "arch", "Endiannes did not match (%d to %d) on %s" % \
521 (littleendian, elf.isLittleEndian(), package_qa_clean_path(path,d)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500522
523QAPATHTEST[desktop] = "package_qa_check_desktop"
524def package_qa_check_desktop(path, name, d, elf, messages):
525 """
526 Run all desktop files through desktop-file-validate.
527 """
528 if path.endswith(".desktop"):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500529 desktop_file_validate = os.path.join(d.getVar('STAGING_BINDIR_NATIVE'),'desktop-file-validate')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500530 output = os.popen("%s %s" % (desktop_file_validate, path))
531 # This only produces output on errors
532 for l in output:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500533 package_qa_add_message(messages, "desktop", "Desktop file issue: " + l.strip())
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500534
535QAPATHTEST[textrel] = "package_qa_textrel"
536def package_qa_textrel(path, name, d, elf, messages):
537 """
538 Check if the binary contains relocations in .text
539 """
540
541 if not elf:
542 return
543
544 if os.path.islink(path):
545 return
546
547 phdrs = elf.run_objdump("-p", d)
548 sane = True
549
550 import re
551 textrel_re = re.compile("\s+TEXTREL\s+")
552 for line in phdrs.split("\n"):
553 if textrel_re.match(line):
554 sane = False
555
556 if not sane:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500557 package_qa_add_message(messages, "textrel", "ELF binary '%s' has relocations in .text" % path)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500558
559QAPATHTEST[ldflags] = "package_qa_hash_style"
560def package_qa_hash_style(path, name, d, elf, messages):
561 """
562 Check if the binary has the right hash style...
563 """
564
565 if not elf:
566 return
567
568 if os.path.islink(path):
569 return
570
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500571 gnu_hash = "--hash-style=gnu" in d.getVar('LDFLAGS')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500572 if not gnu_hash:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500573 gnu_hash = "--hash-style=both" in d.getVar('LDFLAGS')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500574 if not gnu_hash:
575 return
576
577 sane = False
578 has_syms = False
579
580 phdrs = elf.run_objdump("-p", d)
581
582 # If this binary has symbols, we expect it to have GNU_HASH too.
583 for line in phdrs.split("\n"):
584 if "SYMTAB" in line:
585 has_syms = True
586 if "GNU_HASH" in line:
587 sane = True
588 if "[mips32]" in line or "[mips64]" in line:
589 sane = True
590
591 if has_syms and not sane:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500592 package_qa_add_message(messages, "ldflags", "No GNU_HASH in the elf binary: '%s'" % path)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500593
594
595QAPATHTEST[buildpaths] = "package_qa_check_buildpaths"
596def package_qa_check_buildpaths(path, name, d, elf, messages):
597 """
598 Check for build paths inside target files and error if not found in the whitelist
599 """
600 # Ignore .debug files, not interesting
601 if path.find(".debug") != -1:
602 return
603
604 # Ignore symlinks
605 if os.path.islink(path):
606 return
607
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500608 # Ignore ipk and deb's CONTROL dir
609 if path.find(name + "/CONTROL/") != -1 or path.find(name + "/DEBIAN/") != -1:
610 return
611
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500612 tmpdir = d.getVar('TMPDIR')
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500613 with open(path, 'rb') as f:
614 file_content = f.read().decode('utf-8', errors='ignore')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500615 if tmpdir in file_content:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500616 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 -0500617
618
619QAPATHTEST[xorg-driver-abi] = "package_qa_check_xorg_driver_abi"
620def package_qa_check_xorg_driver_abi(path, name, d, elf, messages):
621 """
622 Check that all packages containing Xorg drivers have ABI dependencies
623 """
624
625 # Skip dev, dbg or nativesdk packages
626 if name.endswith("-dev") or name.endswith("-dbg") or name.startswith("nativesdk-"):
627 return
628
629 driverdir = d.expand("${libdir}/xorg/modules/drivers/")
630 if driverdir in path and path.endswith(".so"):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500631 mlprefix = d.getVar('MLPREFIX') or ''
632 for rdep in bb.utils.explode_deps(d.getVar('RDEPENDS_' + name) or ""):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500633 if rdep.startswith("%sxorg-abi-" % mlprefix):
634 return
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500635 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 -0500636
637QAPATHTEST[infodir] = "package_qa_check_infodir"
638def package_qa_check_infodir(path, name, d, elf, messages):
639 """
640 Check that /usr/share/info/dir isn't shipped in a particular package
641 """
642 infodir = d.expand("${infodir}/dir")
643
644 if infodir in path:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500645 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 -0500646
647QAPATHTEST[symlink-to-sysroot] = "package_qa_check_symlink_to_sysroot"
648def package_qa_check_symlink_to_sysroot(path, name, d, elf, messages):
649 """
650 Check that the package doesn't contain any absolute symlinks to the sysroot.
651 """
652 if os.path.islink(path):
653 target = os.readlink(path)
654 if os.path.isabs(target):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500655 tmpdir = d.getVar('TMPDIR')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500656 if target.startswith(tmpdir):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500657 trimmed = path.replace(os.path.join (d.getVar("PKGDEST"), name), "")
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500658 package_qa_add_message(messages, "symlink-to-sysroot", "Symlink %s in %s points to TMPDIR" % (trimmed, name))
659
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600660# Check license variables
661do_populate_lic[postfuncs] += "populate_lic_qa_checksum"
662python populate_lic_qa_checksum() {
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500663 """
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600664 Check for changes in the license files.
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500665 """
666 import tempfile
667 sane = True
668
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500669 lic_files = d.getVar('LIC_FILES_CHKSUM') or ''
670 lic = d.getVar('LICENSE')
671 pn = d.getVar('PN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500672
673 if lic == "CLOSED":
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500674 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500675
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500676 if not lic_files and d.getVar('SRC_URI'):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600677 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 -0500678
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500679 srcdir = d.getVar('S')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500680
681 for url in lic_files.split():
682 try:
683 (type, host, path, user, pswd, parm) = bb.fetch.decodeurl(url)
684 except bb.fetch.MalformedUrl:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600685 sane = package_qa_handle_error("license-checksum", pn + ": LIC_FILES_CHKSUM contains an invalid URL: " + url, d)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500686 continue
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500687 srclicfile = os.path.join(srcdir, path)
688 if not os.path.isfile(srclicfile):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500689 package_qa_handle_error("license-checksum", pn + ": LIC_FILES_CHKSUM points to an invalid file: " + srclicfile, d)
690 continue
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500691
692 recipemd5 = parm.get('md5', '')
693 beginline, endline = 0, 0
694 if 'beginline' in parm:
695 beginline = int(parm['beginline'])
696 if 'endline' in parm:
697 endline = int(parm['endline'])
698
699 if (not beginline) and (not endline):
700 md5chksum = bb.utils.md5_file(srclicfile)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500701 with open(srclicfile, 'rb') as f:
702 license = f.read()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500703 else:
704 fi = open(srclicfile, 'rb')
705 fo = tempfile.NamedTemporaryFile(mode='wb', prefix='poky.', suffix='.tmp', delete=False)
706 tmplicfile = fo.name;
707 lineno = 0
708 linesout = 0
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500709 license = []
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500710 for line in fi:
711 lineno += 1
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600712 if (lineno >= beginline):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500713 if ((lineno <= endline) or not endline):
714 fo.write(line)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500715 license.append(line)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500716 linesout += 1
717 else:
718 break
719 fo.flush()
720 fo.close()
721 fi.close()
722 md5chksum = bb.utils.md5_file(tmplicfile)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500723 license = b''.join(license)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500724 os.unlink(tmplicfile)
725
726 if recipemd5 == md5chksum:
727 bb.note (pn + ": md5 checksum matched for ", url)
728 else:
729 if recipemd5:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500730 msg = pn + ": The LIC_FILES_CHKSUM does not match for " + url
731 msg = msg + "\n" + pn + ": The new md5 checksum is " + md5chksum
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500732 try:
733 license_lines = license.decode('utf-8').split('\n')
734 except:
735 # License text might not be valid UTF-8, in which
736 # case we don't know how to include it in our output
737 # and have to skip it.
738 pass
739 else:
740 max_lines = int(d.getVar('QA_MAX_LICENSE_LINES') or 20)
741 if not license_lines or license_lines[-1] != '':
742 # Ensure that our license text ends with a line break
743 # (will be added with join() below).
744 license_lines.append('')
745 remove = len(license_lines) - max_lines
746 if remove > 0:
747 start = max_lines // 2
748 end = start + remove - 1
749 del license_lines[start:end]
750 license_lines.insert(start, '...')
751 msg = msg + "\n" + pn + ": Here is the selected license text:" + \
752 "\n" + \
753 "{:v^70}".format(" beginline=%d " % beginline if beginline else "") + \
754 "\n" + "\n".join(license_lines) + \
755 "{:^^70}".format(" endline=%d " % endline if endline else "")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500756 if beginline:
757 if endline:
758 srcfiledesc = "%s (lines %d through to %d)" % (srclicfile, beginline, endline)
759 else:
760 srcfiledesc = "%s (beginning on line %d)" % (srclicfile, beginline)
761 elif endline:
762 srcfiledesc = "%s (ending on line %d)" % (srclicfile, endline)
763 else:
764 srcfiledesc = srclicfile
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500765 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 -0500766
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500767 else:
768 msg = pn + ": LIC_FILES_CHKSUM is not specified for " + url
769 msg = msg + "\n" + pn + ": The md5 checksum is " + md5chksum
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600770 sane = package_qa_handle_error("license-checksum", msg, d)
771
772 if not sane:
773 bb.fatal("Fatal QA errors found, failing task.")
774}
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500775
776def package_qa_check_staged(path,d):
777 """
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500778 Check staged la and pc files for common problems like references to the work
779 directory.
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500780
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500781 As this is run after every stage we should be able to find the one
782 responsible for the errors easily even if we look at every .pc and .la file.
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500783 """
784
785 sane = True
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500786 tmpdir = d.getVar('TMPDIR')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500787 workdir = os.path.join(tmpdir, "work")
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500788 recipesysroot = d.getVar("RECIPE_SYSROOT")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500789
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500790 if bb.data.inherits_class("native", d) or bb.data.inherits_class("cross", d):
791 pkgconfigcheck = workdir
792 else:
793 pkgconfigcheck = tmpdir
794
795 # find all .la and .pc files
796 # read the content
797 # and check for stuff that looks wrong
798 for root, dirs, files in os.walk(path):
799 for file in files:
800 path = os.path.join(root,file)
801 if file.endswith(".la"):
802 with open(path) as f:
803 file_content = f.read()
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500804 file_content = file_content.replace(recipesysroot, "")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500805 if workdir in file_content:
806 error_msg = "%s failed sanity test (workdir) in path %s" % (file,root)
807 sane = package_qa_handle_error("la", error_msg, d)
808 elif file.endswith(".pc"):
809 with open(path) as f:
810 file_content = f.read()
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500811 file_content = file_content.replace(recipesysroot, "")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500812 if pkgconfigcheck in file_content:
813 error_msg = "%s failed sanity test (tmpdir) in path %s" % (file,root)
814 sane = package_qa_handle_error("pkgconfig", error_msg, d)
815
816 return sane
817
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500818# Run all package-wide warnfuncs and errorfuncs
819def package_qa_package(warnfuncs, errorfuncs, skip, package, d):
820 warnings = {}
821 errors = {}
822
823 for func in warnfuncs:
824 func(package, d, warnings)
825 for func in errorfuncs:
826 func(package, d, errors)
827
828 for w in warnings:
829 package_qa_handle_error(w, warnings[w], d)
830 for e in errors:
831 package_qa_handle_error(e, errors[e], d)
832
833 return len(errors) == 0
834
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500835# Walk over all files in a directory and call func
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500836def package_qa_walk(warnfuncs, errorfuncs, skip, package, d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500837 import oe.qa
838
839 #if this will throw an exception, then fix the dict above
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500840 target_os = d.getVar('TARGET_OS')
841 target_arch = d.getVar('TARGET_ARCH')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500842
843 warnings = {}
844 errors = {}
845 for path in pkgfiles[package]:
846 elf = oe.qa.ELFFile(path)
847 try:
848 elf.open()
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500849 except (IOError, oe.qa.NotELFFileError):
850 # IOError can happen if the packaging control files disappear,
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500851 elf = None
852 for func in warnfuncs:
853 func(path, package, d, elf, warnings)
854 for func in errorfuncs:
855 func(path, package, d, elf, errors)
856
857 for w in warnings:
858 package_qa_handle_error(w, warnings[w], d)
859 for e in errors:
860 package_qa_handle_error(e, errors[e], d)
861
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500862def package_qa_check_rdepends(pkg, pkgdest, skip, taskdeps, packages, d):
863 # Don't do this check for kernel/module recipes, there aren't too many debug/development
864 # packages and you can get false positives e.g. on kernel-module-lirc-dev
865 if bb.data.inherits_class("kernel", d) or bb.data.inherits_class("module-base", d):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500866 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500867
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500868 if not "-dbg" in pkg and not "packagegroup-" in pkg and not "-image" in pkg:
869 localdata = bb.data.createCopy(d)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500870 localdata.setVar('OVERRIDES', localdata.getVar('OVERRIDES') + ':' + pkg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500871
872 # Now check the RDEPENDS
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500873 rdepends = bb.utils.explode_deps(localdata.getVar('RDEPENDS') or "")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500874
875 # Now do the sanity check!!!
876 if "build-deps" not in skip:
877 for rdepend in rdepends:
878 if "-dbg" in rdepend and "debug-deps" not in skip:
879 error_msg = "%s rdepends on %s" % (pkg,rdepend)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500880 package_qa_handle_error("debug-deps", error_msg, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500881 if (not "-dev" in pkg and not "-staticdev" in pkg) and rdepend.endswith("-dev") and "dev-deps" not in skip:
882 error_msg = "%s rdepends on %s" % (pkg, rdepend)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500883 package_qa_handle_error("dev-deps", error_msg, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500884 if rdepend not in packages:
885 rdep_data = oe.packagedata.read_subpkgdata(rdepend, d)
886 if rdep_data and 'PN' in rdep_data and rdep_data['PN'] in taskdeps:
887 continue
888 if not rdep_data or not 'PN' in rdep_data:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500889 pkgdata_dir = d.getVar("PKGDATA_DIR")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500890 try:
891 possibles = os.listdir("%s/runtime-rprovides/%s/" % (pkgdata_dir, rdepend))
892 except OSError:
893 possibles = []
894 for p in possibles:
895 rdep_data = oe.packagedata.read_subpkgdata(p, d)
896 if rdep_data and 'PN' in rdep_data and rdep_data['PN'] in taskdeps:
897 break
898 if rdep_data and 'PN' in rdep_data and rdep_data['PN'] in taskdeps:
899 continue
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500900 if rdep_data and 'PN' in rdep_data:
901 error_msg = "%s rdepends on %s, but it isn't a build dependency, missing %s in DEPENDS or PACKAGECONFIG?" % (pkg, rdepend, rdep_data['PN'])
902 else:
903 error_msg = "%s rdepends on %s, but it isn't a build dependency?" % (pkg, rdepend)
904 package_qa_handle_error("build-deps", error_msg, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500905
906 if "file-rdeps" not in skip:
907 ignored_file_rdeps = set(['/bin/sh', '/usr/bin/env', 'rtld(GNU_HASH)'])
908 if bb.data.inherits_class('nativesdk', d):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500909 ignored_file_rdeps |= set(['/bin/bash', '/usr/bin/perl', 'perl'])
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500910 # For Saving the FILERDEPENDS
911 filerdepends = {}
912 rdep_data = oe.packagedata.read_subpkgdata(pkg, d)
913 for key in rdep_data:
914 if key.startswith("FILERDEPENDS_"):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500915 for subkey in bb.utils.explode_deps(rdep_data[key]):
916 if subkey not in ignored_file_rdeps and \
917 not subkey.startswith('perl('):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500918 # We already know it starts with FILERDEPENDS_
919 filerdepends[subkey] = key[13:]
920
921 if filerdepends:
922 next = rdepends
923 done = rdepends[:]
924 # Find all the rdepends on the dependency chain
925 while next:
926 new = []
927 for rdep in next:
928 rdep_data = oe.packagedata.read_subpkgdata(rdep, d)
929 sub_rdeps = rdep_data.get("RDEPENDS_" + rdep)
930 if not sub_rdeps:
931 continue
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500932 for sub_rdep in bb.utils.explode_deps(sub_rdeps):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500933 if sub_rdep in done:
934 continue
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500935 if oe.packagedata.has_subpkgdata(sub_rdep, d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500936 # It's a new rdep
937 done.append(sub_rdep)
938 new.append(sub_rdep)
939 next = new
940
941 # Add the rprovides of itself
942 if pkg not in done:
943 done.insert(0, pkg)
944
945 # The python is not a package, but python-core provides it, so
946 # skip checking /usr/bin/python if python is in the rdeps, in
947 # case there is a RDEPENDS_pkg = "python" in the recipe.
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500948 for py in [ d.getVar('MLPREFIX') + "python", "python" ]:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500949 if py in done:
950 filerdepends.pop("/usr/bin/python",None)
951 done.remove(py)
952 for rdep in done:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500953 # The file dependencies may contain package names, e.g.,
954 # perl
955 filerdepends.pop(rdep,None)
956
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500957 # For Saving the FILERPROVIDES, RPROVIDES and FILES_INFO
958 rdep_data = oe.packagedata.read_subpkgdata(rdep, d)
959 for key in rdep_data:
960 if key.startswith("FILERPROVIDES_") or key.startswith("RPROVIDES_"):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500961 for subkey in bb.utils.explode_deps(rdep_data[key]):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500962 filerdepends.pop(subkey,None)
963 # Add the files list to the rprovides
964 if key == "FILES_INFO":
965 # Use eval() to make it as a dict
966 for subkey in eval(rdep_data[key]):
967 filerdepends.pop(subkey,None)
968 if not filerdepends:
969 # Break if all the file rdepends are met
970 break
971 if filerdepends:
972 for key in filerdepends:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500973 error_msg = "%s contained in package %s requires %s, but no providers found in RDEPENDS_%s?" % \
974 (filerdepends[key].replace("_%s" % pkg, "").replace("@underscore@", "_"), pkg, key, pkg)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500975 package_qa_handle_error("file-rdeps", error_msg, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500976
977def package_qa_check_deps(pkg, pkgdest, skip, d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500978
979 localdata = bb.data.createCopy(d)
980 localdata.setVar('OVERRIDES', pkg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500981
982 def check_valid_deps(var):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500983 try:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500984 rvar = bb.utils.explode_dep_versions2(localdata.getVar(var) or "")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500985 except ValueError as e:
986 bb.fatal("%s_%s: %s" % (var, pkg, e))
987 for dep in rvar:
988 for v in rvar[dep]:
989 if v and not v.startswith(('< ', '= ', '> ', '<= ', '>=')):
990 error_msg = "%s_%s is invalid: %s (%s) only comparisons <, =, >, <=, and >= are allowed" % (var, pkg, dep, v)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500991 package_qa_handle_error("dep-cmp", error_msg, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500992
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500993 check_valid_deps('RDEPENDS')
994 check_valid_deps('RRECOMMENDS')
995 check_valid_deps('RSUGGESTS')
996 check_valid_deps('RPROVIDES')
997 check_valid_deps('RREPLACES')
998 check_valid_deps('RCONFLICTS')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500999
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001000QAPKGTEST[expanded-d] = "package_qa_check_expanded_d"
1001def package_qa_check_expanded_d(package, d, messages):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001002 """
1003 Check for the expanded D (${D}) value in pkg_* and FILES
1004 variables, warn the user to use it correctly.
1005 """
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001006 sane = True
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001007 expanded_d = d.getVar('D')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001008
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001009 for var in 'FILES','pkg_preinst', 'pkg_postinst', 'pkg_prerm', 'pkg_postrm':
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001010 bbvar = d.getVar(var + "_" + package) or ""
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001011 if expanded_d in bbvar:
1012 if var == 'FILES':
1013 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)
1014 sane = False
1015 else:
1016 package_qa_add_message(messages, "expanded-d", "%s in %s recipe contains ${D}, it should be replaced by $D instead" % (var, package))
1017 sane = False
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001018 return sane
1019
1020def package_qa_check_encoding(keys, encode, d):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001021 def check_encoding(key, enc):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001022 sane = True
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001023 value = d.getVar(key)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001024 if value:
1025 try:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001026 s = value.encode(enc)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001027 except UnicodeDecodeError as e:
1028 error_msg = "%s has non %s characters" % (key,enc)
1029 sane = False
1030 package_qa_handle_error("invalid-chars", error_msg, d)
1031 return sane
1032
1033 for key in keys:
1034 sane = check_encoding(key, encode)
1035 if not sane:
1036 break
1037
1038HOST_USER_UID := "${@os.getuid()}"
1039HOST_USER_GID := "${@os.getgid()}"
1040
1041QAPATHTEST[host-user-contaminated] = "package_qa_check_host_user"
1042def package_qa_check_host_user(path, name, d, elf, messages):
1043 """Check for paths outside of /home which are owned by the user running bitbake."""
1044
1045 if not os.path.lexists(path):
1046 return
1047
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001048 dest = d.getVar('PKGDEST')
1049 pn = d.getVar('PN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001050 home = os.path.join(dest, 'home')
1051 if path == home or path.startswith(home + os.sep):
1052 return
1053
1054 try:
1055 stat = os.lstat(path)
1056 except OSError as exc:
1057 import errno
1058 if exc.errno != errno.ENOENT:
1059 raise
1060 else:
Patrick Williamsf1e5d692016-03-30 15:21:19 -05001061 rootfs_path = path[len(dest):]
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001062 check_uid = int(d.getVar('HOST_USER_UID'))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001063 if stat.st_uid == check_uid:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001064 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 -05001065 return False
1066
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001067 check_gid = int(d.getVar('HOST_USER_GID'))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001068 if stat.st_gid == check_gid:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001069 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 -05001070 return False
1071 return True
1072
1073# The PACKAGE FUNC to scan each package
1074python do_package_qa () {
1075 import subprocess
1076 import oe.packagedata
1077
1078 bb.note("DO PACKAGE QA")
1079
1080 bb.build.exec_func("read_subpackage_metadata", d)
1081
1082 # Check non UTF-8 characters on recipe's metadata
1083 package_qa_check_encoding(['DESCRIPTION', 'SUMMARY', 'LICENSE', 'SECTION'], 'utf-8', d)
1084
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001085 logdir = d.getVar('T')
1086 pkg = d.getVar('PN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001087
1088 # Check the compile log for host contamination
1089 compilelog = os.path.join(logdir,"log.do_compile")
1090
1091 if os.path.exists(compilelog):
1092 statement = "grep -e 'CROSS COMPILE Badness:' -e 'is unsafe for cross-compilation' %s > /dev/null" % compilelog
1093 if subprocess.call(statement, shell=True) == 0:
1094 msg = "%s: The compile log indicates that host include and/or library paths were used.\n \
1095 Please check the log '%s' for more information." % (pkg, compilelog)
1096 package_qa_handle_error("compile-host-path", msg, d)
1097
1098 # Check the install log for host contamination
1099 installlog = os.path.join(logdir,"log.do_install")
1100
1101 if os.path.exists(installlog):
1102 statement = "grep -e 'CROSS COMPILE Badness:' -e 'is unsafe for cross-compilation' %s > /dev/null" % installlog
1103 if subprocess.call(statement, shell=True) == 0:
1104 msg = "%s: The install log indicates that host include and/or library paths were used.\n \
1105 Please check the log '%s' for more information." % (pkg, installlog)
1106 package_qa_handle_error("install-host-path", msg, d)
1107
1108 # Scan the packages...
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001109 pkgdest = d.getVar('PKGDEST')
1110 packages = set((d.getVar('PACKAGES') or '').split())
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001111
1112 cpath = oe.cachedpath.CachedPath()
1113 global pkgfiles
1114 pkgfiles = {}
1115 for pkg in packages:
1116 pkgfiles[pkg] = []
1117 for walkroot, dirs, files in cpath.walk(pkgdest + "/" + pkg):
1118 for file in files:
1119 pkgfiles[pkg].append(walkroot + os.sep + file)
1120
1121 # no packages should be scanned
1122 if not packages:
1123 return
1124
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001125 import re
1126 # The package name matches the [a-z0-9.+-]+ regular expression
1127 pkgname_pattern = re.compile("^[a-z0-9.+-]+$")
1128
1129 taskdepdata = d.getVar("BB_TASKDEPDATA", False)
1130 taskdeps = set()
1131 for dep in taskdepdata:
1132 taskdeps.add(taskdepdata[dep][0])
1133
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001134 for package in packages:
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001135 def parse_test_matrix(matrix_name):
1136 testmatrix = d.getVarFlags(matrix_name) or {}
1137 g = globals()
1138 warnchecks = []
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001139 for w in (d.getVar("WARN_QA") or "").split():
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001140 if w in skip:
1141 continue
1142 if w in testmatrix and testmatrix[w] in g:
1143 warnchecks.append(g[testmatrix[w]])
1144 if w == 'unsafe-references-in-binaries':
1145 oe.utils.write_ld_so_conf(d)
1146
1147 errorchecks = []
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001148 for e in (d.getVar("ERROR_QA") or "").split():
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001149 if e in skip:
1150 continue
1151 if e in testmatrix and testmatrix[e] in g:
1152 errorchecks.append(g[testmatrix[e]])
1153 if e == 'unsafe-references-in-binaries':
1154 oe.utils.write_ld_so_conf(d)
1155 return warnchecks, errorchecks
1156
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001157 skip = set((d.getVar('INSANE_SKIP') or "").split() +
1158 (d.getVar('INSANE_SKIP_' + package) or "").split())
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001159 if skip:
1160 bb.note("Package %s skipping QA tests: %s" % (package, str(skip)))
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001161
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001162
1163 bb.note("Checking Package: %s" % package)
1164 # Check package name
1165 if not pkgname_pattern.match(package):
1166 package_qa_handle_error("pkgname",
Patrick Williamsf1e5d692016-03-30 15:21:19 -05001167 "%s doesn't match the [a-z0-9.+-]+ regex" % package, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001168
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001169 warn_checks, error_checks = parse_test_matrix("QAPATHTEST")
1170 package_qa_walk(warn_checks, error_checks, skip, package, d)
1171
1172 warn_checks, error_checks = parse_test_matrix("QAPKGTEST")
1173 package_qa_package(warn_checks, error_checks, skip, package, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001174
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001175 package_qa_check_rdepends(package, pkgdest, skip, taskdeps, packages, d)
1176 package_qa_check_deps(package, pkgdest, skip, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001177
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001178 if 'libdir' in d.getVar("ALL_QA").split():
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001179 package_qa_check_libdir(d)
1180
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001181 qa_sane = d.getVar("QA_SANE")
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001182 if not qa_sane:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001183 bb.fatal("QA run found fatal errors. Please consider fixing them.")
1184 bb.note("DONE with PACKAGE QA")
1185}
1186
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001187# binutils is used for most checks, so need to set as dependency
1188# POPULATESYSROOTDEPS is defined in staging class.
1189do_package_qa[depends] += "${POPULATESYSROOTDEPS}"
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001190do_package_qa[vardepsexclude] = "BB_TASKDEPDATA"
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001191do_package_qa[rdeptask] = "do_packagedata"
1192addtask do_package_qa after do_packagedata do_package before do_build
1193
1194SSTATETASKS += "do_package_qa"
1195do_package_qa[sstate-inputdirs] = ""
1196do_package_qa[sstate-outputdirs] = ""
1197python do_package_qa_setscene () {
1198 sstate_setscene(d)
1199}
1200addtask do_package_qa_setscene
1201
1202python do_qa_staging() {
1203 bb.note("QA checking staging")
1204
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001205 if not package_qa_check_staged(d.expand('${SYSROOT_DESTDIR}${libdir}'), d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001206 bb.fatal("QA staging was broken by the package built above")
1207}
1208
1209python do_qa_configure() {
1210 import subprocess
1211
1212 ###########################################################################
1213 # Check config.log for cross compile issues
1214 ###########################################################################
1215
1216 configs = []
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001217 workdir = d.getVar('WORKDIR')
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001218
1219 if bb.data.inherits_class('autotools', d):
1220 bb.note("Checking autotools environment for common misconfiguration")
1221 for root, dirs, files in os.walk(workdir):
1222 statement = "grep -q -F -e 'CROSS COMPILE Badness:' -e 'is unsafe for cross-compilation' %s" % \
1223 os.path.join(root,"config.log")
1224 if "config.log" in files:
1225 if subprocess.call(statement, shell=True) == 0:
1226 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 -05001227Rerun configure task after fixing this.""")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001228
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001229 if "configure.ac" in files:
1230 configs.append(os.path.join(root,"configure.ac"))
1231 if "configure.in" in files:
1232 configs.append(os.path.join(root, "configure.in"))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001233
1234 ###########################################################################
1235 # Check gettext configuration and dependencies are correct
1236 ###########################################################################
1237
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001238 cnf = d.getVar('EXTRA_OECONF') or ""
1239 if "gettext" not in d.getVar('P') and "gcc-runtime" not in d.getVar('P') and "--disable-nls" not in cnf:
1240 ml = d.getVar("MLPREFIX") or ""
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001241 if bb.data.inherits_class('native', d) or bb.data.inherits_class('cross', d) or bb.data.inherits_class('crosssdk', d) or bb.data.inherits_class('nativesdk', d):
1242 gt = "gettext-native"
1243 elif bb.data.inherits_class('cross-canadian', d):
1244 gt = "nativesdk-gettext"
1245 else:
1246 gt = "virtual/" + ml + "gettext"
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001247 deps = bb.utils.explode_deps(d.getVar('DEPENDS') or "")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001248 if gt not in deps:
1249 for config in configs:
1250 gnu = "grep \"^[[:space:]]*AM_GNU_GETTEXT\" %s >/dev/null" % config
1251 if subprocess.call(gnu, shell=True) == 0:
1252 bb.fatal("""%s required but not in DEPENDS for file %s.
1253Missing inherit gettext?""" % (gt, config))
1254
1255 ###########################################################################
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001256 # Check unrecognised configure options (with a white list)
1257 ###########################################################################
1258 if bb.data.inherits_class("autotools", d):
1259 bb.note("Checking configure output for unrecognised options")
1260 try:
1261 flag = "WARNING: unrecognized options:"
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001262 log = os.path.join(d.getVar('B'), 'config.log')
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001263 output = subprocess.check_output(['grep', '-F', flag, log]).decode("utf-8").replace(', ', ' ')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001264 options = set()
1265 for line in output.splitlines():
1266 options |= set(line.partition(flag)[2].split())
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001267 whitelist = set(d.getVar("UNKNOWN_CONFIGURE_WHITELIST").split())
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001268 options -= whitelist
1269 if options:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001270 pn = d.getVar('PN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001271 error_msg = pn + ": configure was passed unrecognised options: " + " ".join(options)
1272 package_qa_handle_error("unknown-configure-option", error_msg, d)
1273 except subprocess.CalledProcessError:
1274 pass
1275
1276 # Check invalid PACKAGECONFIG
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001277 pkgconfig = (d.getVar("PACKAGECONFIG") or "").split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001278 if pkgconfig:
1279 pkgconfigflags = d.getVarFlags("PACKAGECONFIG") or {}
1280 for pconfig in pkgconfig:
1281 if pconfig not in pkgconfigflags:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001282 pn = d.getVar('PN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001283 error_msg = "%s: invalid PACKAGECONFIG: %s" % (pn, pconfig)
Patrick Williamsf1e5d692016-03-30 15:21:19 -05001284 package_qa_handle_error("invalid-packageconfig", error_msg, d)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001285
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001286 qa_sane = d.getVar("QA_SANE")
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001287 if not qa_sane:
1288 bb.fatal("Fatal QA errors found, failing task.")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001289}
1290
1291python do_qa_unpack() {
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001292 src_uri = d.getVar('SRC_URI')
1293 s_dir = d.getVar('S')
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001294 if src_uri and not os.path.exists(s_dir):
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001295 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 -05001296}
1297
1298# The Staging Func, to check all staging
1299#addtask qa_staging after do_populate_sysroot before do_build
1300do_populate_sysroot[postfuncs] += "do_qa_staging "
1301
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001302# Check broken config.log files, for packages requiring Gettext which
1303# don't have it in DEPENDS.
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001304#addtask qa_configure after do_configure before do_compile
1305do_configure[postfuncs] += "do_qa_configure "
1306
1307# Check does S exist.
1308do_unpack[postfuncs] += "do_qa_unpack"
1309
1310python () {
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001311 tests = d.getVar('ALL_QA').split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001312 if "desktop" in tests:
1313 d.appendVar("PACKAGE_DEPENDS", " desktop-file-utils-native")
1314
1315 ###########################################################################
1316 # Check various variables
1317 ###########################################################################
1318
1319 # Checking ${FILESEXTRAPATHS}
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001320 extrapaths = (d.getVar("FILESEXTRAPATHS") or "")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001321 if '__default' not in extrapaths.split(":"):
1322 msg = "FILESEXTRAPATHS-variable, must always use _prepend (or _append)\n"
1323 msg += "type of assignment, and don't forget the colon.\n"
1324 msg += "Please assign it with the format of:\n"
1325 msg += " FILESEXTRAPATHS_append := \":${THISDIR}/Your_Files_Path\" or\n"
1326 msg += " FILESEXTRAPATHS_prepend := \"${THISDIR}/Your_Files_Path:\"\n"
1327 msg += "in your bbappend file\n\n"
1328 msg += "Your incorrect assignment is:\n"
1329 msg += "%s\n" % extrapaths
1330 bb.warn(msg)
1331
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001332 overrides = d.getVar('OVERRIDES').split(':')
1333 pn = d.getVar('PN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001334 if pn in overrides:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001335 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 -05001336 package_qa_handle_error("pn-overrides", msg, d)
1337
1338 issues = []
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001339 if (d.getVar('PACKAGES') or "").split():
1340 for dep in (d.getVar('QADEPENDS') or "").split():
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001341 d.appendVarFlag('do_package_qa', 'depends', " %s:do_populate_sysroot" % dep)
1342 for var in 'RDEPENDS', 'RRECOMMENDS', 'RSUGGESTS', 'RCONFLICTS', 'RPROVIDES', 'RREPLACES', 'FILES', 'pkg_preinst', 'pkg_postinst', 'pkg_prerm', 'pkg_postrm', 'ALLOW_EMPTY':
1343 if d.getVar(var, False):
1344 issues.append(var)
1345
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001346 fakeroot_tests = d.getVar('FAKEROOT_QA').split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001347 if set(tests) & set(fakeroot_tests):
1348 d.setVarFlag('do_package_qa', 'fakeroot', '1')
1349 d.appendVarFlag('do_package_qa', 'depends', ' virtual/fakeroot-native:do_populate_sysroot')
1350 else:
1351 d.setVarFlag('do_package_qa', 'rdeptask', '')
1352 for i in issues:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001353 package_qa_handle_error("pkgvarcheck", "%s: Variable %s is set as not being package specific, please fix this." % (d.getVar("FILE"), i), d)
1354 qa_sane = d.getVar("QA_SANE")
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001355 if not qa_sane:
1356 bb.fatal("Fatal QA errors found, failing task.")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001357}