summaryrefslogtreecommitdiffstats
path: root/meta
diff options
context:
space:
mode:
Diffstat (limited to 'meta')
-rw-r--r--meta/classes-global/base.bbclass1
-rw-r--r--meta/classes-global/sstate.bbclass12
-rw-r--r--meta/classes-recipe/go-mod-update-modules.bbclass152
-rw-r--r--meta/classes-recipe/go-mod.bbclass2
-rw-r--r--meta/classes-recipe/testsdk.bbclass1
-rw-r--r--meta/classes/create-spdx-2.2.bbclass8
-rw-r--r--meta/conf/bitbake.conf2
-rw-r--r--meta/conf/distro/include/maintainers.inc2
-rw-r--r--meta/conf/distro/include/ptest-packagelists.inc1
-rw-r--r--meta/conf/sanity.conf2
-rw-r--r--meta/lib/oe/license.py15
-rw-r--r--meta/lib/oeqa/buildtools-docs/cases/README (renamed from meta/lib/oeqa/sdk/buildtools-docs-cases/README)0
-rw-r--r--meta/lib/oeqa/buildtools-docs/cases/build.py (renamed from meta/lib/oeqa/sdk/buildtools-docs-cases/build.py)0
-rw-r--r--meta/lib/oeqa/buildtools/cases/README (renamed from meta/lib/oeqa/sdk/buildtools-cases/README)0
-rw-r--r--meta/lib/oeqa/buildtools/cases/build.py (renamed from meta/lib/oeqa/sdk/buildtools-cases/build.py)0
-rw-r--r--meta/lib/oeqa/buildtools/cases/gcc.py (renamed from meta/lib/oeqa/sdk/buildtools-cases/gcc.py)0
-rw-r--r--meta/lib/oeqa/buildtools/cases/https.py (renamed from meta/lib/oeqa/sdk/buildtools-cases/https.py)0
-rw-r--r--meta/lib/oeqa/buildtools/cases/sanity.py (renamed from meta/lib/oeqa/sdk/buildtools-cases/sanity.py)0
-rw-r--r--meta/lib/oeqa/sdk/testsdk.py24
-rw-r--r--meta/lib/oeqa/selftest/cases/devtool.py2
-rw-r--r--meta/lib/oeqa/selftest/cases/recipetool.py33
-rw-r--r--meta/recipes-core/meta/buildtools-docs-tarball.bb5
-rw-r--r--meta/recipes-core/meta/buildtools-tarball.bb21
-rw-r--r--meta/recipes-devtools/dosfstools/dosfstools/0001-fsck.fat-Adhere-to-the-fsck-exit-codes.patch214
-rw-r--r--meta/recipes-devtools/dosfstools/dosfstools/0002-manpages-Document-fsck.fat-new-exit-codes.patch46
-rw-r--r--meta/recipes-devtools/dosfstools/dosfstools_4.2.bb7
-rw-r--r--meta/recipes-devtools/json-c/json-c_0.18.bb3
-rw-r--r--meta/recipes-devtools/mtools/mtools_4.0.49.bb (renamed from meta/recipes-devtools/mtools/mtools_4.0.48.bb)2
-rw-r--r--meta/recipes-devtools/ninja/ninja_1.13.0.bb (renamed from meta/recipes-devtools/ninja/ninja_1.12.1.bb)10
-rw-r--r--meta/recipes-devtools/python/python3-sphinx-argparse_0.5.2.bb13
-rw-r--r--meta/recipes-devtools/python/python3-sphinx-copybutton_0.5.2.bb10
-rw-r--r--meta/recipes-devtools/python/python3-urllib3_2.5.0.bb (renamed from meta/recipes-devtools/python/python3-urllib3_2.4.0.bb)2
-rw-r--r--meta/recipes-devtools/python/python3-wheel_0.46.1.bb (renamed from meta/recipes-devtools/python/python3-wheel_0.45.1.bb)9
-rw-r--r--meta/recipes-devtools/tcf-agent/tcf-agent_1.8.0.bb6
34 files changed, 539 insertions, 66 deletions
diff --git a/meta/classes-global/base.bbclass b/meta/classes-global/base.bbclass
index b86f50e283..ac145d9fd6 100644
--- a/meta/classes-global/base.bbclass
+++ b/meta/classes-global/base.bbclass
@@ -154,6 +154,7 @@ do_fetch[file-checksums] = "${@bb.fetch.get_checksum_file_list(d)}"
154do_fetch[file-checksums] += " ${@get_lic_checksum_file_list(d)}" 154do_fetch[file-checksums] += " ${@get_lic_checksum_file_list(d)}"
155do_fetch[prefuncs] += "fetcher_hashes_dummyfunc" 155do_fetch[prefuncs] += "fetcher_hashes_dummyfunc"
156do_fetch[network] = "1" 156do_fetch[network] = "1"
157do_fetch[umask] = "${OE_SHARED_UMASK}"
157python base_do_fetch() { 158python base_do_fetch() {
158 159
159 src_uri = (d.getVar('SRC_URI') or "").split() 160 src_uri = (d.getVar('SRC_URI') or "").split()
diff --git a/meta/classes-global/sstate.bbclass b/meta/classes-global/sstate.bbclass
index 2968cc4c2e..53bc2e3940 100644
--- a/meta/classes-global/sstate.bbclass
+++ b/meta/classes-global/sstate.bbclass
@@ -745,7 +745,7 @@ def pstaging_fetch(sstatefetch, d):
745 if bb.utils.to_boolean(d.getVar("SSTATE_VERIFY_SIG"), False): 745 if bb.utils.to_boolean(d.getVar("SSTATE_VERIFY_SIG"), False):
746 uris += ['file://{0}.sig;downloadfilename={0}.sig'.format(sstatefetch)] 746 uris += ['file://{0}.sig;downloadfilename={0}.sig'.format(sstatefetch)]
747 747
748 with bb.utils.umask(0o002): 748 with bb.utils.umask(bb.utils.to_filemode(d.getVar("OE_SHARED_UMASK"))):
749 bb.utils.mkdirhier(dldir) 749 bb.utils.mkdirhier(dldir)
750 750
751 for srcuri in uris: 751 for srcuri in uris:
@@ -776,9 +776,10 @@ sstate_task_prefunc[dirs] = "${WORKDIR}"
776python sstate_task_postfunc () { 776python sstate_task_postfunc () {
777 shared_state = sstate_state_fromvars(d) 777 shared_state = sstate_state_fromvars(d)
778 778
779 omask = os.umask(0o002) 779 shared_umask = bb.utils.to_filemode(d.getVar("OE_SHARED_UMASK"))
780 if omask != 0o002: 780 omask = os.umask(shared_umask)
781 bb.note("Using umask 0o002 (not %0o) for sstate packaging" % omask) 781 if omask != shared_umask:
782 bb.note("Using umask %0o (not %0o) for sstate packaging" % (shared_umask, omask))
782 sstate_package(shared_state, d) 783 sstate_package(shared_state, d)
783 os.umask(omask) 784 os.umask(omask)
784 785
@@ -843,7 +844,8 @@ python sstate_create_and_sign_package () {
843 844
844 # Create the required sstate directory if it is not present. 845 # Create the required sstate directory if it is not present.
845 if not sstate_pkg.parent.is_dir(): 846 if not sstate_pkg.parent.is_dir():
846 with bb.utils.umask(0o002): 847 shared_umask = bb.utils.to_filemode(d.getVar("OE_SHARED_UMASK"))
848 with bb.utils.umask(shared_umask):
847 bb.utils.mkdirhier(str(sstate_pkg.parent)) 849 bb.utils.mkdirhier(str(sstate_pkg.parent))
848 850
849 if sign_pkg: 851 if sign_pkg:
diff --git a/meta/classes-recipe/go-mod-update-modules.bbclass b/meta/classes-recipe/go-mod-update-modules.bbclass
new file mode 100644
index 0000000000..5fccd0bb0d
--- /dev/null
+++ b/meta/classes-recipe/go-mod-update-modules.bbclass
@@ -0,0 +1,152 @@
1addtask do_update_modules after do_configure
2do_update_modules[nostamp] = "1"
3do_update_modules[network] = "1"
4
5# This class maintains two files, BPN-go-mods.inc and BPN-licenses.inc.
6#
7# -go-mods.inc will append SRC_URI with all of the Go modules that are
8# dependencies of this recipe.
9#
10# -licenses.inc will append LICENSE and LIC_FILES_CHKSUM with the found licenses
11# in the modules.
12#
13# These files are machine-generated and should not be modified.
14
15python do_update_modules() {
16 import subprocess, tempfile, json, re, urllib.parse
17 from oe.license import tidy_licenses
18 from oe.license_finder import find_licenses
19
20 def unescape_path(path):
21 """Unescape capital letters using exclamation points."""
22 return re.sub(r'!([a-z])', lambda m: m.group(1).upper(), path)
23
24 def fold_uri(uri):
25 """Fold URI for sorting shorter module paths before longer."""
26 return uri.replace(';', ' ').replace('/', '!')
27
28 def parse_existing_licenses():
29 hashes = {}
30 for url in d.getVar("LIC_FILES_CHKSUM").split():
31 (method, host, path, user, pswd, parm) = bb.fetch.decodeurl(url)
32 if "spdx" in parm and parm["spdx"] != "Unknown":
33 hashes[parm["md5"]] = urllib.parse.unquote_plus(parm["spdx"])
34 return hashes
35
36 bpn = d.getVar("BPN")
37 thisdir = d.getVar("THISDIR")
38 s_dir = d.getVar("S")
39
40 with tempfile.TemporaryDirectory(prefix='go-mod-') as mod_cache_dir:
41 notice = """
42# This file has been generated by go-mod-update-modules.bbclass
43#
44# Do not modify it by hand, as the contents will be replaced when
45# running the update-modules task.
46
47"""
48
49 env = dict(os.environ, GOMODCACHE=mod_cache_dir)
50
51 source = d.expand("${UNPACKDIR}/${GO_SRCURI_DESTSUFFIX}")
52 output = subprocess.check_output(("go", "mod", "edit", "-json"), cwd=source, env=env, text=True)
53 go_mod = json.loads(output)
54
55 output = subprocess.check_output(("go", "list", "-json=Dir,Module", "-deps", f"{go_mod['Module']['Path']}/..."), cwd=source, env=env, text=True)
56
57 #
58 # Licenses
59 #
60
61 # load hashes from the existing licenses.inc
62 extra_hashes = parse_existing_licenses()
63
64 # The output of this isn't actually valid JSON, but a series of dicts.
65 # Wrap in [] and join the dicts with ,
66 # Very frustrating that the json parser in python can't repeatedly
67 # parse from a stream.
68 pkgs = json.loads('[' + output.replace('}\n{', '},\n{') + ']')
69 # Collect licenses for the dependencies.
70 licenses = set()
71 lic_files_chksum = []
72 lic_files = {}
73
74 for pkg in pkgs:
75 mod = pkg.get('Module', None)
76 if not mod or mod.get('Main', False):
77 continue
78
79 mod_dir = mod['Dir']
80
81 if not mod_dir.startswith(mod_cache_dir):
82 continue
83
84 path = os.path.relpath(mod_dir, mod_cache_dir)
85
86 for license_name, license_file, license_md5 in find_licenses(mod['Dir'], d, first_only=True, extra_hashes=extra_hashes):
87 lic_files[os.path.join(path, license_file)] = (license_name, license_md5)
88
89 for lic_file in lic_files:
90 license_name, license_md5 = lic_files[lic_file]
91 if license_name == "Unknown":
92 bb.warn(f"Unknown license: {lic_file} {license_md5}")
93
94 licenses.add(lic_files[lic_file][0])
95 lic_files_chksum.append(
96 f'file://pkg/mod/{lic_file};md5={license_md5};spdx={urllib.parse.quote_plus(license_name)}')
97
98 licenses_filename = os.path.join(thisdir, f"{bpn}-licenses.inc")
99 with open(licenses_filename, "w") as f:
100 f.write(notice)
101 f.write(f'LICENSE += "& {" & ".join(tidy_licenses(licenses))}"\n\n')
102 f.write('LIC_FILES_CHKSUM += "\\\n')
103 for lic in sorted(lic_files_chksum, key=fold_uri):
104 f.write(' ' + lic + ' \\\n')
105 f.write('"\n')
106
107 #
108 # Sources
109 #
110
111 # Collect the module cache files downloaded by the go list command as
112 # the go list command knows best what the go list command needs and it
113 # needs more files in the module cache than the go install command as
114 # it doesn't do the dependency pruning mentioned in the Go module
115 # reference, https://go.dev/ref/mod, for go 1.17 or higher.
116 src_uris = []
117 downloaddir = os.path.join(mod_cache_dir, 'cache', 'download')
118 for dirpath, _, filenames in os.walk(downloaddir):
119 # We want to process files under @v directories
120 path, base = os.path.split(os.path.relpath(dirpath, downloaddir))
121 if base != '@v':
122 continue
123
124 path = unescape_path(path)
125 zipver = None
126 for name in filenames:
127 ver, ext = os.path.splitext(name)
128 if ext == '.zip':
129 chksum = bb.utils.sha256_file(os.path.join(dirpath, name))
130 src_uris.append(f'gomod://{path};version={ver};sha256sum={chksum}')
131 zipver = ver
132 break
133 for name in filenames:
134 ver, ext = os.path.splitext(name)
135 if ext == '.mod' and ver != zipver:
136 chksum = bb.utils.sha256_file(os.path.join(dirpath, name))
137 src_uris.append(f'gomod://{path};version={ver};mod=1;sha256sum={chksum}')
138
139
140 go_mods_filename = os.path.join(thisdir, f"{bpn}-go-mods.inc")
141 with open(go_mods_filename, "w") as f:
142 f.write(notice)
143 f.write('SRC_URI += "\\\n')
144 for uri in sorted(src_uris, key=fold_uri):
145 f.write(' ' + uri + ' \\\n')
146 f.write('"\n')
147
148 subprocess.check_output(("go", "clean", "-modcache"), cwd=source, env=env, text=True)
149}
150
151# This doesn't work as we need to wipe the inc files first so we don't try looking for LICENSE files that don't yet exist
152# RECIPE_UPGRADE_EXTRA_TASKS += "do_update_modules"
diff --git a/meta/classes-recipe/go-mod.bbclass b/meta/classes-recipe/go-mod.bbclass
index 93ae72235f..a15dda8f0e 100644
--- a/meta/classes-recipe/go-mod.bbclass
+++ b/meta/classes-recipe/go-mod.bbclass
@@ -23,7 +23,7 @@ GOBUILDFLAGS:append = " -modcacherw"
23inherit go 23inherit go
24 24
25export GOMODCACHE = "${S}/pkg/mod" 25export GOMODCACHE = "${S}/pkg/mod"
26GO_MOD_CACHE_DIR = "${@os.path.relpath(d.getVar('GOMODCACHE'), d.getVar('WORKDIR'))}" 26GO_MOD_CACHE_DIR = "${@os.path.relpath(d.getVar('GOMODCACHE'), d.getVar('UNPACKDIR'))}"
27do_unpack[cleandirs] += "${GOMODCACHE}" 27do_unpack[cleandirs] += "${GOMODCACHE}"
28 28
29GO_WORKDIR ?= "${GO_IMPORT}" 29GO_WORKDIR ?= "${GO_IMPORT}"
diff --git a/meta/classes-recipe/testsdk.bbclass b/meta/classes-recipe/testsdk.bbclass
index 59d2834c99..b1c4fa67e6 100644
--- a/meta/classes-recipe/testsdk.bbclass
+++ b/meta/classes-recipe/testsdk.bbclass
@@ -19,6 +19,7 @@ TESTSDK_SUITES ?= ""
19 19
20TESTSDK_CLASS_NAME ?= "oeqa.sdk.testsdk.TestSDK" 20TESTSDK_CLASS_NAME ?= "oeqa.sdk.testsdk.TestSDK"
21TESTSDKEXT_CLASS_NAME ?= "oeqa.sdkext.testsdk.TestSDKExt" 21TESTSDKEXT_CLASS_NAME ?= "oeqa.sdkext.testsdk.TestSDKExt"
22TESTSDK_CASE_DIRS ?= "sdk"
22 23
23def import_and_run(name, d): 24def import_and_run(name, d):
24 import importlib 25 import importlib
diff --git a/meta/classes/create-spdx-2.2.bbclass b/meta/classes/create-spdx-2.2.bbclass
index 6fc60a1d97..94e0108815 100644
--- a/meta/classes/create-spdx-2.2.bbclass
+++ b/meta/classes/create-spdx-2.2.bbclass
@@ -23,6 +23,8 @@ def get_namespace(d, name):
23 namespace_uuid = uuid.uuid5(uuid.NAMESPACE_DNS, d.getVar("SPDX_UUID_NAMESPACE")) 23 namespace_uuid = uuid.uuid5(uuid.NAMESPACE_DNS, d.getVar("SPDX_UUID_NAMESPACE"))
24 return "%s/%s-%s" % (d.getVar("SPDX_NAMESPACE_PREFIX"), name, str(uuid.uuid5(namespace_uuid, name))) 24 return "%s/%s-%s" % (d.getVar("SPDX_NAMESPACE_PREFIX"), name, str(uuid.uuid5(namespace_uuid, name)))
25 25
26SPDX_PACKAGE_VERSION ??= "${PV}"
27SPDX_PACKAGE_VERSION[doc] = "The version of a package, versionInfo in recipe, package and image"
26 28
27def create_annotation(d, comment): 29def create_annotation(d, comment):
28 from datetime import datetime, timezone 30 from datetime import datetime, timezone
@@ -447,7 +449,7 @@ python do_create_spdx() {
447 449
448 recipe = oe.spdx.SPDXPackage() 450 recipe = oe.spdx.SPDXPackage()
449 recipe.name = d.getVar("PN") 451 recipe.name = d.getVar("PN")
450 recipe.versionInfo = d.getVar("PV") 452 recipe.versionInfo = d.getVar("SPDX_PACKAGE_VERSION")
451 recipe.SPDXID = oe.sbom.get_recipe_spdxid(d) 453 recipe.SPDXID = oe.sbom.get_recipe_spdxid(d)
452 recipe.supplier = d.getVar("SPDX_SUPPLIER") 454 recipe.supplier = d.getVar("SPDX_SUPPLIER")
453 if bb.data.inherits_class("native", d) or bb.data.inherits_class("cross", d): 455 if bb.data.inherits_class("native", d) or bb.data.inherits_class("cross", d):
@@ -556,7 +558,7 @@ python do_create_spdx() {
556 558
557 spdx_package.SPDXID = oe.sbom.get_package_spdxid(pkg_name) 559 spdx_package.SPDXID = oe.sbom.get_package_spdxid(pkg_name)
558 spdx_package.name = pkg_name 560 spdx_package.name = pkg_name
559 spdx_package.versionInfo = d.getVar("PV") 561 spdx_package.versionInfo = d.getVar("SPDX_PACKAGE_VERSION")
560 spdx_package.licenseDeclared = convert_license_to_spdx(package_license, license_data, package_doc, d, found_licenses) 562 spdx_package.licenseDeclared = convert_license_to_spdx(package_license, license_data, package_doc, d, found_licenses)
561 spdx_package.supplier = d.getVar("SPDX_SUPPLIER") 563 spdx_package.supplier = d.getVar("SPDX_SUPPLIER")
562 564
@@ -832,7 +834,7 @@ def combine_spdx(d, rootfs_name, rootfs_deploydir, rootfs_spdxid, packages, spdx
832 834
833 image = oe.spdx.SPDXPackage() 835 image = oe.spdx.SPDXPackage()
834 image.name = d.getVar("PN") 836 image.name = d.getVar("PN")
835 image.versionInfo = d.getVar("PV") 837 image.versionInfo = d.getVar("SPDX_PACKAGE_VERSION")
836 image.SPDXID = rootfs_spdxid 838 image.SPDXID = rootfs_spdxid
837 image.supplier = d.getVar("SPDX_SUPPLIER") 839 image.supplier = d.getVar("SPDX_SUPPLIER")
838 840
diff --git a/meta/conf/bitbake.conf b/meta/conf/bitbake.conf
index a3300fc172..b1f8ac5b11 100644
--- a/meta/conf/bitbake.conf
+++ b/meta/conf/bitbake.conf
@@ -944,6 +944,8 @@ TRANSLATED_TARGET_ARCH ??= "${@d.getVar('TARGET_ARCH').replace("_", "-")}"
944 944
945# Set a default umask to use for tasks for determinism 945# Set a default umask to use for tasks for determinism
946BB_DEFAULT_UMASK ??= "022" 946BB_DEFAULT_UMASK ??= "022"
947# The umask to use for shared files (e.g. DL_DIR and SSTATE_DIR)
948OE_SHARED_UMASK ??= "002"
947 949
948# Complete output from bitbake 950# Complete output from bitbake
949BB_CONSOLELOG ?= "${LOG_DIR}/cooker/${MACHINE}/${DATETIME}.log" 951BB_CONSOLELOG ?= "${LOG_DIR}/cooker/${MACHINE}/${DATETIME}.log"
diff --git a/meta/conf/distro/include/maintainers.inc b/meta/conf/distro/include/maintainers.inc
index d94fb693e3..4d51219c94 100644
--- a/meta/conf/distro/include/maintainers.inc
+++ b/meta/conf/distro/include/maintainers.inc
@@ -718,6 +718,8 @@ RECIPE_MAINTAINER:pn-python3-snowballstemmer = "Tim Orling <tim.orling@konsulko.
718RECIPE_MAINTAINER:pn-python3-sortedcontainers = "Tim Orling <tim.orling@konsulko.com>" 718RECIPE_MAINTAINER:pn-python3-sortedcontainers = "Tim Orling <tim.orling@konsulko.com>"
719RECIPE_MAINTAINER:pn-python3-spdx-tools = "Marta Rybczynska <marta.rybczynska@ygreky.com>" 719RECIPE_MAINTAINER:pn-python3-spdx-tools = "Marta Rybczynska <marta.rybczynska@ygreky.com>"
720RECIPE_MAINTAINER:pn-python3-sphinx = "Trevor Gamblin <tgamblin@baylibre.com>" 720RECIPE_MAINTAINER:pn-python3-sphinx = "Trevor Gamblin <tgamblin@baylibre.com>"
721RECIPE_MAINTAINER:pn-python3-sphinx-argparse = "Antonin Godard <antonin.godard@bootlin.com>"
722RECIPE_MAINTAINER:pn-python3-sphinx-copybutton = "Antonin Godard <antonin.godard@bootlin.com>"
721RECIPE_MAINTAINER:pn-python3-sphinx-rtd-theme = "Tim Orling <tim.orling@konsulko.com>" 723RECIPE_MAINTAINER:pn-python3-sphinx-rtd-theme = "Tim Orling <tim.orling@konsulko.com>"
722RECIPE_MAINTAINER:pn-python3-sphinxcontrib-applehelp = "Tim Orling <tim.orling@konsulko.com>" 724RECIPE_MAINTAINER:pn-python3-sphinxcontrib-applehelp = "Tim Orling <tim.orling@konsulko.com>"
723RECIPE_MAINTAINER:pn-python3-sphinxcontrib-devhelp = "Tim Orling <tim.orling@konsulko.com>" 725RECIPE_MAINTAINER:pn-python3-sphinxcontrib-devhelp = "Tim Orling <tim.orling@konsulko.com>"
diff --git a/meta/conf/distro/include/ptest-packagelists.inc b/meta/conf/distro/include/ptest-packagelists.inc
index e06731ece7..4253c7b062 100644
--- a/meta/conf/distro/include/ptest-packagelists.inc
+++ b/meta/conf/distro/include/ptest-packagelists.inc
@@ -78,6 +78,7 @@ PTESTS_FAST = "\
78 python3-uritools \ 78 python3-uritools \
79 python3-wcwidth \ 79 python3-wcwidth \
80 python3-webcolors \ 80 python3-webcolors \
81 python3-wheel \
81 qemu \ 82 qemu \
82 quilt \ 83 quilt \
83 rpm-sequoia \ 84 rpm-sequoia \
diff --git a/meta/conf/sanity.conf b/meta/conf/sanity.conf
index 3692007e96..474816797a 100644
--- a/meta/conf/sanity.conf
+++ b/meta/conf/sanity.conf
@@ -3,7 +3,7 @@
3# See sanity.bbclass 3# See sanity.bbclass
4# 4#
5# Expert users can confirm their sanity with "touch conf/sanity.conf" 5# Expert users can confirm their sanity with "touch conf/sanity.conf"
6BB_MIN_VERSION = "2.15.0" 6BB_MIN_VERSION = "2.15.1"
7 7
8SANITY_ABIFILE = "${TMPDIR}/abi_version" 8SANITY_ABIFILE = "${TMPDIR}/abi_version"
9 9
diff --git a/meta/lib/oe/license.py b/meta/lib/oe/license.py
index 6f882c3812..6e55fa1e7f 100644
--- a/meta/lib/oe/license.py
+++ b/meta/lib/oe/license.py
@@ -462,3 +462,18 @@ def skip_incompatible_package_licenses(d, pkgs):
462 skipped_pkgs[pkg] = incompatible_lic 462 skipped_pkgs[pkg] = incompatible_lic
463 463
464 return skipped_pkgs 464 return skipped_pkgs
465
466def tidy_licenses(value):
467 """
468 Flat, split and sort licenses.
469 """
470 from oe.license import flattened_licenses
471
472 def _choose(a, b):
473 str_a, str_b = sorted((" & ".join(a), " & ".join(b)), key=str.casefold)
474 return ["(%s | %s)" % (str_a, str_b)]
475
476 if not isinstance(value, str):
477 value = " & ".join(value)
478
479 return sorted(list(set(flattened_licenses(value, _choose))), key=str.casefold)
diff --git a/meta/lib/oeqa/sdk/buildtools-docs-cases/README b/meta/lib/oeqa/buildtools-docs/cases/README
index f8edbc7dad..f8edbc7dad 100644
--- a/meta/lib/oeqa/sdk/buildtools-docs-cases/README
+++ b/meta/lib/oeqa/buildtools-docs/cases/README
diff --git a/meta/lib/oeqa/sdk/buildtools-docs-cases/build.py b/meta/lib/oeqa/buildtools-docs/cases/build.py
index 6e3ee94292..6e3ee94292 100644
--- a/meta/lib/oeqa/sdk/buildtools-docs-cases/build.py
+++ b/meta/lib/oeqa/buildtools-docs/cases/build.py
diff --git a/meta/lib/oeqa/sdk/buildtools-cases/README b/meta/lib/oeqa/buildtools/cases/README
index d4f20faa9f..d4f20faa9f 100644
--- a/meta/lib/oeqa/sdk/buildtools-cases/README
+++ b/meta/lib/oeqa/buildtools/cases/README
diff --git a/meta/lib/oeqa/sdk/buildtools-cases/build.py b/meta/lib/oeqa/buildtools/cases/build.py
index c85c32496b..c85c32496b 100644
--- a/meta/lib/oeqa/sdk/buildtools-cases/build.py
+++ b/meta/lib/oeqa/buildtools/cases/build.py
diff --git a/meta/lib/oeqa/sdk/buildtools-cases/gcc.py b/meta/lib/oeqa/buildtools/cases/gcc.py
index a62c4d0bc4..a62c4d0bc4 100644
--- a/meta/lib/oeqa/sdk/buildtools-cases/gcc.py
+++ b/meta/lib/oeqa/buildtools/cases/gcc.py
diff --git a/meta/lib/oeqa/sdk/buildtools-cases/https.py b/meta/lib/oeqa/buildtools/cases/https.py
index 4525e3d758..4525e3d758 100644
--- a/meta/lib/oeqa/sdk/buildtools-cases/https.py
+++ b/meta/lib/oeqa/buildtools/cases/https.py
diff --git a/meta/lib/oeqa/sdk/buildtools-cases/sanity.py b/meta/lib/oeqa/buildtools/cases/sanity.py
index a55d456656..a55d456656 100644
--- a/meta/lib/oeqa/sdk/buildtools-cases/sanity.py
+++ b/meta/lib/oeqa/buildtools/cases/sanity.py
diff --git a/meta/lib/oeqa/sdk/testsdk.py b/meta/lib/oeqa/sdk/testsdk.py
index 52b702b6a2..cffcf9f49a 100644
--- a/meta/lib/oeqa/sdk/testsdk.py
+++ b/meta/lib/oeqa/sdk/testsdk.py
@@ -31,6 +31,28 @@ class TestSDK(TestSDKBase):
31 context_class = OESDKTestContext 31 context_class = OESDKTestContext
32 test_type = 'sdk' 32 test_type = 'sdk'
33 33
34 def sdk_dir_names(self, d):
35 """Return list from TESTSDK_CASE_DIRS."""
36 testdirs = d.getVar("TESTSDK_CASE_DIRS")
37 if testdirs:
38 return testdirs.split()
39
40 bb.fatal("TESTSDK_CASE_DIRS unset, can't find SDK test directories.")
41
42 def get_sdk_paths(self, d):
43 """
44 Return a list of paths where SDK test cases reside.
45
46 SDK tests are expected in <LAYER_DIR>/lib/oeqa/<dirname>/cases
47 """
48 paths = []
49 for layer in d.getVar("BBLAYERS").split():
50 for dirname in self.sdk_dir_names(d):
51 case_path = os.path.join(layer, "lib", "oeqa", dirname, "cases")
52 if os.path.isdir(case_path):
53 paths.append(case_path)
54 return paths
55
34 def get_tcname(self, d): 56 def get_tcname(self, d):
35 """ 57 """
36 Get the name of the SDK file 58 Get the name of the SDK file
@@ -115,7 +137,7 @@ class TestSDK(TestSDKBase):
115 137
116 try: 138 try:
117 modules = (d.getVar("TESTSDK_SUITES") or "").split() 139 modules = (d.getVar("TESTSDK_SUITES") or "").split()
118 tc.loadTests(self.context_executor_class.default_cases, modules) 140 tc.loadTests(self.get_sdk_paths(d), modules)
119 except Exception as e: 141 except Exception as e:
120 import traceback 142 import traceback
121 bb.fatal("Loading tests failed:\n%s" % traceback.format_exc()) 143 bb.fatal("Loading tests failed:\n%s" % traceback.format_exc())
diff --git a/meta/lib/oeqa/selftest/cases/devtool.py b/meta/lib/oeqa/selftest/cases/devtool.py
index 74a7727cc0..05f228f03e 100644
--- a/meta/lib/oeqa/selftest/cases/devtool.py
+++ b/meta/lib/oeqa/selftest/cases/devtool.py
@@ -154,7 +154,7 @@ class DevtoolTestCase(OESelftestTestCase):
154 value = invalue 154 value = invalue
155 invar = None 155 invar = None
156 elif '=' in line: 156 elif '=' in line:
157 splitline = line.split('=', 1) 157 splitline = re.split(r"[?+:]*=[+]?", line, 1)
158 var = splitline[0].rstrip() 158 var = splitline[0].rstrip()
159 value = splitline[1].strip().strip('"') 159 value = splitline[1].strip().strip('"')
160 if value.endswith('\\'): 160 if value.endswith('\\'):
diff --git a/meta/lib/oeqa/selftest/cases/recipetool.py b/meta/lib/oeqa/selftest/cases/recipetool.py
index 2a91f6c7ae..0bd724c8ee 100644
--- a/meta/lib/oeqa/selftest/cases/recipetool.py
+++ b/meta/lib/oeqa/selftest/cases/recipetool.py
@@ -757,13 +757,12 @@ class RecipetoolCreateTests(RecipetoolBase):
757 757
758 def test_recipetool_create_go(self): 758 def test_recipetool_create_go(self):
759 # Basic test to check go recipe generation 759 # Basic test to check go recipe generation
760 self.maxDiff = None
761
760 temprecipe = os.path.join(self.tempdir, 'recipe') 762 temprecipe = os.path.join(self.tempdir, 'recipe')
761 os.makedirs(temprecipe) 763 os.makedirs(temprecipe)
762 764
763 recipefile = os.path.join(temprecipe, 'recipetool-go-test_git.bb') 765 recipefile = os.path.join(temprecipe, 'recipetool-go-test_git.bb')
764 deps_require_file = os.path.join(temprecipe, 'recipetool-go-test', 'recipetool-go-test-modules.inc')
765 lics_require_file = os.path.join(temprecipe, 'recipetool-go-test', 'recipetool-go-test-licenses.inc')
766 modules_txt_file = os.path.join(temprecipe, 'recipetool-go-test', 'modules.txt')
767 766
768 srcuri = 'https://git.yoctoproject.org/recipetool-go-test.git' 767 srcuri = 'https://git.yoctoproject.org/recipetool-go-test.git'
769 srcrev = "c3e213c01b6c1406b430df03ef0d1ae77de5d2f7" 768 srcrev = "c3e213c01b6c1406b430df03ef0d1ae77de5d2f7"
@@ -771,13 +770,11 @@ class RecipetoolCreateTests(RecipetoolBase):
771 770
772 result = runCmd('recipetool create -o %s %s -S %s -B %s' % (temprecipe, srcuri, srcrev, srcbranch)) 771 result = runCmd('recipetool create -o %s %s -S %s -B %s' % (temprecipe, srcuri, srcrev, srcbranch))
773 772
774 self.maxDiff = None 773 inherits = ['go-mod', 'go-mod-update-modules']
775 inherits = ['go-vendor']
776 774
777 checkvars = {} 775 checkvars = {}
778 checkvars['GO_IMPORT'] = "git.yoctoproject.org/recipetool-go-test" 776 checkvars['GO_IMPORT'] = "git.yoctoproject.org/recipetool-go-test"
779 checkvars['SRC_URI'] = {'git://${GO_IMPORT};destsuffix=git/src/${GO_IMPORT};nobranch=1;name=${BPN};protocol=https', 777 checkvars['SRC_URI'] = {'git://${GO_IMPORT};protocol=https;nobranch=1;destsuffix=${GO_SRCURI_DESTSUFFIX}'}
780 'file://modules.txt'}
781 checkvars['LIC_FILES_CHKSUM'] = { 778 checkvars['LIC_FILES_CHKSUM'] = {
782 'file://src/${GO_IMPORT}/LICENSE;md5=4e3933dd47afbf115e484d11385fb3bd', 779 'file://src/${GO_IMPORT}/LICENSE;md5=4e3933dd47afbf115e484d11385fb3bd',
783 'file://src/${GO_IMPORT}/is/LICENSE;md5=62beaee5a116dd1e80161667b1df39ab' 780 'file://src/${GO_IMPORT}/is/LICENSE;md5=62beaee5a116dd1e80161667b1df39ab'
@@ -786,26 +783,16 @@ class RecipetoolCreateTests(RecipetoolBase):
786 self._test_recipe_contents(recipefile, checkvars, inherits) 783 self._test_recipe_contents(recipefile, checkvars, inherits)
787 self.assertNotIn('Traceback', result.output) 784 self.assertNotIn('Traceback', result.output)
788 785
786 lics_require_file = os.path.join(temprecipe, 'recipetool-go-test-licenses.inc')
787 self.assertFileExists(lics_require_file)
789 checkvars = {} 788 checkvars = {}
790 checkvars['VENDORED_LIC_FILES_CHKSUM'] = set( 789 checkvars['LIC_FILES_CHKSUM'] = {'file://pkg/mod/github.com/godbus/dbus/v5@v5.1.0/LICENSE;md5=09042bd5c6c96a2b9e45ddf1bc517eed;spdx=BSD-2-Clause'}
791 ['file://src/${GO_IMPORT}/vendor/github.com/godbus/dbus/v5/LICENSE;md5=09042bd5c6c96a2b9e45ddf1bc517eed',
792 'file://src/${GO_IMPORT}/vendor/github.com/matryer/is/LICENSE;md5=62beaee5a116dd1e80161667b1df39ab'])
793 self.assertTrue(os.path.isfile(lics_require_file))
794 self._test_recipe_contents(lics_require_file, checkvars, []) 790 self._test_recipe_contents(lics_require_file, checkvars, [])
795 791
796 # make sure that dependencies don't mention local directory ./matryer/is 792 deps_require_file = os.path.join(temprecipe, 'recipetool-go-test-go-mods.inc')
797 dependencies = \ 793 self.assertFileExists(deps_require_file)
798 [ ('github.com/godbus/dbus','v5.1.0', 'github.com/godbus/dbus/v5', '/v5', ''),
799 ]
800
801 src_uri = set()
802 for d in dependencies:
803 src_uri.add(self._go_urifiy(*d))
804
805 checkvars = {} 794 checkvars = {}
806 checkvars['GO_DEPENDENCIES_SRC_URI'] = src_uri 795 checkvars['SRC_URI'] = {'gomod://github.com/godbus/dbus/v5;version=v5.1.0;sha256sum=03dfa8e71089a6f477310d15c4d3a036d82d028532881b50fee254358e782ad9'}
807
808 self.assertTrue(os.path.isfile(deps_require_file))
809 self._test_recipe_contents(deps_require_file, checkvars, []) 796 self._test_recipe_contents(deps_require_file, checkvars, [])
810 797
811class RecipetoolTests(RecipetoolBase): 798class RecipetoolTests(RecipetoolBase):
diff --git a/meta/recipes-core/meta/buildtools-docs-tarball.bb b/meta/recipes-core/meta/buildtools-docs-tarball.bb
index b9ef68eb6d..98d47f7b71 100644
--- a/meta/recipes-core/meta/buildtools-docs-tarball.bb
+++ b/meta/recipes-core/meta/buildtools-docs-tarball.bb
@@ -7,6 +7,8 @@ LICENSE = "MIT"
7# Add nativesdk equivalent of build-essentials 7# Add nativesdk equivalent of build-essentials
8TOOLCHAIN_HOST_TASK += "\ 8TOOLCHAIN_HOST_TASK += "\
9 nativesdk-python3-sphinx \ 9 nativesdk-python3-sphinx \
10 nativesdk-python3-sphinx-argparse \
11 nativesdk-python3-sphinx-copybutton \
10 nativesdk-python3-sphinx-rtd-theme \ 12 nativesdk-python3-sphinx-rtd-theme \
11 nativesdk-python3-pyyaml \ 13 nativesdk-python3-pyyaml \
12 nativesdk-rsvg \ 14 nativesdk-rsvg \
@@ -16,4 +18,5 @@ TOOLCHAIN_OUTPUTNAME = "${SDK_ARCH}-buildtools-docs-nativesdk-standalone-${DISTR
16 18
17SDK_TITLE = "Docs Build tools tarball" 19SDK_TITLE = "Docs Build tools tarball"
18 20
19TESTSDK_CASES = "buildtools-docs-cases" 21# Directory that contains testcases
22TESTSDK_CASE_DIRS = "buildtools-docs" \ No newline at end of file
diff --git a/meta/recipes-core/meta/buildtools-tarball.bb b/meta/recipes-core/meta/buildtools-tarball.bb
index 6fa6d93a3d..02117ab84d 100644
--- a/meta/recipes-core/meta/buildtools-tarball.bb
+++ b/meta/recipes-core/meta/buildtools-tarball.bb
@@ -124,22 +124,7 @@ TOOLCHAIN_NEED_CONFIGSITE_CACHE = ""
124# The recipe doesn't need any default deps 124# The recipe doesn't need any default deps
125INHIBIT_DEFAULT_DEPS = "1" 125INHIBIT_DEFAULT_DEPS = "1"
126 126
127# Directory in testsdk that contains testcases 127inherit testsdk
128TESTSDK_CASES = "buildtools-cases"
129 128
130# We have our own code, avoid deferred inherit 129# Directory that contains testcases
131SDK_CLASSES:remove = "testsdk" 130TESTSDK_CASE_DIRS = "buildtools" \ No newline at end of file
132
133python do_testsdk() {
134 import oeqa.sdk.testsdk
135 testsdk = oeqa.sdk.testsdk.TestSDK()
136
137 cases_path = os.path.join(os.path.abspath(os.path.dirname(oeqa.sdk.testsdk.__file__)), d.getVar("TESTSDK_CASES"))
138 testsdk.context_executor_class.default_cases = [cases_path,]
139
140 testsdk.run(d)
141}
142addtask testsdk
143do_testsdk[nostamp] = "1"
144do_testsdk[network] = "1"
145do_testsdk[depends] += "xz-native:do_populate_sysroot"
diff --git a/meta/recipes-devtools/dosfstools/dosfstools/0001-fsck.fat-Adhere-to-the-fsck-exit-codes.patch b/meta/recipes-devtools/dosfstools/dosfstools/0001-fsck.fat-Adhere-to-the-fsck-exit-codes.patch
new file mode 100644
index 0000000000..3d2ce48723
--- /dev/null
+++ b/meta/recipes-devtools/dosfstools/dosfstools/0001-fsck.fat-Adhere-to-the-fsck-exit-codes.patch
@@ -0,0 +1,214 @@
1From 9d165145b9f9c20a56e111360fbc2003c2b28cba Mon Sep 17 00:00:00 2001
2From: Ricardo Simoes <ricardo.simoes@pt.bosch.com>
3Date: Thu, 26 Jun 2025 08:14:29 +0100
4Subject: [PATCH] fsck.fat: Adhere to the fsck exit codes
5
6fsck.fat is used as a filesystem-specific checker for the `fsck`. This
7also causes `fsck` to return the same exit-codes given by `fsck.fat`.
8
9In most cases this is already the case. One exception to that comes when
10checking a read-only filesystem. In that case `fsck.fat` will return 6,
11which for `fsck` means "Fiesystem errors left uncorrected" and "System
12should reboot". When a more proper response would be to return 8,
13"Operational Error".
14
15This commit solves that problem by introducing a new header file which
16standardizes the exit codes used by `fsck.fat`.
17
18Signed-off-by: Ricardo Ungerer <ungerer.ricardo@gmail.com>
19
20Upstream-Status: Inactive-Upstream [lastcommit: 2023, lastrelease: 2021]
21Upstream-Status: Submitted [https://github.com/dosfstools/dosfstools/pull/217]
22---
23 src/Makefile.am | 4 ++--
24 src/common.c | 8 ++++----
25 src/exit_codes.h | 15 +++++++++++++++
26 src/fsck.fat.c | 23 ++++++++++++-----------
27 src/io.c | 3 ++-
28 5 files changed, 35 insertions(+), 18 deletions(-)
29 create mode 100644 src/exit_codes.h
30
31diff --git a/src/Makefile.am b/src/Makefile.am
32index a389046..48f00dd 100644
33--- a/src/Makefile.am
34+++ b/src/Makefile.am
35@@ -23,7 +23,7 @@ EXTRA_DIST = blkdev/README
36
37 charconv_common_sources = charconv.c charconv.h
38 charconv_common_ldadd = $(LIBICONV)
39-fscklabel_common_sources = boot.c boot.h common.c common.h \
40+fscklabel_common_sources = boot.c boot.h common.c common.h exit_codes.h \
41 fat.c fat.h io.c io.h msdos_fs.h \
42 $(charconv_common_sources) \
43 fsck.fat.h endian_compat.h
44@@ -38,7 +38,7 @@ devinfo_common_sources = device_info.c device_info.h \
45 blkdev/blkdev.c blkdev/blkdev.h \
46 blkdev/linux_version.c blkdev/linux_version.h
47 mkfs_fat_SOURCES = mkfs.fat.c msdos_fs.h common.c common.h endian_compat.h \
48- $(charconv_common_sources) $(devinfo_common_sources)
49+ exit_codes.h $(charconv_common_sources) $(devinfo_common_sources)
50 mkfs_fat_CPPFLAGS = -I$(srcdir)/blkdev
51 mkfs_fat_CFLAGS = $(AM_CFLAGS)
52 mkfs_fat_LDADD = $(charconv_common_ldadd)
53diff --git a/src/common.c b/src/common.c
54index 4f1afcb..089d4b3 100644
55--- a/src/common.c
56+++ b/src/common.c
57@@ -38,7 +38,7 @@
58
59 #include "common.h"
60 #include "charconv.h"
61-
62+#include "exit_codes.h"
63
64 int interactive;
65 int write_immed;
66@@ -62,7 +62,7 @@ void die(const char *msg, ...)
67 vfprintf(stderr, msg, args);
68 va_end(args);
69 fprintf(stderr, "\n");
70- exit(1);
71+ exit(OPERATIONAL_ERROR);
72 }
73
74 void pdie(const char *msg, ...)
75@@ -205,7 +205,7 @@ int get_choice(int noninteractive_result, const char *noninteractive_msg,
76 } while (choice == '\n'); /* filter out enter presses */
77
78 if (choice == EOF)
79- exit(1);
80+ exit(USAGE_OR_SYNTAX_ERROR);
81
82 printf("%c\n", choice);
83
84@@ -235,7 +235,7 @@ int get_choice(int noninteractive_result, const char *noninteractive_msg,
85 inhibit_quit_choice = 0;
86
87 if (quit_choice == 1)
88- exit(0);
89+ exit(NO_ERRORS);
90 }
91 }
92
93diff --git a/src/exit_codes.h b/src/exit_codes.h
94new file mode 100644
95index 0000000..f67d22e
96--- /dev/null
97+++ b/src/exit_codes.h
98@@ -0,0 +1,15 @@
99+#ifndef _EXIT_CODES_H
100+#define _EXIT_CODES_H
101+
102+/* Codes as defined by fsck.
103+ For more information, see fsck manpage. */
104+#define NO_ERRORS 0
105+#define FS_ERRORS_CORRECTED 1
106+#define SYSTEM_SHOULD_BE_REBOOTED 2
107+#define FS_ERRORS_LEFT_UNCORRECTED 4
108+#define OPERATIONAL_ERROR 8
109+#define USAGE_OR_SYNTAX_ERROR 16
110+#define CHECKING_CANCELED_BY_USER 32
111+#define SHARED_LIB_ERROR 128
112+
113+#endif
114diff --git a/src/fsck.fat.c b/src/fsck.fat.c
115index 8b02b57..42e3ab4 100644
116--- a/src/fsck.fat.c
117+++ b/src/fsck.fat.c
118@@ -46,6 +46,7 @@
119 #include "file.h"
120 #include "check.h"
121 #include "charconv.h"
122+#include "exit_codes.h"
123
124 int rw = 0, list = 0, test = 0, verbose = 0;
125 long fat_table = 0;
126@@ -147,10 +148,10 @@ int main(int argc, char **argv)
127 codepage = strtol(optarg, &tmp, 10);
128 if (!*optarg || isspace(*optarg) || *tmp || errno || codepage < 0 || codepage > INT_MAX) {
129 fprintf(stderr, "Invalid codepage : %s\n", optarg);
130- usage(argv[0], 2);
131+ usage(argv[0], USAGE_OR_SYNTAX_ERROR);
132 }
133 if (!set_dos_codepage(codepage))
134- usage(argv[0], 2);
135+ usage(argv[0], USAGE_OR_SYNTAX_ERROR);
136 break;
137 case 'd':
138 file_add(optarg, fdt_drop);
139@@ -163,7 +164,7 @@ int main(int argc, char **argv)
140 fat_table = strtol(optarg, &tmp, 10);
141 if (!*optarg || isspace(*optarg) || *tmp || errno || fat_table < 0 || fat_table > 255) {
142 fprintf(stderr, "Invalid FAT table : %s\n", optarg);
143- usage(argv[0], 2);
144+ usage(argv[0], USAGE_OR_SYNTAX_ERROR);
145 }
146 break;
147 case 'l':
148@@ -202,31 +203,31 @@ int main(int argc, char **argv)
149 atari_format = 1;
150 } else {
151 fprintf(stderr, "Unknown variant: %s\n", optarg);
152- usage(argv[0], 2);
153+ usage(argv[0], USAGE_OR_SYNTAX_ERROR);
154 }
155 break;
156 case 'w':
157 write_immed = 1;
158 break;
159 case OPT_HELP:
160- usage(argv[0], 0);
161+ usage(argv[0], EXIT_SUCCESS);
162 break;
163 case '?':
164- usage(argv[0], 2);
165+ usage(argv[0], USAGE_OR_SYNTAX_ERROR);
166 break;
167 default:
168 fprintf(stderr,
169 "Internal error: getopt_long() returned unexpected value %d\n", c);
170- exit(3);
171+ exit(OPERATIONAL_ERROR);
172 }
173 if (!set_dos_codepage(-1)) /* set default codepage if none was given in command line */
174- exit(2);
175+ exit(OPERATIONAL_ERROR);
176 if ((test || write_immed) && !rw) {
177 fprintf(stderr, "-t and -w can not be used in read only mode\n");
178- exit(2);
179+ exit(USAGE_OR_SYNTAX_ERROR);
180 }
181 if (optind != argc - 1)
182- usage(argv[0], 2);
183+ usage(argv[0], USAGE_OR_SYNTAX_ERROR);
184
185 printf("fsck.fat " VERSION " (" VERSION_DATE ")\n");
186 fs_open(argv[optind], rw);
187@@ -285,5 +286,5 @@ exit:
188 n_files, (unsigned long)fs.data_clusters - free_clusters,
189 (unsigned long)fs.data_clusters);
190
191- return fs_close(rw) ? 1 : 0;
192+ return fs_close(rw) ? FS_ERRORS_CORRECTED : NO_ERRORS;
193 }
194diff --git a/src/io.c b/src/io.c
195index 8c0c3b2..8bd1ae5 100644
196--- a/src/io.c
197+++ b/src/io.c
198@@ -44,6 +44,7 @@
199 #include "fsck.fat.h"
200 #include "common.h"
201 #include "io.h"
202+#include "exit_codes.h"
203
204 typedef struct _change {
205 void *data;
206@@ -60,7 +61,7 @@ void fs_open(const char *path, int rw)
207 {
208 if ((fd = open(path, rw ? O_RDWR : O_RDONLY)) < 0) {
209 perror("open");
210- exit(6);
211+ exit(OPERATIONAL_ERROR);
212 }
213 changes = last = NULL;
214 did_change = 0;
diff --git a/meta/recipes-devtools/dosfstools/dosfstools/0002-manpages-Document-fsck.fat-new-exit-codes.patch b/meta/recipes-devtools/dosfstools/dosfstools/0002-manpages-Document-fsck.fat-new-exit-codes.patch
new file mode 100644
index 0000000000..29bba7b093
--- /dev/null
+++ b/meta/recipes-devtools/dosfstools/dosfstools/0002-manpages-Document-fsck.fat-new-exit-codes.patch
@@ -0,0 +1,46 @@
1From 8d703216d2ea3247092a08adb0c37b38eb77ccc7 Mon Sep 17 00:00:00 2001
2From: Ricardo Ungerer <ungerer.ricardo@gmail.com>
3Date: Wed, 21 May 2025 07:18:15 +0100
4Subject: [PATCH 2/3] manpages: Document fsck.fat new exit codes
5
6Signed-off-by: Ricardo Ungerer <ungerer.ricardo@gmail.com>
7
8Upstream-Status: Inactive-Upstream [lastcommit: 2023, lastrelease: 2021]
9Upstream-Status: Submitted [https://github.com/dosfstools/dosfstools/pull/217]
10---
11 manpages/fsck.fat.8.in | 18 +++++++++++++-----
12 1 file changed, 13 insertions(+), 5 deletions(-)
13
14diff --git a/manpages/fsck.fat.8.in b/manpages/fsck.fat.8.in
15index 824a83d..557aa4c 100644
16--- a/manpages/fsck.fat.8.in
17+++ b/manpages/fsck.fat.8.in
18@@ -222,13 +222,21 @@ Display help message describing usage and options then exit.
19 .\" ----------------------------------------------------------------------------
20 .SH "EXIT STATUS"
21 .IP "0" 4
22-No recoverable errors have been detected.
23+No errors
24 .IP "1" 4
25-Recoverable errors have been detected or \fBfsck.fat\fP has discovered an
26-internal inconsistency.
27+Filesystem errors corrected
28 .IP "2" 4
29-Usage error.
30-\fBfsck.fat\fP did not access the filesystem.
31+System should be rebooted
32+.IP "4" 4
33+Filesystem errors left uncorrected
34+.IP "8" 4
35+Operational error
36+.IP "16" 4
37+Usage or syntax error
38+.IP "32" 4
39+Checking canceled by user request
40+.IP "128" 4
41+Shared-library error
42 .\" ----------------------------------------------------------------------------
43 .SH FILES
44 .IP "\fIfsck0000.rec\fP, \fIfsck0001.rec\fP, ..." 4
45--
462.25.1
diff --git a/meta/recipes-devtools/dosfstools/dosfstools_4.2.bb b/meta/recipes-devtools/dosfstools/dosfstools_4.2.bb
index 175fa265ef..86fb68f664 100644
--- a/meta/recipes-devtools/dosfstools/dosfstools_4.2.bb
+++ b/meta/recipes-devtools/dosfstools/dosfstools_4.2.bb
@@ -10,11 +10,12 @@ LICENSE = "GPL-3.0-only"
10LIC_FILES_CHKSUM = "file://COPYING;md5=d32239bcb673463ab874e80d47fae504" 10LIC_FILES_CHKSUM = "file://COPYING;md5=d32239bcb673463ab874e80d47fae504"
11 11
12SRC_URI = "${GITHUB_BASE_URI}/download/v${PV}/${BP}.tar.gz \ 12SRC_URI = "${GITHUB_BASE_URI}/download/v${PV}/${BP}.tar.gz \
13 " 13 file://source-date-epoch.patch \
14 file://0001-fsck.fat-Adhere-to-the-fsck-exit-codes.patch \
15 file://0002-manpages-Document-fsck.fat-new-exit-codes.patch \
16 "
14SRC_URI[sha256sum] = "64926eebf90092dca21b14259a5301b7b98e7b1943e8a201c7d726084809b527" 17SRC_URI[sha256sum] = "64926eebf90092dca21b14259a5301b7b98e7b1943e8a201c7d726084809b527"
15 18
16SRC_URI += "file://source-date-epoch.patch"
17
18inherit autotools gettext pkgconfig update-alternatives github-releases 19inherit autotools gettext pkgconfig update-alternatives github-releases
19 20
20EXTRA_OECONF = "--enable-compat-symlinks --without-iconv" 21EXTRA_OECONF = "--enable-compat-symlinks --without-iconv"
diff --git a/meta/recipes-devtools/json-c/json-c_0.18.bb b/meta/recipes-devtools/json-c/json-c_0.18.bb
index ece320d66c..c112aacf4b 100644
--- a/meta/recipes-devtools/json-c/json-c_0.18.bb
+++ b/meta/recipes-devtools/json-c/json-c_0.18.bb
@@ -19,8 +19,7 @@ UPSTREAM_CHECK_REGEX = "json-c-(?P<pver>\d+(\.\d+)+)-\d+"
19 19
20RPROVIDES:${PN} = "libjson" 20RPROVIDES:${PN} = "libjson"
21 21
22# - '-Werror' must be disabled for ICECC builds 22# Apps aren't needed/packaged and their CMakeLists.txt is incompatible with CMake 4+.
23# - Apps aren't needed/packaged and their CMakeLists.txt is incompatible with CMake 4+.
24EXTRA_OECMAKE = "-DDISABLE_WERROR=ON \ 23EXTRA_OECMAKE = "-DDISABLE_WERROR=ON \
25 -DBUILD_APPS=OFF \ 24 -DBUILD_APPS=OFF \
26" 25"
diff --git a/meta/recipes-devtools/mtools/mtools_4.0.48.bb b/meta/recipes-devtools/mtools/mtools_4.0.49.bb
index 646735f3b3..294b2f37b2 100644
--- a/meta/recipes-devtools/mtools/mtools_4.0.48.bb
+++ b/meta/recipes-devtools/mtools/mtools_4.0.49.bb
@@ -24,7 +24,7 @@ RRECOMMENDS:${PN}:libc-glibc = "\
24 glibc-gconv-ibm866 \ 24 glibc-gconv-ibm866 \
25 glibc-gconv-ibm869 \ 25 glibc-gconv-ibm869 \
26 " 26 "
27SRC_URI[sha256sum] = "03c29aac8735dd7154a989fbc29eaf2b506121ae1c3a35cd0bf2a02e94d271a9" 27SRC_URI[sha256sum] = "6fe5193583d6e7c59da75e63d7234f76c0b07caf33b103894f46f66a871ffc9f"
28 28
29SRC_URI = "${GNU_MIRROR}/mtools/mtools-${PV}.tar.bz2 \ 29SRC_URI = "${GNU_MIRROR}/mtools/mtools-${PV}.tar.bz2 \
30 file://mtools-makeinfo.patch \ 30 file://mtools-makeinfo.patch \
diff --git a/meta/recipes-devtools/ninja/ninja_1.12.1.bb b/meta/recipes-devtools/ninja/ninja_1.13.0.bb
index 5aff82edec..a5fa8f1c9e 100644
--- a/meta/recipes-devtools/ninja/ninja_1.12.1.bb
+++ b/meta/recipes-devtools/ninja/ninja_1.13.0.bb
@@ -1,14 +1,18 @@
1SUMMARY = "Ninja is a small build system with a focus on speed." 1SUMMARY = "Ninja is a small build system with a focus on speed."
2HOMEPAGE = "https://ninja-build.org/" 2HOMEPAGE = "https://ninja-build.org/"
3DESCRIPTION = "Ninja is a small build system with a focus on speed. It differs from other build systems in two major respects: it is designed to have its input files generated by a higher-level build system, and it is designed to run builds as fast as possible." 3DESCRIPTION = "Ninja is a small build system with a focus on speed. \
4It differs from other build systems in two major respects: \
5it is designed to have its input files generated by a higher-level build system, \
6and it is designed to run builds as fast as possible."
7
4LICENSE = "Apache-2.0" 8LICENSE = "Apache-2.0"
5LIC_FILES_CHKSUM = "file://COPYING;md5=a81586a64ad4e476c791cda7e2f2c52e" 9LIC_FILES_CHKSUM = "file://COPYING;md5=a81586a64ad4e476c791cda7e2f2c52e"
6 10
7DEPENDS = "re2c-native ninja-native" 11DEPENDS = "re2c-native ninja-native"
8 12
9SRCREV = "2daa09ba270b0a43e1929d29b073348aa985dfaa" 13SRCREV = "b4d51f6ed5bed09dd2b70324df0d9cb4ecad2638"
10 14
11SRC_URI = "git://github.com/ninja-build/ninja.git;branch=release;protocol=https" 15SRC_URI = "git://github.com/ninja-build/ninja.git;branch=release;protocol=https;tag=v${PV}"
12UPSTREAM_CHECK_GITTAGREGEX = "v(?P<pver>.*)" 16UPSTREAM_CHECK_GITTAGREGEX = "v(?P<pver>.*)"
13 17
14do_configure[noexec] = "1" 18do_configure[noexec] = "1"
diff --git a/meta/recipes-devtools/python/python3-sphinx-argparse_0.5.2.bb b/meta/recipes-devtools/python/python3-sphinx-argparse_0.5.2.bb
new file mode 100644
index 0000000000..554fb3eb51
--- /dev/null
+++ b/meta/recipes-devtools/python/python3-sphinx-argparse_0.5.2.bb
@@ -0,0 +1,13 @@
1SUMMARY = "A sphinx extension that automatically documents argparse commands and options"
2HOMEPAGE = "https://sphinx-argparse.readthedocs.io/"
3LICENSE = "MIT"
4LIC_FILES_CHKSUM = "file://LICENCE.rst;md5=5c1cd8f13774629fee215681e66a1056"
5
6SRC_URI[sha256sum] = "e5352f8fa894b6fb6fda0498ba28a9f8d435971ef4bbc1a6c9c6414e7644f032"
7
8PYPI_PACKAGE = "sphinx_argparse"
9UPSTREAM_CHECK_PYPI_PACKAGE = "${PYPI_PACKAGE}"
10
11inherit pypi python_flit_core
12
13BBCLASSEXTEND = "native nativesdk"
diff --git a/meta/recipes-devtools/python/python3-sphinx-copybutton_0.5.2.bb b/meta/recipes-devtools/python/python3-sphinx-copybutton_0.5.2.bb
new file mode 100644
index 0000000000..0441804661
--- /dev/null
+++ b/meta/recipes-devtools/python/python3-sphinx-copybutton_0.5.2.bb
@@ -0,0 +1,10 @@
1SUMMARY = "Add a copy button to code blocks in Sphinx"
2HOMEPAGE = "https://sphinx-copybutton.readthedocs.io"
3LICENSE = "MIT"
4LIC_FILES_CHKSUM = "file://LICENSE;md5=c60e920848b6d2ecec51ea44a1a33bf0"
5
6SRC_URI[sha256sum] = "4cf17c82fb9646d1bc9ca92ac280813a3b605d8c421225fd9913154103ee1fbd"
7
8inherit setuptools3 pypi
9
10BBCLASSEXTEND = "native nativesdk"
diff --git a/meta/recipes-devtools/python/python3-urllib3_2.4.0.bb b/meta/recipes-devtools/python/python3-urllib3_2.5.0.bb
index 7a4bffc05e..a4f3995730 100644
--- a/meta/recipes-devtools/python/python3-urllib3_2.4.0.bb
+++ b/meta/recipes-devtools/python/python3-urllib3_2.5.0.bb
@@ -3,7 +3,7 @@ HOMEPAGE = "https://github.com/urllib3/urllib3"
3LICENSE = "MIT" 3LICENSE = "MIT"
4LIC_FILES_CHKSUM = "file://LICENSE.txt;md5=52d273a3054ced561275d4d15260ecda" 4LIC_FILES_CHKSUM = "file://LICENSE.txt;md5=52d273a3054ced561275d4d15260ecda"
5 5
6SRC_URI[sha256sum] = "414bc6535b787febd7567804cc015fee39daab8ad86268f1310a9250697de466" 6SRC_URI[sha256sum] = "3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760"
7 7
8inherit pypi python_hatchling 8inherit pypi python_hatchling
9 9
diff --git a/meta/recipes-devtools/python/python3-wheel_0.45.1.bb b/meta/recipes-devtools/python/python3-wheel_0.46.1.bb
index 8274e83747..058af2f0e7 100644
--- a/meta/recipes-devtools/python/python3-wheel_0.45.1.bb
+++ b/meta/recipes-devtools/python/python3-wheel_0.46.1.bb
@@ -4,9 +4,14 @@ SECTION = "devel/python"
4LICENSE = "MIT" 4LICENSE = "MIT"
5LIC_FILES_CHKSUM = "file://LICENSE.txt;md5=7ffb0db04527cfe380e4f2726bd05ebf" 5LIC_FILES_CHKSUM = "file://LICENSE.txt;md5=7ffb0db04527cfe380e4f2726bd05ebf"
6 6
7SRC_URI[sha256sum] = "661e1abd9198507b1409a20c02106d9670b2576e916d58f520316666abca6729" 7SRC_URI[sha256sum] = "fd477efb5da0f7df1d3c76c73c14394002c844451bd63229d8570f376f5e6a38"
8 8
9inherit python_flit_core pypi 9inherit python_flit_core pypi ptest-python-pytest
10
11RDEPENDS:${PN} += "python3-packaging"
12
13# One test is skipped but requires the "full" python3-flit, not just python3-flit-core
14RDEPENDS:${PN}-ptest += "python3-setuptools"
10 15
11BBCLASSEXTEND = "native nativesdk" 16BBCLASSEXTEND = "native nativesdk"
12 17
diff --git a/meta/recipes-devtools/tcf-agent/tcf-agent_1.8.0.bb b/meta/recipes-devtools/tcf-agent/tcf-agent_1.8.0.bb
index 1639ae84e9..f008c0c6de 100644
--- a/meta/recipes-devtools/tcf-agent/tcf-agent_1.8.0.bb
+++ b/meta/recipes-devtools/tcf-agent/tcf-agent_1.8.0.bb
@@ -49,6 +49,12 @@ CFLAGS:append:riscv64 = " ${LCL_STOP_SERVICES}"
49CFLAGS:append:riscv32 = " ${LCL_STOP_SERVICES}" 49CFLAGS:append:riscv32 = " ${LCL_STOP_SERVICES}"
50CFLAGS:append:loongarch64 = " ${LCL_STOP_SERVICES}" 50CFLAGS:append:loongarch64 = " ${LCL_STOP_SERVICES}"
51 51
52# This works with gcc-ranlib wrapper only because it exists without error if nothing
53# is passed as argument but binutils ranlib and llvm ranlib do not and expect an input
54# passing $@ ensures that Makefile default target which is the archive name in tcf makefiles
55# is passed to RANLIB, ensures that whichever ranlib is used, the behavior is identical
56RANLIB:append = " $@"
57
52do_install() { 58do_install() {
53 oe_runmake install INSTALLROOT=${D} 59 oe_runmake install INSTALLROOT=${D}
54 install -d ${D}${sysconfdir}/init.d/ 60 install -d ${D}${sysconfdir}/init.d/