blob: b416918013c1c4fb0cf4cdf2e6d66fa6b11e2699 [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001#
2# Sanity check the users setup for common misconfigurations
3#
4
Andrew Geissler82c905d2020-04-13 13:39:40 -05005SANITY_REQUIRED_UTILITIES ?= "patch diffstat git bzip2 tar \
Brad Bishop6e60e8b2018-02-01 10:27:11 -05006 gzip gawk chrpath wget cpio perl file which"
Patrick Williamsc124f4f2015-09-15 14:41:29 -05007
8def bblayers_conf_file(d):
Brad Bishop6e60e8b2018-02-01 10:27:11 -05009 return os.path.join(d.getVar('TOPDIR'), 'conf/bblayers.conf')
Patrick Williamsc124f4f2015-09-15 14:41:29 -050010
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):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050023 index, line = sanity_conf_find_line(r"^%s" % version_var_name, lines)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050024 lines[index] = '%s = "%d"\n' % (version_var_name, new_version)
25 with open(fn, "w") as f:
26 f.write(''.join(lines))
27
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050028# Functions added to this variable MUST throw a NotImplementedError exception unless
29# they successfully changed the config version in the config file. Exceptions
30# are used since exec_func doesn't handle return values.
31BBLAYERS_CONF_UPDATE_FUNCS += " \
32 conf/bblayers.conf:LCONF_VERSION:LAYER_CONF_VERSION:oecore_update_bblayers \
33 conf/local.conf:CONF_VERSION:LOCALCONF_VERSION:oecore_update_localconf \
34 conf/site.conf:SCONF_VERSION:SITE_CONF_VERSION:oecore_update_siteconf \
35"
Patrick Williamsc124f4f2015-09-15 14:41:29 -050036
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050037SANITY_DIFF_TOOL ?= "meld"
38
39SANITY_LOCALCONF_SAMPLE ?= "${COREBASE}/meta*/conf/local.conf.sample"
40python oecore_update_localconf() {
41 # Check we are using a valid local.conf
Brad Bishop6e60e8b2018-02-01 10:27:11 -050042 current_conf = d.getVar('CONF_VERSION')
43 conf_version = d.getVar('LOCALCONF_VERSION')
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050044
45 failmsg = """Your version of local.conf was generated from an older/newer version of
46local.conf.sample and there have been updates made to this file. Please compare the two
47files and merge any changes before continuing.
48
49Matching the version numbers will remove this message.
50
51\"${SANITY_DIFF_TOOL} conf/local.conf ${SANITY_LOCALCONF_SAMPLE}\"
52
53is a good way to visualise the changes."""
54 failmsg = d.expand(failmsg)
55
56 raise NotImplementedError(failmsg)
57}
58
59SANITY_SITECONF_SAMPLE ?= "${COREBASE}/meta*/conf/site.conf.sample"
60python oecore_update_siteconf() {
61 # If we have a site.conf, check it's valid
Brad Bishop6e60e8b2018-02-01 10:27:11 -050062 current_sconf = d.getVar('SCONF_VERSION')
63 sconf_version = d.getVar('SITE_CONF_VERSION')
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050064
65 failmsg = """Your version of site.conf was generated from an older version of
66site.conf.sample and there have been updates made to this file. Please compare the two
67files and merge any changes before continuing.
68
69Matching the version numbers will remove this message.
70
71\"${SANITY_DIFF_TOOL} conf/site.conf ${SANITY_SITECONF_SAMPLE}\"
72
73is a good way to visualise the changes."""
74 failmsg = d.expand(failmsg)
75
76 raise NotImplementedError(failmsg)
77}
78
79SANITY_BBLAYERCONF_SAMPLE ?= "${COREBASE}/meta*/conf/bblayers.conf.sample"
Patrick Williamsc124f4f2015-09-15 14:41:29 -050080python oecore_update_bblayers() {
81 # bblayers.conf is out of date, so see if we can resolve that
82
Brad Bishop6e60e8b2018-02-01 10:27:11 -050083 current_lconf = int(d.getVar('LCONF_VERSION'))
84 lconf_version = int(d.getVar('LAYER_CONF_VERSION'))
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050085
86 failmsg = """Your version of bblayers.conf has the wrong LCONF_VERSION (has ${LCONF_VERSION}, expecting ${LAYER_CONF_VERSION}).
87Please compare your file against bblayers.conf.sample and merge any changes before continuing.
88"${SANITY_DIFF_TOOL} conf/bblayers.conf ${SANITY_BBLAYERCONF_SAMPLE}"
89
90is a good way to visualise the changes."""
91 failmsg = d.expand(failmsg)
92
93 if not current_lconf:
94 raise NotImplementedError(failmsg)
95
Patrick Williamsc124f4f2015-09-15 14:41:29 -050096 lines = []
97
98 if current_lconf < 4:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050099 raise NotImplementedError(failmsg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500100
101 bblayers_fn = bblayers_conf_file(d)
102 lines = sanity_conf_read(bblayers_fn)
103
104 if current_lconf == 4 and lconf_version > 4:
105 topdir_var = '$' + '{TOPDIR}'
106 index, bbpath_line = sanity_conf_find_line('BBPATH', lines)
107 if bbpath_line:
108 start = bbpath_line.find('"')
109 if start != -1 and (len(bbpath_line) != (start + 1)):
110 if bbpath_line[start + 1] == '"':
111 lines[index] = (bbpath_line[:start + 1] +
112 topdir_var + bbpath_line[start + 1:])
113 else:
114 if not topdir_var in bbpath_line:
115 lines[index] = (bbpath_line[:start + 1] +
116 topdir_var + ':' + bbpath_line[start + 1:])
117 else:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500118 raise NotImplementedError(failmsg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500119 else:
120 index, bbfiles_line = sanity_conf_find_line('BBFILES', lines)
121 if bbfiles_line:
122 lines.insert(index, 'BBPATH = "' + topdir_var + '"\n')
123 else:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500124 raise NotImplementedError(failmsg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500125
126 current_lconf += 1
127 sanity_conf_update(bblayers_fn, lines, 'LCONF_VERSION', current_lconf)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500128 bb.note("Your conf/bblayers.conf has been automatically updated.")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500129 return
130
131 elif current_lconf == 5 and lconf_version > 5:
132 # Null update, to avoid issues with people switching between poky and other distros
133 current_lconf = 6
134 sanity_conf_update(bblayers_fn, lines, 'LCONF_VERSION', current_lconf)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500135 bb.note("Your conf/bblayers.conf has been automatically updated.")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500136 return
137
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600138 status.addresult()
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500139
140 elif current_lconf == 6 and lconf_version > 6:
141 # Handle rename of meta-yocto -> meta-poky
142 # This marks the start of separate version numbers but code is needed in OE-Core
143 # for the migration, one last time.
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500144 layers = d.getVar('BBLAYERS').split()
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500145 layers = [ os.path.basename(path) for path in layers ]
146 if 'meta-yocto' in layers:
147 found = False
148 while True:
149 index, meta_yocto_line = sanity_conf_find_line(r'.*meta-yocto[\'"\s\n]', lines)
150 if meta_yocto_line:
151 lines[index] = meta_yocto_line.replace('meta-yocto', 'meta-poky')
152 found = True
153 else:
154 break
155 if not found:
156 raise NotImplementedError(failmsg)
157 index, meta_yocto_line = sanity_conf_find_line('LCONF_VERSION.*\n', lines)
158 if meta_yocto_line:
159 lines[index] = 'POKY_BBLAYERS_CONF_VERSION = "1"\n'
160 else:
161 raise NotImplementedError(failmsg)
162 with open(bblayers_fn, "w") as f:
163 f.write(''.join(lines))
164 bb.note("Your conf/bblayers.conf has been automatically updated.")
165 return
166 current_lconf += 1
167 sanity_conf_update(bblayers_fn, lines, 'LCONF_VERSION', current_lconf)
168 bb.note("Your conf/bblayers.conf has been automatically updated.")
169 return
170
171 raise NotImplementedError(failmsg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500172}
173
174def raise_sanity_error(msg, d, network_error=False):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500175 if d.getVar("SANITY_USE_EVENTS") == "1":
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500176 try:
177 bb.event.fire(bb.event.SanityCheckFailed(msg, network_error), d)
178 except TypeError:
179 bb.event.fire(bb.event.SanityCheckFailed(msg), d)
180 return
181
182 bb.fatal(""" OE-core's config sanity checker detected a potential misconfiguration.
183 Either fix the cause of this error or at your own risk disable the checker (see sanity.conf).
184 Following is the list of potential problems / advisories:
185
186 %s""" % msg)
187
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500188# Check a single tune for validity.
189def check_toolchain_tune(data, tune, multilib):
190 tune_errors = []
191 if not tune:
192 return "No tuning found for %s multilib." % multilib
193 localdata = bb.data.createCopy(data)
194 if multilib != "default":
195 # Apply the overrides so we can look at the details.
196 overrides = localdata.getVar("OVERRIDES", False) + ":virtclass-multilib-" + multilib
197 localdata.setVar("OVERRIDES", overrides)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500198 bb.debug(2, "Sanity-checking tuning '%s' (%s) features:" % (tune, multilib))
Patrick Williams213cb262021-08-07 19:21:33 -0500199 features = (localdata.getVar("TUNE_FEATURES:tune-%s" % tune) or "").split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500200 if not features:
201 return "Tuning '%s' has no defined features, and cannot be used." % tune
202 valid_tunes = localdata.getVarFlags('TUNEVALID') or {}
203 conflicts = localdata.getVarFlags('TUNECONFLICTS') or {}
204 # [doc] is the documentation for the variable, not a real feature
205 if 'doc' in valid_tunes:
206 del valid_tunes['doc']
207 if 'doc' in conflicts:
208 del conflicts['doc']
209 for feature in features:
210 if feature in conflicts:
211 for conflict in conflicts[feature].split():
212 if conflict in features:
213 tune_errors.append("Feature '%s' conflicts with '%s'." %
214 (feature, conflict))
215 if feature in valid_tunes:
216 bb.debug(2, " %s: %s" % (feature, valid_tunes[feature]))
217 else:
218 tune_errors.append("Feature '%s' is not defined." % feature)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500219 if tune_errors:
220 return "Tuning '%s' has the following errors:\n" % tune + '\n'.join(tune_errors)
221
222def check_toolchain(data):
223 tune_error_set = []
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500224 deftune = data.getVar("DEFAULTTUNE")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500225 tune_errors = check_toolchain_tune(data, deftune, 'default')
226 if tune_errors:
227 tune_error_set.append(tune_errors)
228
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500229 multilibs = (data.getVar("MULTILIB_VARIANTS") or "").split()
230 global_multilibs = (data.getVar("MULTILIB_GLOBAL_VARIANTS") or "").split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500231
232 if multilibs:
233 seen_libs = []
234 seen_tunes = []
235 for lib in multilibs:
236 if lib in seen_libs:
237 tune_error_set.append("The multilib '%s' appears more than once." % lib)
238 else:
239 seen_libs.append(lib)
240 if not lib in global_multilibs:
241 tune_error_set.append("Multilib %s is not present in MULTILIB_GLOBAL_VARIANTS" % lib)
Patrick Williams213cb262021-08-07 19:21:33 -0500242 tune = data.getVar("DEFAULTTUNE:virtclass-multilib-%s" % lib)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500243 if tune in seen_tunes:
244 tune_error_set.append("The tuning '%s' appears in more than one multilib." % tune)
245 else:
246 seen_libs.append(tune)
247 if tune == deftune:
248 tune_error_set.append("Multilib '%s' (%s) is also the default tuning." % (lib, deftune))
249 else:
250 tune_errors = check_toolchain_tune(data, tune, lib)
251 if tune_errors:
252 tune_error_set.append(tune_errors)
253 if tune_error_set:
254 return "Toolchain tunings invalid:\n" + '\n'.join(tune_error_set) + "\n"
255
256 return ""
257
258def check_conf_exists(fn, data):
259 bbpath = []
260 fn = data.expand(fn)
261 vbbpath = data.getVar("BBPATH", False)
262 if vbbpath:
263 bbpath += vbbpath.split(":")
264 for p in bbpath:
265 currname = os.path.join(data.expand(p), fn)
266 if os.access(currname, os.R_OK):
267 return True
268 return False
269
270def check_create_long_filename(filepath, pathname):
271 import string, random
272 testfile = os.path.join(filepath, ''.join(random.choice(string.ascii_letters) for x in range(200)))
273 try:
274 if not os.path.exists(filepath):
275 bb.utils.mkdirhier(filepath)
276 f = open(testfile, "w")
277 f.close()
278 os.remove(testfile)
279 except IOError as e:
280 import errno
281 err, strerror = e.args
282 if err == errno.ENAMETOOLONG:
283 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
284 else:
285 return "Failed to create a file in %s: %s.\n" % (pathname, strerror)
286 except OSError as e:
287 errno, strerror = e.args
288 return "Failed to create %s directory in which to run long name sanity check: %s.\n" % (pathname, strerror)
289 return ""
290
291def check_path_length(filepath, pathname, limit):
292 if len(filepath) > limit:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500293 return "The length of %s is longer than %s, this would cause unexpected errors, please use a shorter path.\n" % (pathname, limit)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500294 return ""
295
296def get_filesystem_id(path):
Brad Bishopd5ae7d92018-06-14 09:52:03 -0700297 import subprocess
298 try:
Brad Bishop19323692019-04-05 15:28:33 -0400299 return subprocess.check_output(["stat", "-f", "-c", "%t", path]).decode('utf-8').strip()
Brad Bishopd5ae7d92018-06-14 09:52:03 -0700300 except subprocess.CalledProcessError:
301 bb.warn("Can't get filesystem id of: %s" % path)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500302 return None
303
304# Check that the path isn't located on nfs.
305def check_not_nfs(path, name):
306 # The nfs' filesystem id is 6969
307 if get_filesystem_id(path) == "6969":
308 return "The %s: %s can't be located on nfs.\n" % (name, path)
309 return ""
310
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500311# Check that the path is on a case-sensitive file system
312def check_case_sensitive(path, name):
313 import tempfile
314 with tempfile.NamedTemporaryFile(prefix='TmP', dir=path) as tmp_file:
315 if os.path.exists(tmp_file.name.lower()):
316 return "The %s (%s) can't be on a case-insensitive file system.\n" % (name, path)
317 return ""
318
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500319# Check that path isn't a broken symlink
320def check_symlink(lnk, data):
321 if os.path.islink(lnk) and not os.path.exists(lnk):
322 raise_sanity_error("%s is a broken symlink." % lnk, data)
323
324def check_connectivity(d):
325 # URI's to check can be set in the CONNECTIVITY_CHECK_URIS variable
326 # using the same syntax as for SRC_URI. If the variable is not set
327 # the check is skipped
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500328 test_uris = (d.getVar('CONNECTIVITY_CHECK_URIS') or "").split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500329 retval = ""
330
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500331 bbn = d.getVar('BB_NO_NETWORK')
332 if bbn not in (None, '0', '1'):
333 return 'BB_NO_NETWORK should be "0" or "1", but it is "%s"' % bbn
334
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500335 # Only check connectivity if network enabled and the
336 # CONNECTIVITY_CHECK_URIS are set
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500337 network_enabled = not (bbn == '1')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500338 check_enabled = len(test_uris)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500339 if check_enabled and network_enabled:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500340 # Take a copy of the data store and unset MIRRORS and PREMIRRORS
341 data = bb.data.createCopy(d)
342 data.delVar('PREMIRRORS')
343 data.delVar('MIRRORS')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500344 try:
345 fetcher = bb.fetch2.Fetch(test_uris, data)
346 fetcher.checkstatus()
347 except Exception as err:
348 # Allow the message to be configured so that users can be
349 # pointed to a support mechanism.
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500350 msg = data.getVar('CONNECTIVITY_CHECK_MSG') or ""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500351 if len(msg) == 0:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500352 msg = "%s.\n" % err
Andrew Geisslerc926e172021-05-07 16:11:35 -0500353 msg += " Please ensure your host's network is configured correctly.\n"
354 msg += " If your ISP or network is blocking the above URL,\n"
355 msg += " try with another domain name, for example by setting:\n"
Andrew Geissler7e0e3c02022-02-25 20:34:39 +0000356 msg += " CONNECTIVITY_CHECK_URIS = \"https://www.example.com/\""
Andrew Geisslerc926e172021-05-07 16:11:35 -0500357 msg += " You could also set BB_NO_NETWORK = \"1\" to disable network\n"
358 msg += " access if all required sources are on local disk.\n"
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500359 retval = msg
360
361 return retval
362
363def check_supported_distro(sanity_data):
364 from fnmatch import fnmatch
365
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500366 tested_distros = sanity_data.getVar('SANITY_TESTED_DISTROS')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500367 if not tested_distros:
368 return
369
370 try:
371 distro = oe.lsb.distro_identifier()
372 except Exception:
373 distro = None
374
375 if not distro:
376 bb.warn('Host distribution could not be determined; you may possibly experience unexpected failures. It is recommended that you use a tested distribution.')
377
378 for supported in [x.strip() for x in tested_distros.split('\\n')]:
379 if fnmatch(distro, supported):
380 return
381
382 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)
383
384# Checks we should only make if MACHINE is set correctly
385def check_sanity_validmachine(sanity_data):
386 messages = ""
387
388 # Check TUNE_ARCH is set
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500389 if sanity_data.getVar('TUNE_ARCH') == 'INVALID':
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500390 messages = messages + 'TUNE_ARCH is unset. Please ensure your MACHINE configuration includes a valid tune configuration file which will set this correctly.\n'
391
392 # Check TARGET_OS is set
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500393 if sanity_data.getVar('TARGET_OS') == 'INVALID':
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500394 messages = messages + 'Please set TARGET_OS directly, or choose a MACHINE or DISTRO that does so.\n'
395
396 # Check that we don't have duplicate entries in PACKAGE_ARCHS & that TUNE_PKGARCH is in PACKAGE_ARCHS
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500397 pkgarchs = sanity_data.getVar('PACKAGE_ARCHS')
398 tunepkg = sanity_data.getVar('TUNE_PKGARCH')
399 defaulttune = sanity_data.getVar('DEFAULTTUNE')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500400 tunefound = False
401 seen = {}
402 dups = []
403
404 for pa in pkgarchs.split():
405 if seen.get(pa, 0) == 1:
406 dups.append(pa)
407 else:
408 seen[pa] = 1
409 if pa == tunepkg:
410 tunefound = True
411
412 if len(dups):
413 messages = messages + "Error, the PACKAGE_ARCHS variable contains duplicates. The following archs are listed more than once: %s" % " ".join(dups)
414
415 if tunefound == False:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500416 messages = messages + "Error, the PACKAGE_ARCHS variable (%s) for DEFAULTTUNE (%s) does not contain TUNE_PKGARCH (%s)." % (pkgarchs, defaulttune, tunepkg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500417
418 return messages
419
Brad Bishop316dfdd2018-06-25 12:45:53 -0400420# Patch before 2.7 can't handle all the features in git-style diffs. Some
421# patches may incorrectly apply, and others won't apply at all.
422def check_patch_version(sanity_data):
Brad Bishop316dfdd2018-06-25 12:45:53 -0400423 import re, subprocess
424
425 try:
Brad Bishopd5ae7d92018-06-14 09:52:03 -0700426 result = subprocess.check_output(["patch", "--version"], stderr=subprocess.STDOUT).decode('utf-8')
Brad Bishop316dfdd2018-06-25 12:45:53 -0400427 version = re.search(r"[0-9.]+", result.splitlines()[0]).group()
Andrew Geissler595f6302022-01-24 19:11:47 +0000428 if bb.utils.vercmp_string_op(version, "2.7", "<"):
Brad Bishop316dfdd2018-06-25 12:45:53 -0400429 return "Your version of patch is older than 2.7 and has bugs which will break builds. Please install a newer version of patch.\n"
430 else:
431 return None
432 except subprocess.CalledProcessError as e:
433 return "Unable to execute patch --version, exit code %d:\n%s\n" % (e.returncode, e.output)
434
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500435# Unpatched versions of make 3.82 are known to be broken. See GNU Savannah Bug 30612.
436# Use a modified reproducer from http://savannah.gnu.org/bugs/?30612 to validate.
437def check_make_version(sanity_data):
Brad Bishopd5ae7d92018-06-14 09:52:03 -0700438 import subprocess
439
440 try:
441 result = subprocess.check_output(['make', '--version'], stderr=subprocess.STDOUT).decode('utf-8')
442 except subprocess.CalledProcessError as e:
443 return "Unable to execute make --version, exit code %d\n%s\n" % (e.returncode, e.output)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500444 version = result.split()[2]
Andrew Geissler595f6302022-01-24 19:11:47 +0000445 if bb.utils.vercmp_string_op(version, "3.82", "=="):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500446 # Construct a test file
447 f = open("makefile_test", "w")
448 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")
449 f.write("\n")
450 f.write("makefile_test_a.c:\n")
451 f.write(" touch $@\n")
452 f.write("\n")
453 f.write("makefile_test_b.c:\n")
454 f.write(" touch $@\n")
455 f.close()
456
457 # Check if make 3.82 has been patched
Brad Bishopd5ae7d92018-06-14 09:52:03 -0700458 try:
459 subprocess.check_call(['make', '-f', 'makefile_test'])
460 except subprocess.CalledProcessError as e:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500461 return "Your version of make 3.82 is broken. Please revert to 3.81 or install a patched version.\n"
Brad Bishopd5ae7d92018-06-14 09:52:03 -0700462 finally:
463 os.remove("makefile_test")
464 if os.path.exists("makefile_test_a.c"):
465 os.remove("makefile_test_a.c")
466 if os.path.exists("makefile_test_b.c"):
467 os.remove("makefile_test_b.c")
468 if os.path.exists("makefile_test.a"):
469 os.remove("makefile_test.a")
Patrick Williams03907ee2022-05-01 06:28:52 -0500470
471 if bb.utils.vercmp_string_op(version, "4.2.1", "=="):
472 distro = oe.lsb.distro_identifier()
Andrew Geisslerd5838332022-05-27 11:33:10 -0500473 if "ubuntu" in distro or "debian" in distro or "linuxmint" in distro:
Patrick Williams03907ee2022-05-01 06:28:52 -0500474 return None
475 return "make version 4.2.1 is known to have issues on Centos/OpenSUSE and other non-Ubuntu systems. Please use a buildtools-make-tarball or a newer version of make.\n"
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500476 return None
477
478
Andrew Geissler82c905d2020-04-13 13:39:40 -0500479# Check if we're running on WSL (Windows Subsystem for Linux).
480# WSLv1 is known not to work but WSLv2 should work properly as
481# long as the VHDX file is optimized often, let the user know
482# upfront.
483# More information on installing WSLv2 at:
484# https://docs.microsoft.com/en-us/windows/wsl/wsl2-install
Brad Bishope2d5b612018-11-23 10:55:50 +1300485def check_wsl(d):
486 with open("/proc/version", "r") as f:
487 verdata = f.readlines()
488 for l in verdata:
489 if "Microsoft" in l:
Andrew Geissler82c905d2020-04-13 13:39:40 -0500490 return "OpenEmbedded doesn't work under WSLv1, please upgrade to WSLv2 if you want to run builds on Windows"
491 elif "microsoft" in l:
492 bb.warn("You are running bitbake under WSLv2, this works properly but you should optimize your VHDX file eventually to avoid running out of storage space")
493 return None
494
Andrew Geissler595f6302022-01-24 19:11:47 +0000495# Require at least gcc version 7.5.
Andrew Geissler82c905d2020-04-13 13:39:40 -0500496#
497# This can be fixed on CentOS-7 with devtoolset-6+
498# https://www.softwarecollections.org/en/scls/rhscl/devtoolset-6/
499#
500# A less invasive fix is with scripts/install-buildtools (or with user
501# built buildtools-extended-tarball)
502#
503def check_gcc_version(sanity_data):
Andrew Geissler82c905d2020-04-13 13:39:40 -0500504 import subprocess
505
506 build_cc, version = oe.utils.get_host_compiler_version(sanity_data)
507 if build_cc.strip() == "gcc":
Andrew Geissler595f6302022-01-24 19:11:47 +0000508 if bb.utils.vercmp_string_op(version, "7.5", "<"):
509 return "Your version of gcc is older than 7.5 and will break builds. Please install a newer version of gcc (you could use the project's buildtools-extended-tarball or use scripts/install-buildtools).\n"
Brad Bishope2d5b612018-11-23 10:55:50 +1300510 return None
511
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500512# Tar version 1.24 and onwards handle overwriting symlinks correctly
513# but earlier versions do not; this needs to work properly for sstate
Brad Bishop6dbb3162019-11-25 09:41:34 -0500514# Version 1.28 is needed so opkg-build works correctly when reproducibile builds are enabled
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500515def check_tar_version(sanity_data):
Brad Bishopd5ae7d92018-06-14 09:52:03 -0700516 import subprocess
517 try:
518 result = subprocess.check_output(["tar", "--version"], stderr=subprocess.STDOUT).decode('utf-8')
519 except subprocess.CalledProcessError as e:
520 return "Unable to execute tar --version, exit code %d\n%s\n" % (e.returncode, e.output)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500521 version = result.split()[3]
Andrew Geissler595f6302022-01-24 19:11:47 +0000522 if bb.utils.vercmp_string_op(version, "1.28", "<"):
Andrew Geissler82c905d2020-04-13 13:39:40 -0500523 return "Your version of tar is older than 1.28 and does not have the support needed to enable reproducible builds. Please install a newer version of tar (you could use the project's buildtools-tarball from our last release or use scripts/install-buildtools).\n"
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500524 return None
525
526# We use git parameters and functionality only found in 1.7.8 or later
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500527# The kernel tools assume git >= 1.8.3.1 (verified needed > 1.7.9.5) see #6162
528# The git fetcher also had workarounds for git < 1.7.9.2 which we've dropped
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500529def check_git_version(sanity_data):
Brad Bishopd5ae7d92018-06-14 09:52:03 -0700530 import subprocess
531 try:
532 result = subprocess.check_output(["git", "--version"], stderr=subprocess.DEVNULL).decode('utf-8')
533 except subprocess.CalledProcessError as e:
534 return "Unable to execute git --version, exit code %d\n%s\n" % (e.returncode, e.output)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500535 version = result.split()[2]
Andrew Geissler595f6302022-01-24 19:11:47 +0000536 if bb.utils.vercmp_string_op(version, "1.8.3.1", "<"):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500537 return "Your version of git is older than 1.8.3.1 and has bugs which will break builds. Please install a newer version of git.\n"
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500538 return None
539
540# Check the required perl modules which may not be installed by default
541def check_perl_modules(sanity_data):
Brad Bishopd5ae7d92018-06-14 09:52:03 -0700542 import subprocess
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500543 ret = ""
544 modules = ( "Text::ParseWords", "Thread::Queue", "Data::Dumper" )
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500545 errresult = ''
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500546 for m in modules:
Brad Bishopd5ae7d92018-06-14 09:52:03 -0700547 try:
548 subprocess.check_output(["perl", "-e", "use %s" % m])
549 except subprocess.CalledProcessError as e:
Brad Bishopc342db32019-05-15 21:57:59 -0400550 errresult += bytes.decode(e.output)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500551 ret += "%s " % m
552 if ret:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500553 return "Required perl module(s) not found: %s\n\n%s\n" % (ret, errresult)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500554 return None
555
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600556def sanity_check_conffiles(d):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500557 funcs = d.getVar('BBLAYERS_CONF_UPDATE_FUNCS').split()
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500558 for func in funcs:
559 conffile, current_version, required_version, func = func.split(":")
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500560 if check_conf_exists(conffile, d) and d.getVar(current_version) is not None and \
561 d.getVar(current_version) != d.getVar(required_version):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500562 try:
Brad Bishop08902b02019-08-20 09:16:51 -0400563 bb.build.exec_func(func, d)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500564 except NotImplementedError as e:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500565 bb.fatal(str(e))
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600566 d.setVar("BB_INVALIDCONF", True)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500567
Andrew Geissler9aee5002022-03-30 16:27:02 +0000568def drop_v14_cross_builds(d):
569 import glob
570 indexes = glob.glob(d.expand("${SSTATE_MANIFESTS}/index-${BUILD_ARCH}_*"))
571 for i in indexes:
572 with open(i, "r") as f:
573 lines = f.readlines()
574 for l in reversed(lines):
575 try:
576 (stamp, manifest, workdir) = l.split()
577 except ValueError:
578 bb.fatal("Invalid line '%s' in sstate manifest '%s'" % (l, i))
579 for m in glob.glob(manifest + ".*"):
580 if m.endswith(".postrm"):
581 continue
582 sstate_clean_manifest(m, d)
583 bb.utils.remove(stamp + "*")
584 bb.utils.remove(workdir, recurse = True)
585
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500586def sanity_handle_abichanges(status, d):
587 #
588 # Check the 'ABI' of TMPDIR
589 #
590 import subprocess
591
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500592 current_abi = d.getVar('OELAYOUT_ABI')
593 abifile = d.getVar('SANITY_ABIFILE')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500594 if os.path.exists(abifile):
595 with open(abifile, "r") as f:
596 abi = f.read().strip()
597 if not abi.isdigit():
598 with open(abifile, "w") as f:
599 f.write(current_abi)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500600 elif int(abi) <= 11 and current_abi == "12":
601 status.addresult("The layout of TMPDIR changed for Recipe Specific Sysroots.\nConversion doesn't make sense and this change will rebuild everything so please delete TMPDIR (%s).\n" % d.getVar("TMPDIR"))
Andrew Geisslerf0343792020-11-18 10:42:21 -0600602 elif int(abi) <= 13 and current_abi == "14":
603 status.addresult("TMPDIR changed to include path filtering from the pseudo database.\nIt is recommended to use a clean TMPDIR with the new pseudo path filtering so TMPDIR (%s) would need to be removed to continue.\n" % d.getVar("TMPDIR"))
Andrew Geissler9aee5002022-03-30 16:27:02 +0000604 elif int(abi) == 14 and current_abi == "15":
605 drop_v14_cross_builds(d)
606 with open(abifile, "w") as f:
607 f.write(current_abi)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500608 elif (abi != current_abi):
609 # Code to convert from one ABI to another could go here if possible.
610 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))
611 else:
612 with open(abifile, "w") as f:
613 f.write(current_abi)
614
615def check_sanity_sstate_dir_change(sstate_dir, data):
616 # Sanity checks to be done when the value of SSTATE_DIR changes
617
618 # Check that SSTATE_DIR isn't on a filesystem with limited filename length (eg. eCryptFS)
619 testmsg = ""
620 if sstate_dir != "":
621 testmsg = check_create_long_filename(sstate_dir, "SSTATE_DIR")
622 # If we don't have permissions to SSTATE_DIR, suggest the user set it as an SSTATE_MIRRORS
623 try:
624 err = testmsg.split(': ')[1].strip()
625 if err == "Permission denied.":
626 testmsg = testmsg + "You could try using %s in SSTATE_MIRRORS rather than as an SSTATE_CACHE.\n" % (sstate_dir)
627 except IndexError:
628 pass
629 return testmsg
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500630
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500631def check_sanity_version_change(status, d):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500632 # Sanity checks to be done when SANITY_VERSION or NATIVELSBSTRING changes
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500633 # In other words, these tests run once in a given build directory and then
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500634 # never again until the sanity version or host distrubution id/version changes.
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500635
Brad Bishop64c979e2019-11-04 13:55:29 -0500636 # Check the python install is complete. Examples that are often removed in
637 # minimal installations: glib-2.0-natives requries # xml.parsers.expat and icu
638 # requires distutils.sysconfig.
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500639 try:
640 import xml.parsers.expat
Brad Bishop64c979e2019-11-04 13:55:29 -0500641 import distutils.sysconfig
642 except ImportError as e:
643 status.addresult('Your Python 3 is not a full install. Please install the module %s (see the Getting Started guide for further information).\n' % e.name)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500644
Andrew Geissler82c905d2020-04-13 13:39:40 -0500645 status.addresult(check_gcc_version(d))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500646 status.addresult(check_make_version(d))
Brad Bishop316dfdd2018-06-25 12:45:53 -0400647 status.addresult(check_patch_version(d))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500648 status.addresult(check_tar_version(d))
649 status.addresult(check_git_version(d))
650 status.addresult(check_perl_modules(d))
Brad Bishope2d5b612018-11-23 10:55:50 +1300651 status.addresult(check_wsl(d))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500652
653 missing = ""
654
655 if not check_app_exists("${MAKE}", d):
656 missing = missing + "GNU make,"
657
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600658 if not check_app_exists('${BUILD_CC}', d):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500659 missing = missing + "C Compiler (%s)," % d.getVar("BUILD_CC")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500660
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600661 if not check_app_exists('${BUILD_CXX}', d):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500662 missing = missing + "C++ Compiler (%s)," % d.getVar("BUILD_CXX")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500663
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500664 required_utilities = d.getVar('SANITY_REQUIRED_UTILITIES')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500665
666 for util in required_utilities.split():
667 if not check_app_exists(util, d):
668 missing = missing + "%s," % util
669
670 if missing:
671 missing = missing.rstrip(',')
672 status.addresult("Please install the following missing utilities: %s\n" % missing)
673
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500674 assume_provided = d.getVar('ASSUME_PROVIDED').split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500675 # Check user doesn't have ASSUME_PROVIDED = instead of += in local.conf
676 if "diffstat-native" not in assume_provided:
677 status.addresult('Please use ASSUME_PROVIDED +=, not ASSUME_PROVIDED = in your local.conf\n')
678
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500679 # Check that TMPDIR isn't on a filesystem with limited filename length (eg. eCryptFS)
Brad Bishop64c979e2019-11-04 13:55:29 -0500680 import stat
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500681 tmpdir = d.getVar('TMPDIR')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500682 status.addresult(check_create_long_filename(tmpdir, "TMPDIR"))
683 tmpdirmode = os.stat(tmpdir).st_mode
684 if (tmpdirmode & stat.S_ISGID):
685 status.addresult("TMPDIR is setgid, please don't build in a setgid directory")
686 if (tmpdirmode & stat.S_ISUID):
687 status.addresult("TMPDIR is setuid, please don't build in a setuid directory")
688
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600689 # Check that a user isn't building in a path in PSEUDO_IGNORE_PATHS
690 pseudoignorepaths = d.getVar('PSEUDO_IGNORE_PATHS', expand=True).split(",")
691 workdir = d.getVar('WORKDIR', expand=True)
692 for i in pseudoignorepaths:
693 if i and workdir.startswith(i):
694 status.addresult("You are building in a path included in PSEUDO_IGNORE_PATHS " + str(i) + " please locate the build outside this path.\n")
695
696 # Check if PSEUDO_IGNORE_PATHS and and paths under pseudo control overlap
697 pseudoignorepaths = d.getVar('PSEUDO_IGNORE_PATHS', expand=True).split(",")
698 pseudo_control_dir = "${D},${PKGD},${PKGDEST},${IMAGEROOTFS},${SDK_OUTPUT}"
699 pseudocontroldir = d.expand(pseudo_control_dir).split(",")
700 for i in pseudoignorepaths:
701 for j in pseudocontroldir:
702 if i and j:
703 if j.startswith(i):
704 status.addresult("A path included in PSEUDO_IGNORE_PATHS " + str(i) + " and the path " + str(j) + " overlap and this will break pseudo permission and ownership tracking. Please set the path " + str(j) + " to a different directory which does not overlap with pseudo controlled directories. \n")
705
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500706 # Some third-party software apparently relies on chmod etc. being suid root (!!)
707 import stat
708 suid_check_bins = "chown chmod mknod".split()
709 for bin_cmd in suid_check_bins:
710 bin_path = bb.utils.which(os.environ["PATH"], bin_cmd)
711 if bin_path:
712 bin_stat = os.stat(bin_path)
713 if bin_stat.st_uid == 0 and bin_stat.st_mode & stat.S_ISUID:
714 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)
715
716 # Check that we can fetch from various network transports
717 netcheck = check_connectivity(d)
718 status.addresult(netcheck)
719 if netcheck:
720 status.network_error = True
721
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500722 nolibs = d.getVar('NO32LIBS')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500723 if not nolibs:
724 lib32path = '/lib'
725 if os.path.exists('/lib64') and ( os.path.islink('/lib64') or os.path.islink('/lib') ):
726 lib32path = '/lib32'
727
728 if os.path.exists('%s/libc.so.6' % lib32path) and not os.path.exists('/usr/include/gnu/stubs-32.h'):
729 status.addresult("You have a 32-bit libc, but no 32-bit headers. You must install the 32-bit libc headers.\n")
730
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500731 bbpaths = d.getVar('BBPATH').split(":")
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600732 if ("." in bbpaths or "./" in bbpaths or "" in bbpaths):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500733 status.addresult("BBPATH references the current directory, either through " \
734 "an empty entry, a './' or a '.'.\n\t This is unsafe and means your "\
735 "layer configuration is adding empty elements to BBPATH.\n\t "\
736 "Please check your layer.conf files and other BBPATH " \
737 "settings to remove the current working directory " \
738 "references.\n" \
739 "Parsed BBPATH is" + str(bbpaths));
740
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500741 oes_bb_conf = d.getVar( 'OES_BITBAKE_CONF')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500742 if not oes_bb_conf:
743 status.addresult('You are not using the OpenEmbedded version of conf/bitbake.conf. This means your environment is misconfigured, in particular check BBPATH.\n')
744
745 # The length of TMPDIR can't be longer than 410
746 status.addresult(check_path_length(tmpdir, "TMPDIR", 410))
747
748 # Check that TMPDIR isn't located on nfs
749 status.addresult(check_not_nfs(tmpdir, "TMPDIR"))
750
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500751 # Check for case-insensitive file systems (such as Linux in Docker on
752 # macOS with default HFS+ file system)
753 status.addresult(check_case_sensitive(tmpdir, "TMPDIR"))
754
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600755def sanity_check_locale(d):
756 """
757 Currently bitbake switches locale to en_US.UTF-8 so check that this locale actually exists.
758 """
759 import locale
760 try:
761 locale.setlocale(locale.LC_ALL, "en_US.UTF-8")
762 except locale.Error:
Brad Bishop316dfdd2018-06-25 12:45:53 -0400763 raise_sanity_error("Your system needs to support the en_US.UTF-8 locale.", d)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600764
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500765def check_sanity_everybuild(status, d):
766 import os, stat
767 # Sanity tests which test the users environment so need to run at each build (or are so cheap
768 # it makes sense to always run them.
769
770 if 0 == os.getuid():
771 raise_sanity_error("Do not use Bitbake as root.", d)
772
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600773 # Check the Python version, we now have a minimum of Python 3.6
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500774 import sys
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600775 if sys.hexversion < 0x030600F0:
776 status.addresult('The system requires at least Python 3.6 to run. Please update your Python interpreter.\n')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500777
778 # Check the bitbake version meets minimum requirements
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500779 minversion = d.getVar('BB_MIN_VERSION')
Andrew Geissler595f6302022-01-24 19:11:47 +0000780 if bb.utils.vercmp_string_op(bb.__version__, minversion, "<"):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500781 status.addresult('Bitbake version %s is required and version %s was found\n' % (minversion, bb.__version__))
782
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600783 sanity_check_locale(d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500784
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500785 paths = d.getVar('PATH').split(":")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500786 if "." in paths or "./" in paths or "" in paths:
787 status.addresult("PATH contains '.', './' or '' (empty element), which will break the build, please remove this.\nParsed PATH is " + str(paths) + "\n")
788
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600789 #Check if bitbake is present in PATH environment variable
790 bb_check = bb.utils.which(d.getVar('PATH'), 'bitbake')
791 if not bb_check:
792 bb.warn("bitbake binary is not found in PATH, did you source the script?")
793
Andrew Geissler1e34c2d2020-05-29 16:02:59 -0500794 # Check whether 'inherit' directive is found (used for a class to inherit)
795 # in conf file it's supposed to be uppercase INHERIT
796 inherit = d.getVar('inherit')
797 if inherit:
798 status.addresult("Please don't use inherit directive in your local.conf. The directive is supposed to be used in classes and recipes only to inherit of bbclasses. Here INHERIT should be used.\n")
799
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500800 # Check that the DISTRO is valid, if set
801 # need to take into account DISTRO renaming DISTRO
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500802 distro = d.getVar('DISTRO')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500803 if distro and distro != "nodistro":
804 if not ( check_conf_exists("conf/distro/${DISTRO}.conf", d) or check_conf_exists("conf/distro/include/${DISTRO}.inc", d) ):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500805 status.addresult("DISTRO '%s' not found. Please set a valid DISTRO in your local.conf\n" % d.getVar("DISTRO"))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500806
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500807 # Check that these variables don't use tilde-expansion as we don't do that
808 for v in ("TMPDIR", "DL_DIR", "SSTATE_DIR"):
809 if d.getVar(v).startswith("~"):
810 status.addresult("%s uses ~ but Bitbake will not expand this, use an absolute path or variables." % v)
811
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500812 # Check that DL_DIR is set, exists and is writable. In theory, we should never even hit the check if DL_DIR isn't
813 # set, since so much relies on it being set.
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500814 dldir = d.getVar('DL_DIR')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500815 if not dldir:
816 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")
817 if os.path.exists(dldir) and not os.access(dldir, os.W_OK):
818 status.addresult("DL_DIR: %s exists but you do not appear to have write access to it. \n" % dldir)
819 check_symlink(dldir, d)
820
821 # Check that the MACHINE is valid, if it is set
822 machinevalid = True
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500823 if d.getVar('MACHINE'):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500824 if not check_conf_exists("conf/machine/${MACHINE}.conf", d):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500825 status.addresult('MACHINE=%s is invalid. Please set a valid MACHINE in your local.conf, environment or other configuration file.\n' % (d.getVar('MACHINE')))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500826 machinevalid = False
827 else:
828 status.addresult(check_sanity_validmachine(d))
829 else:
830 status.addresult('Please set a MACHINE in your local.conf or environment\n')
831 machinevalid = False
832 if machinevalid:
833 status.addresult(check_toolchain(d))
834
835 # Check that the SDKMACHINE is valid, if it is set
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500836 if d.getVar('SDKMACHINE'):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500837 if not check_conf_exists("conf/machine-sdk/${SDKMACHINE}.conf", d):
838 status.addresult('Specified SDKMACHINE value is not valid\n')
839 elif d.getVar('SDK_ARCH', False) == "${BUILD_ARCH}":
840 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')
841
Brad Bishop64c979e2019-11-04 13:55:29 -0500842 # If SDK_VENDOR looks like "-my-sdk" then the triples are badly formed so fail early
843 sdkvendor = d.getVar("SDK_VENDOR")
844 if not (sdkvendor.startswith("-") and sdkvendor.count("-") == 1):
Andrew Geissler82c905d2020-04-13 13:39:40 -0500845 status.addresult("SDK_VENDOR should be of the form '-foosdk' with a single dash; found '%s'\n" % sdkvendor)
Brad Bishop64c979e2019-11-04 13:55:29 -0500846
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500847 check_supported_distro(d)
848
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600849 omask = os.umask(0o022)
850 if omask & 0o755:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500851 status.addresult("Please use a umask which allows a+rx and u+rwx\n")
852 os.umask(omask)
853
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500854 if d.getVar('TARGET_ARCH') == "arm":
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500855 # This path is no longer user-readable in modern (very recent) Linux
856 try:
857 if os.path.exists("/proc/sys/vm/mmap_min_addr"):
858 f = open("/proc/sys/vm/mmap_min_addr", "r")
859 try:
860 if (int(f.read().strip()) > 65536):
861 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")
862 finally:
863 f.close()
864 except:
865 pass
866
Andrew Geisslerc926e172021-05-07 16:11:35 -0500867 for checkdir in ['COREBASE', 'TMPDIR']:
868 val = d.getVar(checkdir)
869 if val.find('..') != -1:
870 status.addresult("Error, you have '..' in your %s directory path. Please ensure the variable contains an absolute path as this can break some recipe builds in obtuse ways." % checkdir)
871 if val.find('+') != -1:
872 status.addresult("Error, you have an invalid character (+) in your %s directory path. Please move the installation to a directory which doesn't include any + characters." % checkdir)
873 if val.find('@') != -1:
874 status.addresult("Error, you have an invalid character (@) in your %s directory path. Please move the installation to a directory which doesn't include any @ characters." % checkdir)
875 if val.find(' ') != -1:
876 status.addresult("Error, you have a space in your %s directory path. Please move the installation to a directory which doesn't include a space since autotools doesn't support this." % checkdir)
877 if val.find('%') != -1:
878 status.addresult("Error, you have an invalid character (%) in your %s directory path which causes problems with python string formatting. Please move the installation to a directory which doesn't include any % characters." % checkdir)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500879
880 # Check the format of MIRRORS, PREMIRRORS and SSTATE_MIRRORS
881 import re
882 mirror_vars = ['MIRRORS', 'PREMIRRORS', 'SSTATE_MIRRORS']
883 protocols = ['http', 'ftp', 'file', 'https', \
884 'git', 'gitsm', 'hg', 'osc', 'p4', 'svn', \
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500885 'bzr', 'cvs', 'npm', 'sftp', 'ssh', 's3', 'az' ]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500886 for mirror_var in mirror_vars:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500887 mirrors = (d.getVar(mirror_var) or '').replace('\\n', ' ').split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500888
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500889 # Split into pairs
890 if len(mirrors) % 2 != 0:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500891 bb.warn('Invalid mirror variable value for %s: %s, should contain paired members.' % (mirror_var, str(mirrors)))
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500892 continue
893 mirrors = list(zip(*[iter(mirrors)]*2))
894
895 for mirror_entry in mirrors:
896 pattern, mirror = mirror_entry
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500897
898 decoded = bb.fetch2.decodeurl(pattern)
899 try:
900 pattern_scheme = re.compile(decoded[0])
901 except re.error as exc:
902 bb.warn('Invalid scheme regex (%s) in %s; %s' % (pattern, mirror_var, mirror_entry))
903 continue
904
905 if not any(pattern_scheme.match(protocol) for protocol in protocols):
906 bb.warn('Invalid protocol (%s) in %s: %s' % (decoded[0], mirror_var, mirror_entry))
907 continue
908
909 if not any(mirror.startswith(protocol + '://') for protocol in protocols):
910 bb.warn('Invalid protocol in %s: %s' % (mirror_var, mirror_entry))
911 continue
912
913 if mirror.startswith('file://'):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600914 import urllib
915 check_symlink(urllib.parse.urlparse(mirror).path, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500916 # SSTATE_MIRROR ends with a /PATH string
917 if mirror.endswith('/PATH'):
918 # remove /PATH$ from SSTATE_MIRROR to get a working
919 # base directory path
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600920 mirror_base = urllib.parse.urlparse(mirror[:-1*len('/PATH')]).path
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500921 check_symlink(mirror_base, d)
922
Andrew Geissler9aee5002022-03-30 16:27:02 +0000923 # Check sstate mirrors aren't being used with a local hash server and no remote
924 hashserv = d.getVar("BB_HASHSERVE")
925 if d.getVar("SSTATE_MIRRORS") and hashserv and hashserv.startswith("unix://") and not d.getVar("BB_HASHSERVE_UPSTREAM"):
926 bb.warn("You are using a local hash equivalence server but have configured an sstate mirror. This will likely mean no sstate will match from the mirror. You may wish to disable the hash equivalence use (BB_HASHSERVE), or use a hash equivalence server alongside the sstate mirror.")
927
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500928 # Check that TMPDIR hasn't changed location since the last time we were run
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500929 tmpdir = d.getVar('TMPDIR')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500930 checkfile = os.path.join(tmpdir, "saved_tmpdir")
931 if os.path.exists(checkfile):
932 with open(checkfile, "r") as f:
933 saved_tmpdir = f.read().strip()
934 if (saved_tmpdir != tmpdir):
Brad Bishopd89cb5f2019-04-10 09:02:41 -0400935 status.addresult("Error, TMPDIR has changed location. You need to either move it back to %s or delete it and rebuild\n" % saved_tmpdir)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500936 else:
937 bb.utils.mkdirhier(tmpdir)
938 # Remove setuid, setgid and sticky bits from TMPDIR
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500939 try:
940 os.chmod(tmpdir, os.stat(tmpdir).st_mode & ~ stat.S_ISUID)
941 os.chmod(tmpdir, os.stat(tmpdir).st_mode & ~ stat.S_ISGID)
942 os.chmod(tmpdir, os.stat(tmpdir).st_mode & ~ stat.S_ISVTX)
943 except OSError as exc:
944 bb.warn("Unable to chmod TMPDIR: %s" % exc)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500945 with open(checkfile, "w") as f:
946 f.write(tmpdir)
947
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600948 # If /bin/sh is a symlink, check that it points to dash or bash
949 if os.path.islink('/bin/sh'):
950 real_sh = os.path.realpath('/bin/sh')
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500951 # Due to update-alternatives, the shell name may take various
952 # forms, such as /bin/dash, bin/bash, /bin/bash.bash ...
953 if '/dash' not in real_sh and '/bash' not in real_sh:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600954 status.addresult("Error, /bin/sh links to %s, must be dash or bash\n" % real_sh)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500955
956def check_sanity(sanity_data):
957 class SanityStatus(object):
958 def __init__(self):
959 self.messages = ""
960 self.network_error = False
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500961
962 def addresult(self, message):
963 if message:
964 self.messages = self.messages + message
965
966 status = SanityStatus()
967
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500968 tmpdir = sanity_data.getVar('TMPDIR')
969 sstate_dir = sanity_data.getVar('SSTATE_DIR')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500970
971 check_symlink(sstate_dir, sanity_data)
972
973 # Check saved sanity info
974 last_sanity_version = 0
975 last_tmpdir = ""
976 last_sstate_dir = ""
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500977 last_nativelsbstr = ""
Andrew Geissler82c905d2020-04-13 13:39:40 -0500978 sanityverfile = sanity_data.expand("${TOPDIR}/cache/sanity_info")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500979 if os.path.exists(sanityverfile):
980 with open(sanityverfile, 'r') as f:
981 for line in f:
982 if line.startswith('SANITY_VERSION'):
983 last_sanity_version = int(line.split()[1])
984 if line.startswith('TMPDIR'):
985 last_tmpdir = line.split()[1]
986 if line.startswith('SSTATE_DIR'):
987 last_sstate_dir = line.split()[1]
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500988 if line.startswith('NATIVELSBSTRING'):
989 last_nativelsbstr = line.split()[1]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500990
991 check_sanity_everybuild(status, sanity_data)
992
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500993 sanity_version = int(sanity_data.getVar('SANITY_VERSION') or 1)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500994 network_error = False
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500995 # NATIVELSBSTRING var may have been overridden with "universal", so
996 # get actual host distribution id and version
997 nativelsbstr = lsb_distro_identifier(sanity_data)
998 if last_sanity_version < sanity_version or last_nativelsbstr != nativelsbstr:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500999 check_sanity_version_change(status, sanity_data)
1000 status.addresult(check_sanity_sstate_dir_change(sstate_dir, sanity_data))
1001 else:
1002 if last_sstate_dir != sstate_dir:
1003 status.addresult(check_sanity_sstate_dir_change(sstate_dir, sanity_data))
1004
1005 if os.path.exists(os.path.dirname(sanityverfile)) and not status.messages:
1006 with open(sanityverfile, 'w') as f:
1007 f.write("SANITY_VERSION %s\n" % sanity_version)
1008 f.write("TMPDIR %s\n" % tmpdir)
1009 f.write("SSTATE_DIR %s\n" % sstate_dir)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001010 f.write("NATIVELSBSTRING %s\n" % nativelsbstr)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001011
1012 sanity_handle_abichanges(status, sanity_data)
1013
1014 if status.messages != "":
1015 raise_sanity_error(sanity_data.expand(status.messages), sanity_data, status.network_error)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001016
1017# Create a copy of the datastore and finalise it to ensure appends and
1018# overrides are set - the datastore has yet to be finalised at ConfigParsed
1019def copy_data(e):
1020 sanity_data = bb.data.createCopy(e.data)
1021 sanity_data.finalize()
1022 return sanity_data
1023
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001024addhandler config_reparse_eventhandler
1025config_reparse_eventhandler[eventmask] = "bb.event.ConfigParsed"
1026python config_reparse_eventhandler() {
1027 sanity_check_conffiles(e.data)
1028}
1029
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001030addhandler check_sanity_eventhandler
1031check_sanity_eventhandler[eventmask] = "bb.event.SanityCheck bb.event.NetworkTest"
1032python check_sanity_eventhandler() {
1033 if bb.event.getName(e) == "SanityCheck":
1034 sanity_data = copy_data(e)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001035 check_sanity(sanity_data)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001036 if e.generateevents:
1037 sanity_data.setVar("SANITY_USE_EVENTS", "1")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001038 bb.event.fire(bb.event.SanityCheckPassed(), e.data)
1039 elif bb.event.getName(e) == "NetworkTest":
1040 sanity_data = copy_data(e)
1041 if e.generateevents:
1042 sanity_data.setVar("SANITY_USE_EVENTS", "1")
1043 bb.event.fire(bb.event.NetworkTestFailed() if check_connectivity(sanity_data) else bb.event.NetworkTestPassed(), e.data)
1044
1045 return
1046}