diff options
Diffstat (limited to 'meta/classes-global/sanity.bbclass')
-rw-r--r-- | meta/classes-global/sanity.bbclass | 99 |
1 files changed, 82 insertions, 17 deletions
diff --git a/meta/classes-global/sanity.bbclass b/meta/classes-global/sanity.bbclass index 180c6b77d8..1044ed9cc6 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 | ||
302 | def 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 | |||
302 | def get_filesystem_id(path): | 307 | def 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 | ||
483 | def 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 | # |
486 | def check_gcc_version(sanity_data): | 516 | def 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 | ||
498 | def check_tar_version(sanity_data): | 526 | def 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 | ||
607 | def 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 | |||
577 | def sanity_handle_abichanges(status, d): | 629 | def sanity_handle_abichanges(status, d): |
578 | # | 630 | # |
579 | # Check the 'ABI' of TMPDIR | 631 | # Check the 'ABI' of TMPDIR |
@@ -638,17 +690,18 @@ def check_sanity_version_change(status, d): | |||
638 | status.addresult(check_git_version(d)) | 690 | status.addresult(check_git_version(d)) |
639 | status.addresult(check_perl_modules(d)) | 691 | status.addresult(check_perl_modules(d)) |
640 | status.addresult(check_wsl(d)) | 692 | status.addresult(check_wsl(d)) |
693 | status.addresult(check_userns()) | ||
641 | 694 | ||
642 | missing = "" | 695 | missing = "" |
643 | 696 | ||
644 | if not check_app_exists("${MAKE}", d): | 697 | if not check_app_exists("${MAKE}", d): |
645 | missing = missing + "GNU make," | 698 | missing = missing + "GNU make," |
646 | 699 | ||
647 | if not check_app_exists('${BUILD_CC}', d): | 700 | if not check_app_exists('gcc', d): |
648 | missing = missing + "C Compiler (%s)," % d.getVar("BUILD_CC") | 701 | missing = missing + "C Compiler (gcc)," |
649 | 702 | ||
650 | if not check_app_exists('${BUILD_CXX}', d): | 703 | if not check_app_exists('g++', d): |
651 | missing = missing + "C++ Compiler (%s)," % d.getVar("BUILD_CXX") | 704 | missing = missing + "C++ Compiler (g++)," |
652 | 705 | ||
653 | required_utilities = d.getVar('SANITY_REQUIRED_UTILITIES') | 706 | required_utilities = d.getVar('SANITY_REQUIRED_UTILITIES') |
654 | 707 | ||
@@ -668,6 +721,7 @@ def check_sanity_version_change(status, d): | |||
668 | # Check that TMPDIR isn't on a filesystem with limited filename length (eg. eCryptFS) | 721 | # Check that TMPDIR isn't on a filesystem with limited filename length (eg. eCryptFS) |
669 | import stat | 722 | import stat |
670 | tmpdir = d.getVar('TMPDIR') | 723 | tmpdir = d.getVar('TMPDIR') |
724 | topdir = d.getVar('TOPDIR') | ||
671 | status.addresult(check_create_long_filename(tmpdir, "TMPDIR")) | 725 | status.addresult(check_create_long_filename(tmpdir, "TMPDIR")) |
672 | tmpdirmode = os.stat(tmpdir).st_mode | 726 | tmpdirmode = os.stat(tmpdir).st_mode |
673 | if (tmpdirmode & stat.S_ISGID): | 727 | if (tmpdirmode & stat.S_ISGID): |
@@ -676,14 +730,14 @@ def check_sanity_version_change(status, d): | |||
676 | status.addresult("TMPDIR is setuid, please don't build in a setuid directory") | 730 | status.addresult("TMPDIR is setuid, please don't build in a setuid directory") |
677 | 731 | ||
678 | # Check that a user isn't building in a path in PSEUDO_IGNORE_PATHS | 732 | # Check that a user isn't building in a path in PSEUDO_IGNORE_PATHS |
679 | pseudoignorepaths = d.getVar('PSEUDO_IGNORE_PATHS', expand=True).split(",") | 733 | pseudoignorepaths = (d.getVar('PSEUDO_IGNORE_PATHS', expand=True) or "").split(",") |
680 | workdir = d.getVar('WORKDIR', expand=True) | 734 | workdir = d.getVar('WORKDIR', expand=True) |
681 | for i in pseudoignorepaths: | 735 | for i in pseudoignorepaths: |
682 | if i and workdir.startswith(i): | 736 | 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") | 737 | status.addresult("You are building in a path included in PSEUDO_IGNORE_PATHS " + str(i) + " please locate the build outside this path.\n") |
684 | 738 | ||
685 | # Check if PSEUDO_IGNORE_PATHS and paths under pseudo control overlap | 739 | # Check if PSEUDO_IGNORE_PATHS and paths under pseudo control overlap |
686 | pseudoignorepaths = d.getVar('PSEUDO_IGNORE_PATHS', expand=True).split(",") | 740 | pseudoignorepaths = (d.getVar('PSEUDO_IGNORE_PATHS', expand=True) or "").split(",") |
687 | pseudo_control_dir = "${D},${PKGD},${PKGDEST},${IMAGEROOTFS},${SDK_OUTPUT}" | 741 | pseudo_control_dir = "${D},${PKGD},${PKGDEST},${IMAGEROOTFS},${SDK_OUTPUT}" |
688 | pseudocontroldir = d.expand(pseudo_control_dir).split(",") | 742 | pseudocontroldir = d.expand(pseudo_control_dir).split(",") |
689 | for i in pseudoignorepaths: | 743 | for i in pseudoignorepaths: |
@@ -731,8 +785,11 @@ def check_sanity_version_change(status, d): | |||
731 | if not oes_bb_conf: | 785 | 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') | 786 | 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 | 787 | ||
734 | # The length of TMPDIR can't be longer than 410 | 788 | # The length of TMPDIR can't be longer than 400 |
735 | status.addresult(check_path_length(tmpdir, "TMPDIR", 410)) | 789 | status.addresult(check_path_length(tmpdir, "TMPDIR", 400)) |
790 | |||
791 | # Check that TOPDIR does not contain non ascii chars (perl_5.40.0, Perl-native and shadow-native build failures) | ||
792 | status.addresult(check_non_ascii(topdir, "TOPDIR")) | ||
736 | 793 | ||
737 | # Check that TMPDIR isn't located on nfs | 794 | # Check that TMPDIR isn't located on nfs |
738 | status.addresult(check_not_nfs(tmpdir, "TMPDIR")) | 795 | status.addresult(check_not_nfs(tmpdir, "TMPDIR")) |
@@ -741,6 +798,14 @@ def check_sanity_version_change(status, d): | |||
741 | # macOS with default HFS+ file system) | 798 | # macOS with default HFS+ file system) |
742 | status.addresult(check_case_sensitive(tmpdir, "TMPDIR")) | 799 | status.addresult(check_case_sensitive(tmpdir, "TMPDIR")) |
743 | 800 | ||
801 | # Check if linking with lstdc++ is failing | ||
802 | status.addresult(check_cpp_toolchain_flag(d, "-lstdc++")) | ||
803 | |||
804 | # Check if the C++ toochain support the "--std=gnu++20" flag | ||
805 | status.addresult(check_cpp_toolchain_flag(d, "--std=gnu++20", | ||
806 | "An error occurred during checking the C++ toolchain for '--std=gnu++20' support. " | ||
807 | "Please use a g++ compiler that supports C++20 (e.g. g++ version 10 onwards).")) | ||
808 | |||
744 | def sanity_check_locale(d): | 809 | def sanity_check_locale(d): |
745 | """ | 810 | """ |
746 | Currently bitbake switches locale to en_US.UTF-8 so check that this locale actually exists. | 811 | Currently bitbake switches locale to en_US.UTF-8 so check that this locale actually exists. |
@@ -759,10 +824,10 @@ def check_sanity_everybuild(status, d): | |||
759 | if 0 == os.getuid(): | 824 | if 0 == os.getuid(): |
760 | raise_sanity_error("Do not use Bitbake as root.", d) | 825 | raise_sanity_error("Do not use Bitbake as root.", d) |
761 | 826 | ||
762 | # Check the Python version, we now have a minimum of Python 3.8 | 827 | # Check the Python version, we now have a minimum of Python 3.9 |
763 | import sys | 828 | import sys |
764 | if sys.hexversion < 0x030800F0: | 829 | if sys.hexversion < 0x030900F0: |
765 | status.addresult('The system requires at least Python 3.8 to run. Please update your Python interpreter.\n') | 830 | status.addresult('The system requires at least Python 3.9 to run. Please update your Python interpreter.\n') |
766 | 831 | ||
767 | # Check the bitbake version meets minimum requirements | 832 | # Check the bitbake version meets minimum requirements |
768 | minversion = d.getVar('BB_MIN_VERSION') | 833 | minversion = d.getVar('BB_MIN_VERSION') |