blob: ae86d261e7c50704cf7d5add2d811fe16ffb8258 [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001#
2# Sanity check the users setup for common misconfigurations
3#
4
5SANITY_REQUIRED_UTILITIES ?= "patch diffstat makeinfo git bzip2 tar \
Patrick Williamsf1e5d692016-03-30 15:21:19 -05006 gzip gawk chrpath wget cpio perl file"
Patrick Williamsc124f4f2015-09-15 14:41:29 -05007
8def bblayers_conf_file(d):
9 return os.path.join(d.getVar('TOPDIR', True), 'conf/bblayers.conf')
10
11def sanity_conf_read(fn):
12 with open(fn, 'r') as f:
13 lines = f.readlines()
14 return lines
15
16def sanity_conf_find_line(pattern, lines):
17 import re
18 return next(((index, line)
19 for index, line in enumerate(lines)
20 if re.search(pattern, line)), (None, None))
21
22def sanity_conf_update(fn, lines, version_var_name, new_version):
23 index, line = sanity_conf_find_line(version_var_name, lines)
24 lines[index] = '%s = "%d"\n' % (version_var_name, new_version)
25 with open(fn, "w") as f:
26 f.write(''.join(lines))
27
28# Functions added to this variable MUST throw an exception (or sys.exit()) unless they
29# successfully changed LCONF_VERSION in bblayers.conf
30BBLAYERS_CONF_UPDATE_FUNCS += "oecore_update_bblayers"
31
32python oecore_update_bblayers() {
33 # bblayers.conf is out of date, so see if we can resolve that
34
35 current_lconf = int(d.getVar('LCONF_VERSION', True))
36 if not current_lconf:
37 sys.exit()
38 lconf_version = int(d.getVar('LAYER_CONF_VERSION', True))
39 lines = []
40
41 if current_lconf < 4:
42 sys.exit()
43
44 bblayers_fn = bblayers_conf_file(d)
45 lines = sanity_conf_read(bblayers_fn)
46
47 if current_lconf == 4 and lconf_version > 4:
48 topdir_var = '$' + '{TOPDIR}'
49 index, bbpath_line = sanity_conf_find_line('BBPATH', lines)
50 if bbpath_line:
51 start = bbpath_line.find('"')
52 if start != -1 and (len(bbpath_line) != (start + 1)):
53 if bbpath_line[start + 1] == '"':
54 lines[index] = (bbpath_line[:start + 1] +
55 topdir_var + bbpath_line[start + 1:])
56 else:
57 if not topdir_var in bbpath_line:
58 lines[index] = (bbpath_line[:start + 1] +
59 topdir_var + ':' + bbpath_line[start + 1:])
60 else:
61 sys.exit()
62 else:
63 index, bbfiles_line = sanity_conf_find_line('BBFILES', lines)
64 if bbfiles_line:
65 lines.insert(index, 'BBPATH = "' + topdir_var + '"\n')
66 else:
67 sys.exit()
68
69 current_lconf += 1
70 sanity_conf_update(bblayers_fn, lines, 'LCONF_VERSION', current_lconf)
71 return
72
73 elif current_lconf == 5 and lconf_version > 5:
74 # Null update, to avoid issues with people switching between poky and other distros
75 current_lconf = 6
76 sanity_conf_update(bblayers_fn, lines, 'LCONF_VERSION', current_lconf)
77 return
78
79 sys.exit()
80}
81
82def raise_sanity_error(msg, d, network_error=False):
83 if d.getVar("SANITY_USE_EVENTS", True) == "1":
84 try:
85 bb.event.fire(bb.event.SanityCheckFailed(msg, network_error), d)
86 except TypeError:
87 bb.event.fire(bb.event.SanityCheckFailed(msg), d)
88 return
89
90 bb.fatal(""" OE-core's config sanity checker detected a potential misconfiguration.
91 Either fix the cause of this error or at your own risk disable the checker (see sanity.conf).
92 Following is the list of potential problems / advisories:
93
94 %s""" % msg)
95
96# Check flags associated with a tuning.
97def check_toolchain_tune_args(data, tune, multilib, errs):
98 found_errors = False
99 if check_toolchain_args_present(data, tune, multilib, errs, 'CCARGS'):
100 found_errors = True
101 if check_toolchain_args_present(data, tune, multilib, errs, 'ASARGS'):
102 found_errors = True
103 if check_toolchain_args_present(data, tune, multilib, errs, 'LDARGS'):
104 found_errors = True
105
106 return found_errors
107
108def check_toolchain_args_present(data, tune, multilib, tune_errors, which):
109 args_set = (data.getVar("TUNE_%s" % which, True) or "").split()
110 args_wanted = (data.getVar("TUNEABI_REQUIRED_%s_tune-%s" % (which, tune), True) or "").split()
111 args_missing = []
112
113 # If no args are listed/required, we are done.
114 if not args_wanted:
115 return
116 for arg in args_wanted:
117 if arg not in args_set:
118 args_missing.append(arg)
119
120 found_errors = False
121 if args_missing:
122 found_errors = True
123 tune_errors.append("TUNEABI for %s requires '%s' in TUNE_%s (%s)." %
124 (tune, ' '.join(args_missing), which, ' '.join(args_set)))
125 return found_errors
126
127# Check a single tune for validity.
128def check_toolchain_tune(data, tune, multilib):
129 tune_errors = []
130 if not tune:
131 return "No tuning found for %s multilib." % multilib
132 localdata = bb.data.createCopy(data)
133 if multilib != "default":
134 # Apply the overrides so we can look at the details.
135 overrides = localdata.getVar("OVERRIDES", False) + ":virtclass-multilib-" + multilib
136 localdata.setVar("OVERRIDES", overrides)
137 bb.data.update_data(localdata)
138 bb.debug(2, "Sanity-checking tuning '%s' (%s) features:" % (tune, multilib))
139 features = (localdata.getVar("TUNE_FEATURES_tune-%s" % tune, True) or "").split()
140 if not features:
141 return "Tuning '%s' has no defined features, and cannot be used." % tune
142 valid_tunes = localdata.getVarFlags('TUNEVALID') or {}
143 conflicts = localdata.getVarFlags('TUNECONFLICTS') or {}
144 # [doc] is the documentation for the variable, not a real feature
145 if 'doc' in valid_tunes:
146 del valid_tunes['doc']
147 if 'doc' in conflicts:
148 del conflicts['doc']
149 for feature in features:
150 if feature in conflicts:
151 for conflict in conflicts[feature].split():
152 if conflict in features:
153 tune_errors.append("Feature '%s' conflicts with '%s'." %
154 (feature, conflict))
155 if feature in valid_tunes:
156 bb.debug(2, " %s: %s" % (feature, valid_tunes[feature]))
157 else:
158 tune_errors.append("Feature '%s' is not defined." % feature)
159 whitelist = localdata.getVar("TUNEABI_WHITELIST", True)
160 if whitelist:
161 tuneabi = localdata.getVar("TUNEABI_tune-%s" % tune, True)
162 if not tuneabi:
163 tuneabi = tune
164 if True not in [x in whitelist.split() for x in tuneabi.split()]:
165 tune_errors.append("Tuning '%s' (%s) cannot be used with any supported tuning/ABI." %
166 (tune, tuneabi))
167 else:
168 if not check_toolchain_tune_args(localdata, tuneabi, multilib, tune_errors):
169 bb.debug(2, "Sanity check: Compiler args OK for %s." % tune)
170 if tune_errors:
171 return "Tuning '%s' has the following errors:\n" % tune + '\n'.join(tune_errors)
172
173def check_toolchain(data):
174 tune_error_set = []
175 deftune = data.getVar("DEFAULTTUNE", True)
176 tune_errors = check_toolchain_tune(data, deftune, 'default')
177 if tune_errors:
178 tune_error_set.append(tune_errors)
179
180 multilibs = (data.getVar("MULTILIB_VARIANTS", True) or "").split()
181 global_multilibs = (data.getVar("MULTILIB_GLOBAL_VARIANTS", True) or "").split()
182
183 if multilibs:
184 seen_libs = []
185 seen_tunes = []
186 for lib in multilibs:
187 if lib in seen_libs:
188 tune_error_set.append("The multilib '%s' appears more than once." % lib)
189 else:
190 seen_libs.append(lib)
191 if not lib in global_multilibs:
192 tune_error_set.append("Multilib %s is not present in MULTILIB_GLOBAL_VARIANTS" % lib)
193 tune = data.getVar("DEFAULTTUNE_virtclass-multilib-%s" % lib, True)
194 if tune in seen_tunes:
195 tune_error_set.append("The tuning '%s' appears in more than one multilib." % tune)
196 else:
197 seen_libs.append(tune)
198 if tune == deftune:
199 tune_error_set.append("Multilib '%s' (%s) is also the default tuning." % (lib, deftune))
200 else:
201 tune_errors = check_toolchain_tune(data, tune, lib)
202 if tune_errors:
203 tune_error_set.append(tune_errors)
204 if tune_error_set:
205 return "Toolchain tunings invalid:\n" + '\n'.join(tune_error_set) + "\n"
206
207 return ""
208
209def check_conf_exists(fn, data):
210 bbpath = []
211 fn = data.expand(fn)
212 vbbpath = data.getVar("BBPATH", False)
213 if vbbpath:
214 bbpath += vbbpath.split(":")
215 for p in bbpath:
216 currname = os.path.join(data.expand(p), fn)
217 if os.access(currname, os.R_OK):
218 return True
219 return False
220
221def check_create_long_filename(filepath, pathname):
222 import string, random
223 testfile = os.path.join(filepath, ''.join(random.choice(string.ascii_letters) for x in range(200)))
224 try:
225 if not os.path.exists(filepath):
226 bb.utils.mkdirhier(filepath)
227 f = open(testfile, "w")
228 f.close()
229 os.remove(testfile)
230 except IOError as e:
231 import errno
232 err, strerror = e.args
233 if err == errno.ENAMETOOLONG:
234 return "Failed to create a file with a long name in %s. Please use a filesystem that does not unreasonably limit filename length.\n" % pathname
235 else:
236 return "Failed to create a file in %s: %s.\n" % (pathname, strerror)
237 except OSError as e:
238 errno, strerror = e.args
239 return "Failed to create %s directory in which to run long name sanity check: %s.\n" % (pathname, strerror)
240 return ""
241
242def check_path_length(filepath, pathname, limit):
243 if len(filepath) > limit:
244 return "The length of %s is longer than 410, this would cause unexpected errors, please use a shorter path.\n" % pathname
245 return ""
246
247def get_filesystem_id(path):
248 status, result = oe.utils.getstatusoutput("stat -f -c '%s' %s" % ("%t", path))
249 if status == 0:
250 return result
251 else:
252 bb.warn("Can't get the filesystem id of: %s" % path)
253 return None
254
255# Check that the path isn't located on nfs.
256def check_not_nfs(path, name):
257 # The nfs' filesystem id is 6969
258 if get_filesystem_id(path) == "6969":
259 return "The %s: %s can't be located on nfs.\n" % (name, path)
260 return ""
261
262# Check that path isn't a broken symlink
263def check_symlink(lnk, data):
264 if os.path.islink(lnk) and not os.path.exists(lnk):
265 raise_sanity_error("%s is a broken symlink." % lnk, data)
266
267def check_connectivity(d):
268 # URI's to check can be set in the CONNECTIVITY_CHECK_URIS variable
269 # using the same syntax as for SRC_URI. If the variable is not set
270 # the check is skipped
271 test_uris = (d.getVar('CONNECTIVITY_CHECK_URIS', True) or "").split()
272 retval = ""
273
274 # Only check connectivity if network enabled and the
275 # CONNECTIVITY_CHECK_URIS are set
276 network_enabled = not d.getVar('BB_NO_NETWORK', True)
277 check_enabled = len(test_uris)
278 # Take a copy of the data store and unset MIRRORS and PREMIRRORS
279 data = bb.data.createCopy(d)
280 data.delVar('PREMIRRORS')
281 data.delVar('MIRRORS')
282 if check_enabled and network_enabled:
283 try:
284 fetcher = bb.fetch2.Fetch(test_uris, data)
285 fetcher.checkstatus()
286 except Exception as err:
287 # Allow the message to be configured so that users can be
288 # pointed to a support mechanism.
289 msg = data.getVar('CONNECTIVITY_CHECK_MSG', True) or ""
290 if len(msg) == 0:
291 msg = "%s. Please ensure your network is configured correctly.\n" % err
292 retval = msg
293
294 return retval
295
296def check_supported_distro(sanity_data):
297 from fnmatch import fnmatch
298
299 tested_distros = sanity_data.getVar('SANITY_TESTED_DISTROS', True)
300 if not tested_distros:
301 return
302
303 try:
304 distro = oe.lsb.distro_identifier()
305 except Exception:
306 distro = None
307
308 if not distro:
309 bb.warn('Host distribution could not be determined; you may possibly experience unexpected failures. It is recommended that you use a tested distribution.')
310
311 for supported in [x.strip() for x in tested_distros.split('\\n')]:
312 if fnmatch(distro, supported):
313 return
314
315 bb.warn('Host distribution "%s" has not been validated with this version of the build system; you may possibly experience unexpected failures. It is recommended that you use a tested distribution.' % distro)
316
317# Checks we should only make if MACHINE is set correctly
318def check_sanity_validmachine(sanity_data):
319 messages = ""
320
321 # Check TUNE_ARCH is set
322 if sanity_data.getVar('TUNE_ARCH', True) == 'INVALID':
323 messages = messages + 'TUNE_ARCH is unset. Please ensure your MACHINE configuration includes a valid tune configuration file which will set this correctly.\n'
324
325 # Check TARGET_OS is set
326 if sanity_data.getVar('TARGET_OS', True) == 'INVALID':
327 messages = messages + 'Please set TARGET_OS directly, or choose a MACHINE or DISTRO that does so.\n'
328
329 # Check that we don't have duplicate entries in PACKAGE_ARCHS & that TUNE_PKGARCH is in PACKAGE_ARCHS
330 pkgarchs = sanity_data.getVar('PACKAGE_ARCHS', True)
331 tunepkg = sanity_data.getVar('TUNE_PKGARCH', True)
332 tunefound = False
333 seen = {}
334 dups = []
335
336 for pa in pkgarchs.split():
337 if seen.get(pa, 0) == 1:
338 dups.append(pa)
339 else:
340 seen[pa] = 1
341 if pa == tunepkg:
342 tunefound = True
343
344 if len(dups):
345 messages = messages + "Error, the PACKAGE_ARCHS variable contains duplicates. The following archs are listed more than once: %s" % " ".join(dups)
346
347 if tunefound == False:
348 messages = messages + "Error, the PACKAGE_ARCHS variable does not contain TUNE_PKGARCH (%s)." % tunepkg
349
350 return messages
351
352# Checks if necessary to add option march to host gcc
353def check_gcc_march(sanity_data):
354 result = True
355 message = ""
356
357 # Check if -march not in BUILD_CFLAGS
358 if sanity_data.getVar("BUILD_CFLAGS",True).find("-march") < 0:
359 result = False
360
361 # Construct a test file
362 f = open("gcc_test.c", "w")
363 f.write("int main (){ volatile int atomic = 2; __sync_bool_compare_and_swap (&atomic, 2, 3); return 0; }\n")
364 f.close()
365
366 # Check if GCC could work without march
367 if not result:
368 status,res = oe.utils.getstatusoutput("${BUILD_PREFIX}gcc gcc_test.c -o gcc_test")
369 if status == 0:
370 result = True;
371
372 if not result:
373 status,res = oe.utils.getstatusoutput("${BUILD_PREFIX}gcc -march=native gcc_test.c -o gcc_test")
374 if status == 0:
375 message = "BUILD_CFLAGS_append = \" -march=native\""
376 result = True;
377
378 if not result:
379 build_arch = sanity_data.getVar('BUILD_ARCH', True)
380 status,res = oe.utils.getstatusoutput("${BUILD_PREFIX}gcc -march=%s gcc_test.c -o gcc_test" % build_arch)
381 if status == 0:
382 message = "BUILD_CFLAGS_append = \" -march=%s\"" % build_arch
383 result = True;
384
385 os.remove("gcc_test.c")
386 if os.path.exists("gcc_test"):
387 os.remove("gcc_test")
388
389 return (result, message)
390
391# Unpatched versions of make 3.82 are known to be broken. See GNU Savannah Bug 30612.
392# Use a modified reproducer from http://savannah.gnu.org/bugs/?30612 to validate.
393def check_make_version(sanity_data):
394 from distutils.version import LooseVersion
395 status, result = oe.utils.getstatusoutput("make --version")
396 if status != 0:
397 return "Unable to execute make --version, exit code %s\n" % status
398 version = result.split()[2]
399 if LooseVersion(version) == LooseVersion("3.82"):
400 # Construct a test file
401 f = open("makefile_test", "w")
402 f.write("makefile_test.a: makefile_test_a.c makefile_test_b.c makefile_test.a( makefile_test_a.c makefile_test_b.c)\n")
403 f.write("\n")
404 f.write("makefile_test_a.c:\n")
405 f.write(" touch $@\n")
406 f.write("\n")
407 f.write("makefile_test_b.c:\n")
408 f.write(" touch $@\n")
409 f.close()
410
411 # Check if make 3.82 has been patched
412 status,result = oe.utils.getstatusoutput("make -f makefile_test")
413
414 os.remove("makefile_test")
415 if os.path.exists("makefile_test_a.c"):
416 os.remove("makefile_test_a.c")
417 if os.path.exists("makefile_test_b.c"):
418 os.remove("makefile_test_b.c")
419 if os.path.exists("makefile_test.a"):
420 os.remove("makefile_test.a")
421
422 if status != 0:
423 return "Your version of make 3.82 is broken. Please revert to 3.81 or install a patched version.\n"
424 return None
425
426
427# Tar version 1.24 and onwards handle overwriting symlinks correctly
428# but earlier versions do not; this needs to work properly for sstate
429def check_tar_version(sanity_data):
430 from distutils.version import LooseVersion
431 status, result = oe.utils.getstatusoutput("tar --version")
432 if status != 0:
433 return "Unable to execute tar --version, exit code %s\n" % status
434 version = result.split()[3]
435 if LooseVersion(version) < LooseVersion("1.24"):
436 return "Your version of tar is older than 1.24 and has bugs which will break builds. Please install a newer version of tar.\n"
437 return None
438
439# We use git parameters and functionality only found in 1.7.8 or later
440def check_git_version(sanity_data):
441 from distutils.version import LooseVersion
442 status, result = oe.utils.getstatusoutput("git --version 2> /dev/null")
443 if status != 0:
444 return "Unable to execute git --version, exit code %s\n" % status
445 version = result.split()[2]
446 if LooseVersion(version) < LooseVersion("1.7.8"):
447 return "Your version of git is older than 1.7.8 and has bugs which will break builds. Please install a newer version of git.\n"
448 return None
449
450# Check the required perl modules which may not be installed by default
451def check_perl_modules(sanity_data):
452 ret = ""
453 modules = ( "Text::ParseWords", "Thread::Queue", "Data::Dumper" )
454 for m in modules:
455 status, result = oe.utils.getstatusoutput("perl -e 'use %s' 2> /dev/null" % m)
456 if status != 0:
457 ret += "%s " % m
458 if ret:
459 return "Required perl module(s) not found: %s\n" % ret
460 return None
461
462def sanity_check_conffiles(status, d):
463 # Check we are using a valid local.conf
464 current_conf = d.getVar('CONF_VERSION', True)
465 conf_version = d.getVar('LOCALCONF_VERSION', True)
466
467 if current_conf != conf_version:
468 status.addresult("Your version of local.conf was generated from an older/newer version of local.conf.sample and there have been updates made to this file. Please compare the two files and merge any changes before continuing.\nMatching the version numbers will remove this message.\n\"meld conf/local.conf ${COREBASE}/meta*/conf/local.conf.sample\" is a good way to visualise the changes.\n")
469
470 # Check bblayers.conf is valid
471 current_lconf = d.getVar('LCONF_VERSION', True)
472 lconf_version = d.getVar('LAYER_CONF_VERSION', True)
473 if current_lconf != lconf_version:
474 funcs = d.getVar('BBLAYERS_CONF_UPDATE_FUNCS', True).split()
475 for func in funcs:
476 success = True
477 try:
478 bb.build.exec_func(func, d)
479 except Exception:
480 success = False
481 if success:
482 bb.note("Your conf/bblayers.conf has been automatically updated.")
483 status.reparse = True
484 if not status.reparse:
485 status.addresult("Your version of bblayers.conf has the wrong LCONF_VERSION (has %s, expecting %s).\nPlease compare the your file against bblayers.conf.sample and merge any changes before continuing.\n\"meld conf/bblayers.conf ${COREBASE}/meta*/conf/bblayers.conf.sample\" is a good way to visualise the changes.\n" % (current_lconf, lconf_version))
486
487 # If we have a site.conf, check it's valid
488 if check_conf_exists("conf/site.conf", d):
489 current_sconf = d.getVar('SCONF_VERSION', True)
490 sconf_version = d.getVar('SITE_CONF_VERSION', True)
491 if current_sconf != sconf_version:
492 status.addresult("Your version of site.conf was generated from an older version of site.conf.sample and there have been updates made to this file. Please compare the two files and merge any changes before continuing.\nMatching the version numbers will remove this message.\n\"meld conf/site.conf ${COREBASE}/meta*/conf/site.conf.sample\" is a good way to visualise the changes.\n")
493
494
495def sanity_handle_abichanges(status, d):
496 #
497 # Check the 'ABI' of TMPDIR
498 #
499 import subprocess
500
501 current_abi = d.getVar('OELAYOUT_ABI', True)
502 abifile = d.getVar('SANITY_ABIFILE', True)
503 if os.path.exists(abifile):
504 with open(abifile, "r") as f:
505 abi = f.read().strip()
506 if not abi.isdigit():
507 with open(abifile, "w") as f:
508 f.write(current_abi)
509 elif abi == "2" and current_abi == "3":
510 bb.note("Converting staging from layout version 2 to layout version 3")
511 subprocess.call(d.expand("mv ${TMPDIR}/staging ${TMPDIR}/sysroots"), shell=True)
512 subprocess.call(d.expand("ln -s sysroots ${TMPDIR}/staging"), shell=True)
513 subprocess.call(d.expand("cd ${TMPDIR}/stamps; for i in */*do_populate_staging; do new=`echo $i | sed -e 's/do_populate_staging/do_populate_sysroot/'`; mv $i $new; done"), shell=True)
514 with open(abifile, "w") as f:
515 f.write(current_abi)
516 elif abi == "3" and current_abi == "4":
517 bb.note("Converting staging layout from version 3 to layout version 4")
518 if os.path.exists(d.expand("${STAGING_DIR_NATIVE}${bindir_native}/${MULTIMACH_HOST_SYS}")):
519 subprocess.call(d.expand("mv ${STAGING_DIR_NATIVE}${bindir_native}/${MULTIMACH_HOST_SYS} ${STAGING_BINDIR_CROSS}"), shell=True)
520 subprocess.call(d.expand("ln -s ${STAGING_BINDIR_CROSS} ${STAGING_DIR_NATIVE}${bindir_native}/${MULTIMACH_HOST_SYS}"), shell=True)
521 with open(abifile, "w") as f:
522 f.write(current_abi)
523 elif abi == "4":
524 status.addresult("Staging layout has changed. The cross directory has been deprecated and cross packages are now built under the native sysroot.\nThis requires a rebuild.\n")
525 elif abi == "5" and current_abi == "6":
526 bb.note("Converting staging layout from version 5 to layout version 6")
527 subprocess.call(d.expand("mv ${TMPDIR}/pstagelogs ${SSTATE_MANIFESTS}"), shell=True)
528 with open(abifile, "w") as f:
529 f.write(current_abi)
530 elif abi == "7" and current_abi == "8":
531 status.addresult("Your configuration is using stamp files including the sstate hash but your build directory was built with stamp files that do not include this.\nTo continue, either rebuild or switch back to the OEBasic signature handler with BB_SIGNATURE_HANDLER = 'OEBasic'.\n")
532 elif (abi != current_abi and current_abi == "9"):
533 status.addresult("The layout of the TMPDIR STAMPS directory has changed. Please clean out TMPDIR and rebuild (sstate will be still be valid and reused)\n")
534 elif (abi != current_abi and current_abi == "10" and (abi == "8" or abi == "9")):
535 bb.note("Converting staging layout from version 8/9 to layout version 10")
536 cmd = d.expand("grep -r -l sysroot-providers/virtual_kernel ${SSTATE_MANIFESTS}")
537 ret, result = oe.utils.getstatusoutput(cmd)
538 result = result.split()
539 for f in result:
540 bb.note("Uninstalling manifest file %s" % f)
541 sstate_clean_manifest(f, d)
542 with open(abifile, "w") as f:
543 f.write(current_abi)
544 elif abi == "10" and current_abi == "11":
545 bb.note("Converting staging layout from version 10 to layout version 11")
546 # Files in xf86-video-modesetting moved to xserver-xorg and bitbake can't currently handle that:
547 subprocess.call(d.expand("rm ${TMPDIR}/sysroots/*/usr/lib/xorg/modules/drivers/modesetting_drv.so ${TMPDIR}/sysroots/*/pkgdata/runtime/xf86-video-modesetting* ${TMPDIR}/sysroots/*/pkgdata/runtime-reverse/xf86-video-modesetting* ${TMPDIR}/sysroots/*/pkgdata/shlibs2/xf86-video-modesetting*"), shell=True)
548 with open(abifile, "w") as f:
549 f.write(current_abi)
550 elif (abi != current_abi):
551 # Code to convert from one ABI to another could go here if possible.
552 status.addresult("Error, TMPDIR has changed its layout version number (%s to %s) and you need to either rebuild, revert or adjust it at your own risk.\n" % (abi, current_abi))
553 else:
554 with open(abifile, "w") as f:
555 f.write(current_abi)
556
557def check_sanity_sstate_dir_change(sstate_dir, data):
558 # Sanity checks to be done when the value of SSTATE_DIR changes
559
560 # Check that SSTATE_DIR isn't on a filesystem with limited filename length (eg. eCryptFS)
561 testmsg = ""
562 if sstate_dir != "":
563 testmsg = check_create_long_filename(sstate_dir, "SSTATE_DIR")
564 # If we don't have permissions to SSTATE_DIR, suggest the user set it as an SSTATE_MIRRORS
565 try:
566 err = testmsg.split(': ')[1].strip()
567 if err == "Permission denied.":
568 testmsg = testmsg + "You could try using %s in SSTATE_MIRRORS rather than as an SSTATE_CACHE.\n" % (sstate_dir)
569 except IndexError:
570 pass
571 return testmsg
572
573def check_sanity_version_change(status, d):
574 # Sanity checks to be done when SANITY_VERSION changes
575 # In other words, these tests run once in a given build directory and then
576 # never again until the sanity version changes.
577
578 # Check the python install is complete. glib-2.0-natives requries
579 # xml.parsers.expat
580 try:
581 import xml.parsers.expat
582 except ImportError:
583 status.addresult('Your python is not a full install. Please install the module xml.parsers.expat (python-xml on openSUSE and SUSE Linux).\n')
584 import stat
585
586 status.addresult(check_make_version(d))
587 status.addresult(check_tar_version(d))
588 status.addresult(check_git_version(d))
589 status.addresult(check_perl_modules(d))
590
591 missing = ""
592
593 if not check_app_exists("${MAKE}", d):
594 missing = missing + "GNU make,"
595
596 if not check_app_exists('${BUILD_PREFIX}gcc', d):
597 missing = missing + "C Compiler (%sgcc)," % d.getVar("BUILD_PREFIX", True)
598
599 if not check_app_exists('${BUILD_PREFIX}g++', d):
600 missing = missing + "C++ Compiler (%sg++)," % d.getVar("BUILD_PREFIX", True)
601
602 required_utilities = d.getVar('SANITY_REQUIRED_UTILITIES', True)
603
604 for util in required_utilities.split():
605 if not check_app_exists(util, d):
606 missing = missing + "%s," % util
607
608 if missing:
609 missing = missing.rstrip(',')
610 status.addresult("Please install the following missing utilities: %s\n" % missing)
611
612 assume_provided = d.getVar('ASSUME_PROVIDED', True).split()
613 # Check user doesn't have ASSUME_PROVIDED = instead of += in local.conf
614 if "diffstat-native" not in assume_provided:
615 status.addresult('Please use ASSUME_PROVIDED +=, not ASSUME_PROVIDED = in your local.conf\n')
616
617 if "qemu-native" in assume_provided:
618 if not check_app_exists("qemu-arm", d):
619 status.addresult("qemu-native was in ASSUME_PROVIDED but the QEMU binaries (qemu-arm) can't be found in PATH")
620
621 if "libsdl-native" in assume_provided:
622 if not check_app_exists("sdl-config", d):
623 status.addresult("libsdl-native is set to be ASSUME_PROVIDED but sdl-config can't be found in PATH. Please either install it, or configure qemu not to require sdl.")
624
625 (result, message) = check_gcc_march(d)
626 if result and message:
627 status.addresult("Your gcc version is older than 4.5, please add the following param to local.conf\n \
628 %s\n" % message)
629 if not result:
630 status.addresult("Your gcc version is older than 4.5 or is not working properly. Please verify you can build")
631 status.addresult(" and link something that uses atomic operations, such as: \n")
632 status.addresult(" __sync_bool_compare_and_swap (&atomic, 2, 3);\n")
633
634 # Check that TMPDIR isn't on a filesystem with limited filename length (eg. eCryptFS)
635 tmpdir = d.getVar('TMPDIR', True)
636 status.addresult(check_create_long_filename(tmpdir, "TMPDIR"))
637 tmpdirmode = os.stat(tmpdir).st_mode
638 if (tmpdirmode & stat.S_ISGID):
639 status.addresult("TMPDIR is setgid, please don't build in a setgid directory")
640 if (tmpdirmode & stat.S_ISUID):
641 status.addresult("TMPDIR is setuid, please don't build in a setuid directory")
642
643 # Some third-party software apparently relies on chmod etc. being suid root (!!)
644 import stat
645 suid_check_bins = "chown chmod mknod".split()
646 for bin_cmd in suid_check_bins:
647 bin_path = bb.utils.which(os.environ["PATH"], bin_cmd)
648 if bin_path:
649 bin_stat = os.stat(bin_path)
650 if bin_stat.st_uid == 0 and bin_stat.st_mode & stat.S_ISUID:
651 status.addresult('%s has the setuid bit set. This interferes with pseudo and may cause other issues that break the build process.\n' % bin_path)
652
653 # Check that we can fetch from various network transports
654 netcheck = check_connectivity(d)
655 status.addresult(netcheck)
656 if netcheck:
657 status.network_error = True
658
659 nolibs = d.getVar('NO32LIBS', True)
660 if not nolibs:
661 lib32path = '/lib'
662 if os.path.exists('/lib64') and ( os.path.islink('/lib64') or os.path.islink('/lib') ):
663 lib32path = '/lib32'
664
665 if os.path.exists('%s/libc.so.6' % lib32path) and not os.path.exists('/usr/include/gnu/stubs-32.h'):
666 status.addresult("You have a 32-bit libc, but no 32-bit headers. You must install the 32-bit libc headers.\n")
667
668 bbpaths = d.getVar('BBPATH', True).split(":")
669 if ("." in bbpaths or "./" in bbpaths or "" in bbpaths) and not status.reparse:
670 status.addresult("BBPATH references the current directory, either through " \
671 "an empty entry, a './' or a '.'.\n\t This is unsafe and means your "\
672 "layer configuration is adding empty elements to BBPATH.\n\t "\
673 "Please check your layer.conf files and other BBPATH " \
674 "settings to remove the current working directory " \
675 "references.\n" \
676 "Parsed BBPATH is" + str(bbpaths));
677
678 oes_bb_conf = d.getVar( 'OES_BITBAKE_CONF', True)
679 if not oes_bb_conf:
680 status.addresult('You are not using the OpenEmbedded version of conf/bitbake.conf. This means your environment is misconfigured, in particular check BBPATH.\n')
681
682 # The length of TMPDIR can't be longer than 410
683 status.addresult(check_path_length(tmpdir, "TMPDIR", 410))
684
685 # Check that TMPDIR isn't located on nfs
686 status.addresult(check_not_nfs(tmpdir, "TMPDIR"))
687
688def check_sanity_everybuild(status, d):
689 import os, stat
690 # Sanity tests which test the users environment so need to run at each build (or are so cheap
691 # it makes sense to always run them.
692
693 if 0 == os.getuid():
694 raise_sanity_error("Do not use Bitbake as root.", d)
695
696 # Check the Python version, we now have a minimum of Python 2.7.3
697 import sys
698 if sys.hexversion < 0x020703F0:
699 status.addresult('The system requires at least Python 2.7.3 to run. Please update your Python interpreter.\n')
700
701 # Check the bitbake version meets minimum requirements
702 from distutils.version import LooseVersion
703 minversion = d.getVar('BB_MIN_VERSION', True)
704 if (LooseVersion(bb.__version__) < LooseVersion(minversion)):
705 status.addresult('Bitbake version %s is required and version %s was found\n' % (minversion, bb.__version__))
706
707 sanity_check_conffiles(status, d)
708
709 paths = d.getVar('PATH', True).split(":")
710 if "." in paths or "./" in paths or "" in paths:
711 status.addresult("PATH contains '.', './' or '' (empty element), which will break the build, please remove this.\nParsed PATH is " + str(paths) + "\n")
712
713 # Check that the DISTRO is valid, if set
714 # need to take into account DISTRO renaming DISTRO
715 distro = d.getVar('DISTRO', True)
716 if distro and distro != "nodistro":
717 if not ( check_conf_exists("conf/distro/${DISTRO}.conf", d) or check_conf_exists("conf/distro/include/${DISTRO}.inc", d) ):
718 status.addresult("DISTRO '%s' not found. Please set a valid DISTRO in your local.conf\n" % d.getVar("DISTRO", True))
719
720 # Check that DL_DIR is set, exists and is writable. In theory, we should never even hit the check if DL_DIR isn't
721 # set, since so much relies on it being set.
722 dldir = d.getVar('DL_DIR', True)
723 if not dldir:
724 status.addresult("DL_DIR is not set. Your environment is misconfigured, check that DL_DIR is set, and if the directory exists, that it is writable. \n")
725 if os.path.exists(dldir) and not os.access(dldir, os.W_OK):
726 status.addresult("DL_DIR: %s exists but you do not appear to have write access to it. \n" % dldir)
727 check_symlink(dldir, d)
728
729 # Check that the MACHINE is valid, if it is set
730 machinevalid = True
731 if d.getVar('MACHINE', True):
732 if not check_conf_exists("conf/machine/${MACHINE}.conf", d):
733 status.addresult('Please set a valid MACHINE in your local.conf or environment\n')
734 machinevalid = False
735 else:
736 status.addresult(check_sanity_validmachine(d))
737 else:
738 status.addresult('Please set a MACHINE in your local.conf or environment\n')
739 machinevalid = False
740 if machinevalid:
741 status.addresult(check_toolchain(d))
742
743 # Check that the SDKMACHINE is valid, if it is set
744 if d.getVar('SDKMACHINE', True):
745 if not check_conf_exists("conf/machine-sdk/${SDKMACHINE}.conf", d):
746 status.addresult('Specified SDKMACHINE value is not valid\n')
747 elif d.getVar('SDK_ARCH', False) == "${BUILD_ARCH}":
748 status.addresult('SDKMACHINE is set, but SDK_ARCH has not been changed as a result - SDKMACHINE may have been set too late (e.g. in the distro configuration)\n')
749
750 check_supported_distro(d)
751
752 # Check if DISPLAY is set if TEST_IMAGE is set
753 if d.getVar('TEST_IMAGE', True) == '1' or d.getVar('DEFAULT_TEST_SUITES', True):
754 testtarget = d.getVar('TEST_TARGET', True)
755 if testtarget == 'qemu' or testtarget == 'QemuTarget':
756 display = d.getVar("BB_ORIGENV", False).getVar("DISPLAY", True)
757 if not display:
758 status.addresult('testimage needs an X desktop to start qemu, please set DISPLAY correctly (e.g. DISPLAY=:1.0)\n')
759
760 omask = os.umask(022)
761 if omask & 0755:
762 status.addresult("Please use a umask which allows a+rx and u+rwx\n")
763 os.umask(omask)
764
765 if d.getVar('TARGET_ARCH', True) == "arm":
766 # This path is no longer user-readable in modern (very recent) Linux
767 try:
768 if os.path.exists("/proc/sys/vm/mmap_min_addr"):
769 f = open("/proc/sys/vm/mmap_min_addr", "r")
770 try:
771 if (int(f.read().strip()) > 65536):
772 status.addresult("/proc/sys/vm/mmap_min_addr is not <= 65536. This will cause problems with qemu so please fix the value (as root).\n\nTo fix this in later reboots, set vm.mmap_min_addr = 65536 in /etc/sysctl.conf.\n")
773 finally:
774 f.close()
775 except:
776 pass
777
778 oeroot = d.getVar('COREBASE', True)
779 if oeroot.find('+') != -1:
780 status.addresult("Error, you have an invalid character (+) in your COREBASE directory path. Please move the installation to a directory which doesn't include any + characters.")
781 if oeroot.find('@') != -1:
782 status.addresult("Error, you have an invalid character (@) in your COREBASE directory path. Please move the installation to a directory which doesn't include any @ characters.")
783 if oeroot.find(' ') != -1:
784 status.addresult("Error, you have a space in your COREBASE directory path. Please move the installation to a directory which doesn't include a space since autotools doesn't support this.")
785
786 # Check the format of MIRRORS, PREMIRRORS and SSTATE_MIRRORS
787 import re
788 mirror_vars = ['MIRRORS', 'PREMIRRORS', 'SSTATE_MIRRORS']
789 protocols = ['http', 'ftp', 'file', 'https', \
790 'git', 'gitsm', 'hg', 'osc', 'p4', 'svn', \
791 'bzr', 'cvs']
792 for mirror_var in mirror_vars:
793 mirrors = (d.getVar(mirror_var, True) or '').replace('\\n', '\n').split('\n')
794 for mirror_entry in mirrors:
795 mirror_entry = mirror_entry.strip()
796 if not mirror_entry:
797 # ignore blank lines
798 continue
799
800 try:
801 pattern, mirror = mirror_entry.split()
802 except ValueError:
803 bb.warn('Invalid %s: %s, should be 2 members.' % (mirror_var, mirror_entry.strip()))
804 continue
805
806 decoded = bb.fetch2.decodeurl(pattern)
807 try:
808 pattern_scheme = re.compile(decoded[0])
809 except re.error as exc:
810 bb.warn('Invalid scheme regex (%s) in %s; %s' % (pattern, mirror_var, mirror_entry))
811 continue
812
813 if not any(pattern_scheme.match(protocol) for protocol in protocols):
814 bb.warn('Invalid protocol (%s) in %s: %s' % (decoded[0], mirror_var, mirror_entry))
815 continue
816
817 if not any(mirror.startswith(protocol + '://') for protocol in protocols):
818 bb.warn('Invalid protocol in %s: %s' % (mirror_var, mirror_entry))
819 continue
820
821 if mirror.startswith('file://'):
822 import urlparse
823 check_symlink(urlparse.urlparse(mirror).path, d)
824 # SSTATE_MIRROR ends with a /PATH string
825 if mirror.endswith('/PATH'):
826 # remove /PATH$ from SSTATE_MIRROR to get a working
827 # base directory path
828 mirror_base = urlparse.urlparse(mirror[:-1*len('/PATH')]).path
829 check_symlink(mirror_base, d)
830
831 # Check that TMPDIR hasn't changed location since the last time we were run
832 tmpdir = d.getVar('TMPDIR', True)
833 checkfile = os.path.join(tmpdir, "saved_tmpdir")
834 if os.path.exists(checkfile):
835 with open(checkfile, "r") as f:
836 saved_tmpdir = f.read().strip()
837 if (saved_tmpdir != tmpdir):
838 status.addresult("Error, TMPDIR has changed location. You need to either move it back to %s or rebuild\n" % saved_tmpdir)
839 else:
840 bb.utils.mkdirhier(tmpdir)
841 # Remove setuid, setgid and sticky bits from TMPDIR
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500842 try:
843 os.chmod(tmpdir, os.stat(tmpdir).st_mode & ~ stat.S_ISUID)
844 os.chmod(tmpdir, os.stat(tmpdir).st_mode & ~ stat.S_ISGID)
845 os.chmod(tmpdir, os.stat(tmpdir).st_mode & ~ stat.S_ISVTX)
846 except OSError as exc:
847 bb.warn("Unable to chmod TMPDIR: %s" % exc)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500848 with open(checkfile, "w") as f:
849 f.write(tmpdir)
850
851 # Check vmdk and live can't be built together.
852 if 'vmdk' in d.getVar('IMAGE_FSTYPES', True) and 'live' in d.getVar('IMAGE_FSTYPES', True):
853 status.addresult("Error, IMAGE_FSTYPES vmdk and live can't be built together\n")
854
855 # Check vdi and live can't be built together.
856 if 'vdi' in d.getVar('IMAGE_FSTYPES', True) and 'live' in d.getVar('IMAGE_FSTYPES', True):
857 status.addresult("Error, IMAGE_FSTYPES vdi and live can't be built together\n")
858
859 # Check qcow2 and live can't be built together.
860 if 'qcow2' in d.getVar('IMAGE_FSTYPES', True) and 'live' in d.getVar('IMAGE_FSTYPES', True):
861 status.addresult("Error, IMAGE_FSTYPES qcow2 and live can't be built together\n")
862
863 # Check /bin/sh links to dash or bash
864 real_sh = os.path.realpath('/bin/sh')
865 if not real_sh.endswith('/dash') and not real_sh.endswith('/bash'):
866 status.addresult("Error, /bin/sh links to %s, must be dash or bash\n" % real_sh)
867
868def check_sanity(sanity_data):
869 class SanityStatus(object):
870 def __init__(self):
871 self.messages = ""
872 self.network_error = False
873 self.reparse = False
874
875 def addresult(self, message):
876 if message:
877 self.messages = self.messages + message
878
879 status = SanityStatus()
880
881 tmpdir = sanity_data.getVar('TMPDIR', True)
882 sstate_dir = sanity_data.getVar('SSTATE_DIR', True)
883
884 check_symlink(sstate_dir, sanity_data)
885
886 # Check saved sanity info
887 last_sanity_version = 0
888 last_tmpdir = ""
889 last_sstate_dir = ""
890 sanityverfile = sanity_data.expand("${TOPDIR}/conf/sanity_info")
891 if os.path.exists(sanityverfile):
892 with open(sanityverfile, 'r') as f:
893 for line in f:
894 if line.startswith('SANITY_VERSION'):
895 last_sanity_version = int(line.split()[1])
896 if line.startswith('TMPDIR'):
897 last_tmpdir = line.split()[1]
898 if line.startswith('SSTATE_DIR'):
899 last_sstate_dir = line.split()[1]
900
901 check_sanity_everybuild(status, sanity_data)
902
903 sanity_version = int(sanity_data.getVar('SANITY_VERSION', True) or 1)
904 network_error = False
905 if last_sanity_version < sanity_version:
906 check_sanity_version_change(status, sanity_data)
907 status.addresult(check_sanity_sstate_dir_change(sstate_dir, sanity_data))
908 else:
909 if last_sstate_dir != sstate_dir:
910 status.addresult(check_sanity_sstate_dir_change(sstate_dir, sanity_data))
911
912 if os.path.exists(os.path.dirname(sanityverfile)) and not status.messages:
913 with open(sanityverfile, 'w') as f:
914 f.write("SANITY_VERSION %s\n" % sanity_version)
915 f.write("TMPDIR %s\n" % tmpdir)
916 f.write("SSTATE_DIR %s\n" % sstate_dir)
917
918 sanity_handle_abichanges(status, sanity_data)
919
920 if status.messages != "":
921 raise_sanity_error(sanity_data.expand(status.messages), sanity_data, status.network_error)
922 return status.reparse
923
924# Create a copy of the datastore and finalise it to ensure appends and
925# overrides are set - the datastore has yet to be finalised at ConfigParsed
926def copy_data(e):
927 sanity_data = bb.data.createCopy(e.data)
928 sanity_data.finalize()
929 return sanity_data
930
931addhandler check_sanity_eventhandler
932check_sanity_eventhandler[eventmask] = "bb.event.SanityCheck bb.event.NetworkTest"
933python check_sanity_eventhandler() {
934 if bb.event.getName(e) == "SanityCheck":
935 sanity_data = copy_data(e)
936 if e.generateevents:
937 sanity_data.setVar("SANITY_USE_EVENTS", "1")
938 reparse = check_sanity(sanity_data)
939 e.data.setVar("BB_INVALIDCONF", reparse)
940 bb.event.fire(bb.event.SanityCheckPassed(), e.data)
941 elif bb.event.getName(e) == "NetworkTest":
942 sanity_data = copy_data(e)
943 if e.generateevents:
944 sanity_data.setVar("SANITY_USE_EVENTS", "1")
945 bb.event.fire(bb.event.NetworkTestFailed() if check_connectivity(sanity_data) else bb.event.NetworkTestPassed(), e.data)
946
947 return
948}