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