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