summaryrefslogtreecommitdiffstats
path: root/meta/classes-global/sanity.bbclass
diff options
context:
space:
mode:
Diffstat (limited to 'meta/classes-global/sanity.bbclass')
-rw-r--r--meta/classes-global/sanity.bbclass106
1 files changed, 89 insertions, 17 deletions
diff --git a/meta/classes-global/sanity.bbclass b/meta/classes-global/sanity.bbclass
index 180c6b77d8..d875a022db 100644
--- a/meta/classes-global/sanity.bbclass
+++ b/meta/classes-global/sanity.bbclass
@@ -299,6 +299,11 @@ def check_path_length(filepath, pathname, limit):
299 return "The length of %s is longer than %s, this would cause unexpected errors, please use a shorter path.\n" % (pathname, limit) 299 return "The length of %s is longer than %s, this would cause unexpected errors, please use a shorter path.\n" % (pathname, limit)
300 return "" 300 return ""
301 301
302def check_non_ascii(filepath, pathname):
303 if(not filepath.isascii()):
304 return "Non-ASCII character(s) in %s path (\"%s\") detected. This would cause build failures as we build software that doesn't support this.\n" % (pathname, filepath)
305 return ""
306
302def get_filesystem_id(path): 307def get_filesystem_id(path):
303 import subprocess 308 import subprocess
304 try: 309 try:
@@ -475,6 +480,31 @@ def check_wsl(d):
475 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") 480 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")
476 return None 481 return None
477 482
483def check_userns():
484 """
485 Check that user namespaces are functional, as they're used for network isolation.
486 """
487
488 # There is a known failure case with AppAmrmor where the unshare() call
489 # succeeds (at which point the uid is nobody) but writing to the uid_map
490 # fails (so the uid isn't reset back to the user's uid). We can detect this.
491 parentuid = os.getuid()
492 if not bb.utils.is_local_uid(parentuid):
493 return None
494 pid = os.fork()
495 if not pid:
496 try:
497 bb.utils.disable_network()
498 except:
499 pass
500 os._exit(parentuid != os.getuid())
501
502 ret = os.waitpid(pid, 0)[1]
503 if ret:
504 bb.fatal("User namespaces are not usable by BitBake, possibly due to AppArmor.\n"
505 "See https://discourse.ubuntu.com/t/ubuntu-24-04-lts-noble-numbat-release-notes/39890#unprivileged-user-namespace-restrictions for more information.")
506
507
478# Require at least gcc version 8.0 508# Require at least gcc version 8.0
479# 509#
480# This can be fixed on CentOS-7 with devtoolset-6+ 510# This can be fixed on CentOS-7 with devtoolset-6+
@@ -484,23 +514,23 @@ def check_wsl(d):
484# built buildtools-extended-tarball) 514# built buildtools-extended-tarball)
485# 515#
486def check_gcc_version(sanity_data): 516def check_gcc_version(sanity_data):
487 import subprocess 517 version = oe.utils.get_host_gcc_version(sanity_data)
488 518 if bb.utils.vercmp_string_op(version, "8.0", "<"):
489 build_cc, version = oe.utils.get_host_compiler_version(sanity_data) 519 return "Your version of gcc is older than 8.0 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"
490 if build_cc.strip() == "gcc":
491 if bb.utils.vercmp_string_op(version, "8.0", "<"):
492 return "Your version of gcc is older than 8.0 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"
493 return None 520 return None
494 521
495# Tar version 1.24 and onwards handle overwriting symlinks correctly 522# Tar version 1.24 and onwards handle overwriting symlinks correctly
496# but earlier versions do not; this needs to work properly for sstate 523# but earlier versions do not; this needs to work properly for sstate
497# Version 1.28 is needed so opkg-build works correctly when reproducible builds are enabled 524# Version 1.28 is needed so opkg-build works correctly when reproducible builds are enabled
525# Gtar is assumed at to be used as tar in poky
498def check_tar_version(sanity_data): 526def check_tar_version(sanity_data):
499 import subprocess 527 import subprocess
500 try: 528 try:
501 result = subprocess.check_output(["tar", "--version"], stderr=subprocess.STDOUT).decode('utf-8') 529 result = subprocess.check_output(["tar", "--version"], stderr=subprocess.STDOUT).decode('utf-8')
502 except subprocess.CalledProcessError as e: 530 except subprocess.CalledProcessError as e:
503 return "Unable to execute tar --version, exit code %d\n%s\n" % (e.returncode, e.output) 531 return "Unable to execute tar --version, exit code %d\n%s\n" % (e.returncode, e.output)
532 if not "GNU" in result:
533 return "Your version of tar is not gtar. Please install gtar (you could use the project's buildtools-tarball from our last release or use scripts/install-buildtools).\n"
504 version = result.split()[3] 534 version = result.split()[3]
505 if bb.utils.vercmp_string_op(version, "1.28", "<"): 535 if bb.utils.vercmp_string_op(version, "1.28", "<"):
506 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" 536 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"
@@ -574,6 +604,28 @@ def drop_v14_cross_builds(d):
574 bb.utils.remove(stamp + "*") 604 bb.utils.remove(stamp + "*")
575 bb.utils.remove(workdir, recurse = True) 605 bb.utils.remove(workdir, recurse = True)
576 606
607def check_cpp_toolchain_flag(d, flag, error_message=None):
608 """
609 Checks if the g++ compiler supports the given flag
610 """
611 import shlex
612 import subprocess
613
614 cpp_code = """
615 #include <iostream>
616 int main() {
617 std::cout << "Hello, World!" << std::endl;
618 return 0;
619 }
620 """
621
622 cmd = ["g++", "-x", "c++","-", "-o", "/dev/null", flag]
623 try:
624 subprocess.run(cmd, input=cpp_code, capture_output=True, text=True, check=True)
625 return None
626 except subprocess.CalledProcessError as e:
627 return error_message or f"An unexpected issue occurred during the C++ toolchain check: {str(e)}"
628
577def sanity_handle_abichanges(status, d): 629def sanity_handle_abichanges(status, d):
578 # 630 #
579 # Check the 'ABI' of TMPDIR 631 # Check the 'ABI' of TMPDIR
@@ -620,6 +672,8 @@ def check_sanity_sstate_dir_change(sstate_dir, data):
620 return testmsg 672 return testmsg
621 673
622def check_sanity_version_change(status, d): 674def check_sanity_version_change(status, d):
675 import glob
676
623 # Sanity checks to be done when SANITY_VERSION or NATIVELSBSTRING changes 677 # Sanity checks to be done when SANITY_VERSION or NATIVELSBSTRING changes
624 # In other words, these tests run once in a given build directory and then 678 # In other words, these tests run once in a given build directory and then
625 # never again until the sanity version or host distribution id/version changes. 679 # never again until the sanity version or host distribution id/version changes.
@@ -638,17 +692,23 @@ def check_sanity_version_change(status, d):
638 status.addresult(check_git_version(d)) 692 status.addresult(check_git_version(d))
639 status.addresult(check_perl_modules(d)) 693 status.addresult(check_perl_modules(d))
640 status.addresult(check_wsl(d)) 694 status.addresult(check_wsl(d))
695 status.addresult(check_userns())
641 696
642 missing = "" 697 missing = ""
643 698
644 if not check_app_exists("${MAKE}", d): 699 if not check_app_exists("${MAKE}", d):
645 missing = missing + "GNU make," 700 missing = missing + "GNU make,"
646 701
647 if not check_app_exists('${BUILD_CC}', d): 702 if not check_app_exists('gcc', d):
648 missing = missing + "C Compiler (%s)," % d.getVar("BUILD_CC") 703 missing = missing + "C Compiler (gcc),"
704
705 if not check_app_exists('g++', d):
706 missing = missing + "C++ Compiler (g++),"
649 707
650 if not check_app_exists('${BUILD_CXX}', d): 708 # installing emacs on Ubuntu 24.04 pulls in emacs-gtk -> libgcc-14-dev despite gcc being 13
651 missing = missing + "C++ Compiler (%s)," % d.getVar("BUILD_CXX") 709 # this breaks libcxx-native and compiler-rt-native builds so tell the user to fix things
710 if glob.glob("/usr/lib/gcc/*/14/libgcc_s.so") and not glob.glob("/usr/lib/gcc/*/14/libstdc++.so"):
711 status.addresult('libgcc-14-dev is installed and not libstdc++-14-dev which will break clang native compiles. Please remove one or install the other.')
652 712
653 required_utilities = d.getVar('SANITY_REQUIRED_UTILITIES') 713 required_utilities = d.getVar('SANITY_REQUIRED_UTILITIES')
654 714
@@ -668,6 +728,7 @@ def check_sanity_version_change(status, d):
668 # Check that TMPDIR isn't on a filesystem with limited filename length (eg. eCryptFS) 728 # Check that TMPDIR isn't on a filesystem with limited filename length (eg. eCryptFS)
669 import stat 729 import stat
670 tmpdir = d.getVar('TMPDIR') 730 tmpdir = d.getVar('TMPDIR')
731 topdir = d.getVar('TOPDIR')
671 status.addresult(check_create_long_filename(tmpdir, "TMPDIR")) 732 status.addresult(check_create_long_filename(tmpdir, "TMPDIR"))
672 tmpdirmode = os.stat(tmpdir).st_mode 733 tmpdirmode = os.stat(tmpdir).st_mode
673 if (tmpdirmode & stat.S_ISGID): 734 if (tmpdirmode & stat.S_ISGID):
@@ -676,14 +737,14 @@ def check_sanity_version_change(status, d):
676 status.addresult("TMPDIR is setuid, please don't build in a setuid directory") 737 status.addresult("TMPDIR is setuid, please don't build in a setuid directory")
677 738
678 # Check that a user isn't building in a path in PSEUDO_IGNORE_PATHS 739 # Check that a user isn't building in a path in PSEUDO_IGNORE_PATHS
679 pseudoignorepaths = d.getVar('PSEUDO_IGNORE_PATHS', expand=True).split(",") 740 pseudoignorepaths = (d.getVar('PSEUDO_IGNORE_PATHS', expand=True) or "").split(",")
680 workdir = d.getVar('WORKDIR', expand=True) 741 workdir = d.getVar('WORKDIR', expand=True)
681 for i in pseudoignorepaths: 742 for i in pseudoignorepaths:
682 if i and workdir.startswith(i): 743 if i and workdir.startswith(i):
683 status.addresult("You are building in a path included in PSEUDO_IGNORE_PATHS " + str(i) + " please locate the build outside this path.\n") 744 status.addresult("You are building in a path included in PSEUDO_IGNORE_PATHS " + str(i) + " please locate the build outside this path.\n")
684 745
685 # Check if PSEUDO_IGNORE_PATHS and paths under pseudo control overlap 746 # Check if PSEUDO_IGNORE_PATHS and paths under pseudo control overlap
686 pseudoignorepaths = d.getVar('PSEUDO_IGNORE_PATHS', expand=True).split(",") 747 pseudoignorepaths = (d.getVar('PSEUDO_IGNORE_PATHS', expand=True) or "").split(",")
687 pseudo_control_dir = "${D},${PKGD},${PKGDEST},${IMAGEROOTFS},${SDK_OUTPUT}" 748 pseudo_control_dir = "${D},${PKGD},${PKGDEST},${IMAGEROOTFS},${SDK_OUTPUT}"
688 pseudocontroldir = d.expand(pseudo_control_dir).split(",") 749 pseudocontroldir = d.expand(pseudo_control_dir).split(",")
689 for i in pseudoignorepaths: 750 for i in pseudoignorepaths:
@@ -731,8 +792,11 @@ def check_sanity_version_change(status, d):
731 if not oes_bb_conf: 792 if not oes_bb_conf:
732 status.addresult('You are not using the OpenEmbedded version of conf/bitbake.conf. This means your environment is misconfigured, in particular check BBPATH.\n') 793 status.addresult('You are not using the OpenEmbedded version of conf/bitbake.conf. This means your environment is misconfigured, in particular check BBPATH.\n')
733 794
734 # The length of TMPDIR can't be longer than 410 795 # The length of TMPDIR can't be longer than 400
735 status.addresult(check_path_length(tmpdir, "TMPDIR", 410)) 796 status.addresult(check_path_length(tmpdir, "TMPDIR", 400))
797
798 # Check that TOPDIR does not contain non ascii chars (perl_5.40.0, Perl-native and shadow-native build failures)
799 status.addresult(check_non_ascii(topdir, "TOPDIR"))
736 800
737 # Check that TMPDIR isn't located on nfs 801 # Check that TMPDIR isn't located on nfs
738 status.addresult(check_not_nfs(tmpdir, "TMPDIR")) 802 status.addresult(check_not_nfs(tmpdir, "TMPDIR"))
@@ -741,6 +805,14 @@ def check_sanity_version_change(status, d):
741 # macOS with default HFS+ file system) 805 # macOS with default HFS+ file system)
742 status.addresult(check_case_sensitive(tmpdir, "TMPDIR")) 806 status.addresult(check_case_sensitive(tmpdir, "TMPDIR"))
743 807
808 # Check if linking with lstdc++ is failing
809 status.addresult(check_cpp_toolchain_flag(d, "-lstdc++"))
810
811 # Check if the C++ toochain support the "--std=gnu++20" flag
812 status.addresult(check_cpp_toolchain_flag(d, "--std=gnu++20",
813 "An error occurred during checking the C++ toolchain for '--std=gnu++20' support. "
814 "Please use a g++ compiler that supports C++20 (e.g. g++ version 10 onwards)."))
815
744def sanity_check_locale(d): 816def sanity_check_locale(d):
745 """ 817 """
746 Currently bitbake switches locale to en_US.UTF-8 so check that this locale actually exists. 818 Currently bitbake switches locale to en_US.UTF-8 so check that this locale actually exists.
@@ -759,10 +831,10 @@ def check_sanity_everybuild(status, d):
759 if 0 == os.getuid(): 831 if 0 == os.getuid():
760 raise_sanity_error("Do not use Bitbake as root.", d) 832 raise_sanity_error("Do not use Bitbake as root.", d)
761 833
762 # Check the Python version, we now have a minimum of Python 3.8 834 # Check the Python version, we now have a minimum of Python 3.9
763 import sys 835 import sys
764 if sys.hexversion < 0x030800F0: 836 if sys.hexversion < 0x030900F0:
765 status.addresult('The system requires at least Python 3.8 to run. Please update your Python interpreter.\n') 837 status.addresult('The system requires at least Python 3.9 to run. Please update your Python interpreter.\n')
766 838
767 # Check the bitbake version meets minimum requirements 839 # Check the bitbake version meets minimum requirements
768 minversion = d.getVar('BB_MIN_VERSION') 840 minversion = d.getVar('BB_MIN_VERSION')