192b42cb3SPatrick Williams#
292b42cb3SPatrick Williams# Copyright OpenEmbedded Contributors
392b42cb3SPatrick Williams#
492b42cb3SPatrick Williams# SPDX-License-Identifier: MIT
592b42cb3SPatrick Williams#
692b42cb3SPatrick Williams
7ac13d5f3SPatrick WilliamsUNINATIVE_LOADER ?= "${UNINATIVE_STAGING_DIR}-uninative/${BUILD_ARCH}-linux/lib/${@bb.utils.contains('BUILD_ARCH', 'x86_64', 'ld-linux-x86-64.so.2', '', d)}${@bb.utils.contains('BUILD_ARCH', 'i686', 'ld-linux.so.2', '', d)}${@bb.utils.contains('BUILD_ARCH', 'aarch64', 'ld-linux-aarch64.so.1', '', d)}${@bb.utils.contains('BUILD_ARCH', 'ppc64le', 'ld64.so.2', '', d)}${@bb.utils.contains('BUILD_ARCH', 'riscv64', 'ld-linux-riscv64-lp64d.so.1', '', d)}"
892b42cb3SPatrick WilliamsUNINATIVE_STAGING_DIR ?= "${STAGING_DIR}"
992b42cb3SPatrick Williams
1092b42cb3SPatrick WilliamsUNINATIVE_URL ?= "unset"
1192b42cb3SPatrick WilliamsUNINATIVE_TARBALL ?= "${BUILD_ARCH}-nativesdk-libc-${UNINATIVE_VERSION}.tar.xz"
1292b42cb3SPatrick Williams# Example checksums
1392b42cb3SPatrick Williams#UNINATIVE_CHECKSUM[aarch64] = "dead"
1492b42cb3SPatrick Williams#UNINATIVE_CHECKSUM[i686] = "dead"
1592b42cb3SPatrick Williams#UNINATIVE_CHECKSUM[x86_64] = "dead"
1692b42cb3SPatrick WilliamsUNINATIVE_DLDIR ?= "${DL_DIR}/uninative/"
1792b42cb3SPatrick Williams
1892b42cb3SPatrick Williams# Enabling uninative will change the following variables so they need to go the parsing ignored variables list to prevent multiple recipe parsing
1992b42cb3SPatrick WilliamsBB_HASHCONFIG_IGNORE_VARS += "NATIVELSBSTRING SSTATEPOSTUNPACKFUNCS BUILD_LDFLAGS"
2092b42cb3SPatrick Williams
2192b42cb3SPatrick Williamsaddhandler uninative_event_fetchloader
2292b42cb3SPatrick Williamsuninative_event_fetchloader[eventmask] = "bb.event.BuildStarted"
2392b42cb3SPatrick Williams
2492b42cb3SPatrick Williamsaddhandler uninative_event_enable
2592b42cb3SPatrick Williamsuninative_event_enable[eventmask] = "bb.event.ConfigParsed"
2692b42cb3SPatrick Williams
2792b42cb3SPatrick Williamspython uninative_event_fetchloader() {
2892b42cb3SPatrick Williams    """
2992b42cb3SPatrick Williams    This event fires on the parent and will try to fetch the tarball if the
3092b42cb3SPatrick Williams    loader isn't already present.
3192b42cb3SPatrick Williams    """
3292b42cb3SPatrick Williams
3392b42cb3SPatrick Williams    chksum = d.getVarFlag("UNINATIVE_CHECKSUM", d.getVar("BUILD_ARCH"))
3492b42cb3SPatrick Williams    if not chksum:
3592b42cb3SPatrick Williams        bb.fatal("Uninative selected but not configured correctly, please set UNINATIVE_CHECKSUM[%s]" % d.getVar("BUILD_ARCH"))
3692b42cb3SPatrick Williams
3792b42cb3SPatrick Williams    loader = d.getVar("UNINATIVE_LOADER")
3892b42cb3SPatrick Williams    loaderchksum = loader + ".chksum"
3992b42cb3SPatrick Williams    if os.path.exists(loader) and os.path.exists(loaderchksum):
4092b42cb3SPatrick Williams        with open(loaderchksum, "r") as f:
4192b42cb3SPatrick Williams            readchksum = f.read().strip()
4292b42cb3SPatrick Williams        if readchksum == chksum:
43517393d9SAndrew Geissler            if "uninative" not in d.getVar("SSTATEPOSTUNPACKFUNCS"):
44517393d9SAndrew Geissler                enable_uninative(d)
4592b42cb3SPatrick Williams            return
4692b42cb3SPatrick Williams
4792b42cb3SPatrick Williams    import subprocess
4892b42cb3SPatrick Williams    try:
4992b42cb3SPatrick Williams        # Save and restore cwd as Fetch.download() does a chdir()
5092b42cb3SPatrick Williams        olddir = os.getcwd()
5192b42cb3SPatrick Williams
5292b42cb3SPatrick Williams        tarball = d.getVar("UNINATIVE_TARBALL")
5392b42cb3SPatrick Williams        tarballdir = os.path.join(d.getVar("UNINATIVE_DLDIR"), chksum)
5492b42cb3SPatrick Williams        tarballpath = os.path.join(tarballdir, tarball)
5592b42cb3SPatrick Williams
5692b42cb3SPatrick Williams        if not os.path.exists(tarballpath + ".done"):
5792b42cb3SPatrick Williams            bb.utils.mkdirhier(tarballdir)
5892b42cb3SPatrick Williams            if d.getVar("UNINATIVE_URL") == "unset":
5992b42cb3SPatrick Williams                bb.fatal("Uninative selected but not configured, please set UNINATIVE_URL")
6092b42cb3SPatrick Williams
6192b42cb3SPatrick Williams            localdata = bb.data.createCopy(d)
6292b42cb3SPatrick Williams            localdata.setVar('FILESPATH', "")
6392b42cb3SPatrick Williams            localdata.setVar('DL_DIR', tarballdir)
6492b42cb3SPatrick Williams            # Our games with path manipulation of DL_DIR mean standard PREMIRRORS don't work
6592b42cb3SPatrick Williams            # and we can't easily put 'chksum' into the url path from a url parameter with
6692b42cb3SPatrick Williams            # the current fetcher url handling
6792b42cb3SPatrick Williams            premirrors = bb.fetch2.mirror_from_string(localdata.getVar("PREMIRRORS"))
6892b42cb3SPatrick Williams            for line in premirrors:
6992b42cb3SPatrick Williams                try:
7092b42cb3SPatrick Williams                    (find, replace) = line
7192b42cb3SPatrick Williams                except ValueError:
7292b42cb3SPatrick Williams                    continue
7392b42cb3SPatrick Williams                if find.startswith("http"):
7492b42cb3SPatrick Williams                    localdata.appendVar("PREMIRRORS", " ${UNINATIVE_URL}${UNINATIVE_TARBALL} %s/uninative/%s/${UNINATIVE_TARBALL}" % (replace, chksum))
7592b42cb3SPatrick Williams
7692b42cb3SPatrick Williams            srcuri = d.expand("${UNINATIVE_URL}${UNINATIVE_TARBALL};sha256sum=%s" % chksum)
7792b42cb3SPatrick Williams            bb.note("Fetching uninative binary shim %s (will check PREMIRRORS first)" % srcuri)
7892b42cb3SPatrick Williams
7992b42cb3SPatrick Williams            fetcher = bb.fetch2.Fetch([srcuri], localdata, cache=False)
8092b42cb3SPatrick Williams            fetcher.download()
8192b42cb3SPatrick Williams            localpath = fetcher.localpath(srcuri)
8292b42cb3SPatrick Williams            if localpath != tarballpath and os.path.exists(localpath) and not os.path.exists(tarballpath):
8392b42cb3SPatrick Williams                # Follow the symlink behavior from the bitbake fetch2.
8492b42cb3SPatrick Williams                # This will cover the case where an existing symlink is broken
8592b42cb3SPatrick Williams                # as well as if there are two processes trying to create it
8692b42cb3SPatrick Williams                # at the same time.
8792b42cb3SPatrick Williams                if os.path.islink(tarballpath):
8892b42cb3SPatrick Williams                    # Broken symbolic link
8992b42cb3SPatrick Williams                    os.unlink(tarballpath)
9092b42cb3SPatrick Williams
9192b42cb3SPatrick Williams                # Deal with two processes trying to make symlink at once
9292b42cb3SPatrick Williams                try:
9392b42cb3SPatrick Williams                    os.symlink(localpath, tarballpath)
9492b42cb3SPatrick Williams                except FileExistsError:
9592b42cb3SPatrick Williams                    pass
9692b42cb3SPatrick Williams
9792b42cb3SPatrick Williams        # ldd output is "ldd (Ubuntu GLIBC 2.23-0ubuntu10) 2.23", extract last option from first line
9892b42cb3SPatrick Williams        glibcver = subprocess.check_output(["ldd", "--version"]).decode('utf-8').split('\n')[0].split()[-1]
9992b42cb3SPatrick Williams        if bb.utils.vercmp_string(d.getVar("UNINATIVE_MAXGLIBCVERSION"), glibcver) < 0:
10092b42cb3SPatrick Williams            raise RuntimeError("Your host glibc version (%s) is newer than that in uninative (%s). Disabling uninative so that sstate is not corrupted." % (glibcver, d.getVar("UNINATIVE_MAXGLIBCVERSION")))
10192b42cb3SPatrick Williams
10292b42cb3SPatrick Williams        cmd = d.expand("\
10392b42cb3SPatrick Williamsmkdir -p ${UNINATIVE_STAGING_DIR}-uninative; \
10492b42cb3SPatrick Williamscd ${UNINATIVE_STAGING_DIR}-uninative; \
10592b42cb3SPatrick Williamstar -xJf ${UNINATIVE_DLDIR}/%s/${UNINATIVE_TARBALL}; \
10692b42cb3SPatrick Williams${UNINATIVE_STAGING_DIR}-uninative/relocate_sdk.py \
10792b42cb3SPatrick Williams  ${UNINATIVE_STAGING_DIR}-uninative/${BUILD_ARCH}-linux \
10892b42cb3SPatrick Williams  ${UNINATIVE_LOADER} \
10992b42cb3SPatrick Williams  ${UNINATIVE_LOADER} \
11092b42cb3SPatrick Williams  ${UNINATIVE_STAGING_DIR}-uninative/${BUILD_ARCH}-linux/${bindir_native}/patchelf-uninative \
11192b42cb3SPatrick Williams  ${UNINATIVE_STAGING_DIR}-uninative/${BUILD_ARCH}-linux${base_libdir_native}/libc*.so*" % chksum)
11292b42cb3SPatrick Williams        subprocess.check_output(cmd, shell=True)
11392b42cb3SPatrick Williams
11492b42cb3SPatrick Williams        with open(loaderchksum, "w") as f:
11592b42cb3SPatrick Williams            f.write(chksum)
11692b42cb3SPatrick Williams
11792b42cb3SPatrick Williams        enable_uninative(d)
11892b42cb3SPatrick Williams
11992b42cb3SPatrick Williams    except RuntimeError as e:
12092b42cb3SPatrick Williams        bb.warn(str(e))
12192b42cb3SPatrick Williams    except bb.fetch2.BBFetchException as exc:
12292b42cb3SPatrick Williams        bb.warn("Disabling uninative as unable to fetch uninative tarball: %s" % str(exc))
12392b42cb3SPatrick Williams        bb.warn("To build your own uninative loader, please bitbake uninative-tarball and set UNINATIVE_TARBALL appropriately.")
12492b42cb3SPatrick Williams    except subprocess.CalledProcessError as exc:
12592b42cb3SPatrick Williams        bb.warn("Disabling uninative as unable to install uninative tarball: %s" % str(exc))
12692b42cb3SPatrick Williams        bb.warn("To build your own uninative loader, please bitbake uninative-tarball and set UNINATIVE_TARBALL appropriately.")
12792b42cb3SPatrick Williams    finally:
12892b42cb3SPatrick Williams        os.chdir(olddir)
12992b42cb3SPatrick Williams}
13092b42cb3SPatrick Williams
13192b42cb3SPatrick Williamspython uninative_event_enable() {
13292b42cb3SPatrick Williams    """
13392b42cb3SPatrick Williams    This event handler is called in the workers and is responsible for setting
13492b42cb3SPatrick Williams    up uninative if a loader is found.
13592b42cb3SPatrick Williams    """
13692b42cb3SPatrick Williams    enable_uninative(d)
13792b42cb3SPatrick Williams}
13892b42cb3SPatrick Williams
13992b42cb3SPatrick Williamsdef enable_uninative(d):
14092b42cb3SPatrick Williams    loader = d.getVar("UNINATIVE_LOADER")
14192b42cb3SPatrick Williams    if os.path.exists(loader):
14292b42cb3SPatrick Williams        bb.debug(2, "Enabling uninative")
14392b42cb3SPatrick Williams        d.setVar("NATIVELSBSTRING", "universal%s" % oe.utils.host_gcc_version(d))
14492b42cb3SPatrick Williams        d.appendVar("SSTATEPOSTUNPACKFUNCS", " uninative_changeinterp")
14592b42cb3SPatrick Williams        d.appendVarFlag("SSTATEPOSTUNPACKFUNCS", "vardepvalueexclude", "| uninative_changeinterp")
146*03514f19SPatrick Williams        d.appendVar("BUILD_LDFLAGS", " -Wl,--allow-shlib-undefined -Wl,--dynamic-linker=${UNINATIVE_LOADER} -pthread")
147*03514f19SPatrick Williams        d.appendVarFlag("BUILD_LDFLAGS", "vardepvalueexclude", "| -Wl,--allow-shlib-undefined -Wl,--dynamic-linker=${UNINATIVE_LOADER} -pthread")
14892b42cb3SPatrick Williams        d.appendVarFlag("BUILD_LDFLAGS", "vardepsexclude", "UNINATIVE_LOADER")
1495082cc7fSAndrew Geissler        d.prependVar("PATH", "${UNINATIVE_STAGING_DIR}-uninative/${BUILD_ARCH}-linux${bindir_native}:")
15092b42cb3SPatrick Williams
15192b42cb3SPatrick Williamspython uninative_changeinterp () {
15292b42cb3SPatrick Williams    import subprocess
15392b42cb3SPatrick Williams    import stat
15492b42cb3SPatrick Williams    import oe.qa
15592b42cb3SPatrick Williams
15692b42cb3SPatrick Williams    if not (bb.data.inherits_class('native', d) or bb.data.inherits_class('crosssdk', d) or bb.data.inherits_class('cross', d)):
15792b42cb3SPatrick Williams        return
15892b42cb3SPatrick Williams
15992b42cb3SPatrick Williams    sstateinst = d.getVar('SSTATE_INSTDIR')
16092b42cb3SPatrick Williams    for walkroot, dirs, files in os.walk(sstateinst):
16192b42cb3SPatrick Williams        for file in files:
16292b42cb3SPatrick Williams            if file.endswith(".so") or ".so." in file:
16392b42cb3SPatrick Williams                continue
16492b42cb3SPatrick Williams            f = os.path.join(walkroot, file)
16592b42cb3SPatrick Williams            if os.path.islink(f):
16692b42cb3SPatrick Williams                continue
16792b42cb3SPatrick Williams            s = os.stat(f)
16892b42cb3SPatrick Williams            if not ((s[stat.ST_MODE] & stat.S_IXUSR) or (s[stat.ST_MODE] & stat.S_IXGRP) or (s[stat.ST_MODE] & stat.S_IXOTH)):
16992b42cb3SPatrick Williams                continue
17092b42cb3SPatrick Williams            elf = oe.qa.ELFFile(f)
17192b42cb3SPatrick Williams            try:
17292b42cb3SPatrick Williams                elf.open()
17392b42cb3SPatrick Williams            except oe.qa.NotELFFileError:
17492b42cb3SPatrick Williams                continue
17592b42cb3SPatrick Williams            if not elf.isDynamic():
17692b42cb3SPatrick Williams                continue
17792b42cb3SPatrick Williams
17892b42cb3SPatrick Williams            os.chmod(f, s[stat.ST_MODE] | stat.S_IWUSR)
17992b42cb3SPatrick Williams            subprocess.check_output(("patchelf-uninative", "--set-interpreter", d.getVar("UNINATIVE_LOADER"), f), stderr=subprocess.STDOUT)
18092b42cb3SPatrick Williams            os.chmod(f, s[stat.ST_MODE])
18192b42cb3SPatrick Williams}
182