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