Browse Source

tcmode-external-oe-sdk: integrate combined handling, support multilibs

Signed-off-by: Christopher Larson <chris_larson@mentor.com>
Christopher Larson 3 years ago
parent
commit
eef5cf7ecb
1 changed files with 124 additions and 24 deletions
  1. 124 24
      conf/distro/include/tcmode-external-oe-sdk.inc

+ 124 - 24
conf/distro/include/tcmode-external-oe-sdk.inc

@@ -16,37 +16,137 @@ EXTERNAL_TOOLCHAIN_FEATURES_append = " locale-utf8-is-default"
 oe_multilib_header_pn-glibc-external = ":"
 
 python extract_env_setup_metadata() {
-    import pathlib
-    import subprocess
+    from pathlib import Path
 
-    external_toolchain = pathlib.Path(d.getVar('EXTERNAL_TOOLCHAIN'))
+    external_toolchain = Path(d.getVar('EXTERNAL_TOOLCHAIN'))
     if external_toolchain.is_absolute() and external_toolchain.is_dir():
-        setup = d.getVar('EXTERNAL_TOOLCHAIN_SETUP_SCRIPT')
-        if setup:
-            setup = pathlib.Path(setup)
-        else:
-            arch = d.getVar('TUNE_PKGARCH')
-            setups = external_toolchain.glob('environment-setup-' + arch + '-*')
-            if not setups:
-                bb.fatal('tcmode-external-oe-sdk: failed to determine setup script path for sdk at {}, please set EXTERNAL_TOOLCHAIN_SETUP_SCRIPT to the full path to the environment setup script.'.format(external_toolchain))
-            else:
-                setups = list(setups)
-                if len(setups) > 1:
-                    bb.fatal('tcmode-external-oe-sdk: multiple setup scripts available at {}, please specify the path in EXTERNAL_TOOLCHAIN_SETUP_SCRIPT'.format(external_toolchain))
-                else:
-                    setup = setups[0]
-
-        env = parse_setup_script(setup)
-        target_sys = env.get('TARGET_PREFIX')[:-1]
-        native_sysroot = pathlib.Path(env.get('OECORE_NATIVE_SYSROOT'))
+        setup_external_vars(external_toolchain, d)
 
-        d.setVar('EXTERNAL_TARGET_SYS', str(target_sys))
-        d.setVar('EXTERNAL_TOOLCHAIN_BIN', str(native_sysroot / 'usr' / 'bin' / target_sys))
-        d.setVar('EXTERNAL_TOOLCHAIN_SYSROOT', env.get('SDKTARGETSYSROOT'))
+        localdata = bb.data.createCopy(d)
+        variants = d.getVar('MULTILIB_VARIANTS') or ''
+        for item in variants.split():
+            # Load overrides from 'd' to avoid having to reset the value...
+            overrides = d.getVar('OVERRIDES', False) + ':virtclass-multilib-' + item
+            localdata.setVar('OVERRIDES', overrides)
+            localdata.setVar('MLPREFIX', item + '-')
+            setup_external_vars(external_toolchain, localdata)
 }
 extract_env_setup_metadata[eventmask] = "bb.event.ConfigParsed"
 addhandler extract_env_setup_metadata
 
+def setup_external_vars(external_toolchain, d):
+    from pathlib import Path
+
+    setup, env = get_setup_script_env(external_toolchain, d)
+
+    mlprefix = d.getVar('MLPREFIX')
+    if mlprefix:
+        suffix = '_virtclass-multilib-' + mlprefix[:-1]
+    else:
+        suffix = ''
+
+    d.setVar('EXTERNAL_TOOLCHAIN_SETUP_SCRIPT' + suffix, str(setup))
+
+    target_sys = env.get('TARGET_PREFIX')[:-1]
+    native_sysroot = Path(env.get('OECORE_NATIVE_SYSROOT'))
+    if str(native_sysroot).startswith('$scriptdir/'):
+        native_sysroot = setup.parent / native_sysroot.relative_to('$scriptdir')
+    target_sysroot = Path(env.get('SDKTARGETSYSROOT'))
+    if str(target_sysroot).startswith('$scriptdir/'):
+        target_sysroot = setup.parent / target_sysroot.relative_to('$scriptdir')
+
+    d.setVar('EXTERNAL_TARGET_SYS' + suffix, str(target_sys))
+    d.setVar('EXTERNAL_TOOLCHAIN_BIN' + suffix, str(native_sysroot / 'usr' / 'bin' / target_sys))
+    # In OE multilib configurations, gcc may be a symlink. Resolve it to
+    # determine the real target sys from gcc's perspective.
+    # external_bin = native_sysroot / 'usr' / 'bin' / target_sys
+    # d.setVar('EXTERNAL_TOOLCHAIN_BIN', str(external_bin.resolve()))
+    # gcc = external_bin / (target_sys + "-gcc")
+    # d.setVar('EXTERNAL_TARGET_SYS', gcc.resolve().name[:-4])
+    d.setVar('EXTERNAL_TOOLCHAIN_SYSROOT' + suffix, str(target_sysroot))
+
+# These are treated as prefixes to items in PACKAGE_ARCHS at this time.
+#
+# An armv7-a sysroot will run fine with armv7ve machines, as the latter just
+# have virtualization extensions. We need to handle this sort of thing
+# directly in this case, as for some reason the armv7-a tunes aren't listed in
+# the armv7ve PACKAGE_ARCHS.
+EXTERNAL_TOOLCHAIN_ARCH_COMPAT[armv7ve] += "armv7a"
+
+def select_appropriate_setup_script(d, external_toolchain):
+    candidates = []
+
+    tune_pkgarch = d.getVar('TUNE_PKGARCH')
+    arch_setups = list(external_toolchain.glob('environment-setup-' + tune_pkgarch + '-*'))
+    if arch_setups:
+        # Exact match
+        for setup in arch_setups:
+            setup_env = parse_setup_script(setup)
+            candidates.append((setup, setup_env))
+        return candidates
+
+    target_arch = d.getVar('TARGET_ARCH')
+    target_os = d.getVar('TARGET_OS')
+    baselib = d.getVar('baselib')
+    package_archs = d.getVar('PACKAGE_ARCHS').split()
+
+    arch_compat = d.getVarFlags('EXTERNAL_TOOLCHAIN_ARCH_COMPAT')
+    setups = external_toolchain.glob('environment-setup-*')
+    for setup in setups:
+        setup_env = parse_setup_script(setup)
+        if target_arch != setup_get(setup_env, 'OECORE_TARGET_ARCH'):
+            bb.debug(1, "tcmode-external-sourcery: TARGET_ARCH `{}` doesn't match `{}` in `{}`".format(target_arch, setup_get(setup_env, 'OECORE_TARGET_ARCH'), setup))
+            continue
+        if target_os != setup_get(setup_env, 'OECORE_TARGET_OS'):
+            bb.debug(1, "tcmode-external-sourcery: TARGET_OS `{}` doesn't match `{}` in `{}`".format(target_os, setup_get(setup_env, 'OECORE_TARGET_OS'), setup))
+            continue
+        if baselib != setup_get(setup_env, 'OECORE_BASELIB'):
+            bb.debug(1, "tcmode-external-sourcery: BASELIB `{}` doesn't match `{}` in `{}`".format(baselib, setup_get(setup_env, 'OECORE_BASELIB'), setup))
+            continue
+
+        setup_tune_pkgarch = setup_env.get('TUNE_PKGARCH')
+        if setup_tune_pkgarch:
+            if setup_tune_pkgarch not in package_archs:
+                compatible = False
+                for from_arch, compat_archs in arch_compat.items():
+                    for compat_arch in compat_archs.split():
+                        adjusted_archs = [a.replace(from_arch, compat_arch) for a in package_archs]
+                        if setup_tune_pkgarch in adjusted_archs:
+                            compatible = True
+
+                if not compatible:
+                    bb.debug(1, "tcmode-external-sourcery: skipping incompatible {}: TUNE_PKGARCH `{}` not found in PACKAGE_ARCHS `{}`".format(setup, setup_tune_pkgarch, package_archs))
+                    continue
+        candidates.append((setup, setup_env))
+
+    return candidates
+
+def get_setup_script_env(external_toolchain, d):
+    from pathlib import Path
+
+    setup = d.getVar('EXTERNAL_TOOLCHAIN_SETUP_SCRIPT')
+    if setup:
+        setup = Path(setup)
+        env = parse_setup_script(setup)
+    else:
+        candidates = select_appropriate_setup_script(d, external_toolchain)
+        if not candidates:
+            setup = None
+        elif len(candidates) > 1:
+            bb.fatal("tcmode-external-sourcery: multiple candidate setup scripts found, please specify with EXTERNAL_TOOLCHAIN_SETUP_SCRIPT: {}".format(" ".join(candidates)))
+        else:
+            setup, env = candidates[0]
+            bb.debug(1, "tcmode-external-sourcery: selected setup script {}".format(setup))
+
+    if not setup:
+        bb.fatal('tcmode-external-sourcery: failed to determine setup script path for sdk at {}, please set EXTERNAL_TOOLCHAIN_SETUP_SCRIPT to the full path to the environment setup script.'.format(external_toolchain))
+    return setup, env
+
+def setup_get(setup, field):
+    if not field in setup:
+        bb.fatal("tcmode-external-sourcery: no variable `{}` found in `{}`".format(field, setup))
+    return setup[field]
+
 def parse_setup_script(setup):
     import shlex
     import subprocess