diff mbox series

[1/2] license_image: don't apply INCOMPATIBLE_LICENSE to SDK host tools

Message ID 20261113101537.3586467-1-sean@geanix.com
State New
Headers show
Series [1/2] license_image: don't apply INCOMPATIBLE_LICENSE to SDK host tools | expand

Commit Message

Sean Nyekjaer Nov. 13, 2026, 10:15 a.m. UTC
Since the SDK host and target sysroots are passed through
write_license_files(), do_populate_sdk checks every nativesdk and
cross-canadian package against the image's INCOMPATIBLE_LICENSE and
fails, e.g. with INCOMPATIBLE_LICENSE = "GPL-3.0*":

  Some packages cannot be installed into the image because they have
  incompatible licenses:
        nativesdk-autoconf (GPL-3.0-or-later)

At parse time skip_incompatible_package_licenses() exempts these
recipes, so they are built and packaged, and only the SDK manifest
step rejects them. Move that exemption into
incompatible_license_check_needed() and use it in write_license_files()
too, so host tools in the SDK are treated the same way. Target packages
in the image and in the SDK target sysroot are still checked.

Fixes: f757ae4dadab ("license_image: extend to SDK coverage")
AI-Generated: Claude Opus 5.5 (Claude Code)
Signed-off-by: Sean Nyekjaer <sean@geanix.com>
---
Patches for the discussion here:
https://lists.openembedded.org/g/openembedded-core/topic/122226717

I would like for this to go into the wrynose branch, but it doesn't
apply as is.

 meta/classes-recipe/license_image.bbclass | 13 +++++++++---
 meta/lib/oe/license.py                    | 25 ++++++++++++++---------
 2 files changed, 25 insertions(+), 13 deletions(-)
diff mbox series

Patch

diff --git a/meta/classes-recipe/license_image.bbclass b/meta/classes-recipe/license_image.bbclass
index 7d00b1ae53..728db8ae3a 100644
--- a/meta/classes-recipe/license_image.bbclass
+++ b/meta/classes-recipe/license_image.bbclass
@@ -128,16 +128,23 @@  def write_license_files(d, license_manifest, pkg_dic, rootfs):
 
             pkg_allow_licenses = oe.license.filter_pkg_license_list(pkg, allow_licenses)
 
+            # Host tools in the SDK (nativesdk, cross-canadian) are not
+            # subject to INCOMPATIBLE_LICENSE, same as at parse time.
+            if oe.license.incompatible_license_check_needed(d, pkg_dic[pkg]["PN"]):
+                pkg_bad_licenses = bad_licenses
+            else:
+                pkg_bad_licenses = []
+
             if node:
-                if incompatible_licenses := oe.license.license_allowed(node, bad_licenses, pkg_allow_licenses):
+                if incompatible_licenses := oe.license.license_allowed(node, pkg_bad_licenses, pkg_allow_licenses):
                     incompatible_packages.append("%s (%s)" % (pkg, ' '.join(n.to_string() for n in incompatible_licenses)))
-                elif incompatible_licenses := oe.license.license_allowed(node, bad_licenses, []):
+                elif incompatible_licenses := oe.license.license_allowed(node, pkg_bad_licenses, []):
                     oe.qa.handle_error('license-exception', "Including %s with incompatible license(s) %s into the image, because it has been allowed by exception list." %
                                        (pkg, ' '.join(n.to_string() for n in incompatible_licenses)), d)
 
             (pkg_dic[pkg]["LICENSE"], pkg_dic[pkg]["LICENSES"]) = \
                 oe.license.manifest_licenses(d, pkg_dic[pkg]["LICENSE"],
-                                             bad_licenses, pkg_allow_licenses)
+                                             pkg_bad_licenses, pkg_allow_licenses)
 
             if not "IMAGE_MANIFEST" in pkg_dic[pkg]:
                 # Rootfs manifest
diff --git a/meta/lib/oe/license.py b/meta/lib/oe/license.py
index e2a2bcc47d..035311d469 100644
--- a/meta/lib/oe/license.py
+++ b/meta/lib/oe/license.py
@@ -561,23 +561,28 @@  def filter_pkg_license_list(pkg, lst):
 
     return pkg_lst
 
+def incompatible_license_check_needed(d, pn):
+    """
+    Return False for recipes that INCOMPATIBLE_LICENSE does not apply to:
+    native, nativesdk, cross and cross-canadian recipes, and gcc-source.
+    """
+    if pn.startswith("nativesdk-") or pn.startswith("gcc-source-"):
+        return False
+    for t in ["-native", "-cross-${TARGET_ARCH}", "-cross-initial-${TARGET_ARCH}",
+            "-crosssdk-${SDK_SYS}", "-crosssdk-initial-${SDK_SYS}",
+            "-cross-canadian-${TRANSLATED_TARGET_ARCH}"]:
+        if pn.endswith(d.expand(t)):
+            return False
+    return True
+
 def skip_incompatible_package_licenses(d, pkgs):
     if not pkgs:
         return {}
 
     pn = d.getVar("PN")
 
-    check_license = False if pn.startswith("nativesdk-") else True
-    for t in ["-native", "-cross-${TARGET_ARCH}", "-cross-initial-${TARGET_ARCH}",
-            "-crosssdk-${SDK_SYS}", "-crosssdk-initial-${SDK_SYS}",
-            "-cross-canadian-${TRANSLATED_TARGET_ARCH}"]:
-        if pn.endswith(d.expand(t)):
-            check_license = False
-    if pn.startswith("gcc-source-"):
-        check_license = False
-
     bad_licenses = (d.getVar('INCOMPATIBLE_LICENSE') or "").split()
-    if not check_license or not bad_licenses:
+    if not incompatible_license_check_needed(d, pn) or not bad_licenses:
         return {}
 
     bad_licenses = expand_wildcard_licenses(d, bad_licenses)