uninative.bbclass 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. #
  2. # Copyright OpenEmbedded Contributors
  3. #
  4. # SPDX-License-Identifier: MIT
  5. #
  6. UNINATIVE_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)}"
  7. UNINATIVE_STAGING_DIR ?= "${STAGING_DIR}"
  8. UNINATIVE_URL ?= "unset"
  9. UNINATIVE_TARBALL ?= "${BUILD_ARCH}-nativesdk-libc-${UNINATIVE_VERSION}.tar.xz"
  10. # Example checksums
  11. #UNINATIVE_CHECKSUM[aarch64] = "dead"
  12. #UNINATIVE_CHECKSUM[i686] = "dead"
  13. #UNINATIVE_CHECKSUM[x86_64] = "dead"
  14. UNINATIVE_DLDIR ?= "${DL_DIR}/uninative/"
  15. # Enabling uninative will change the following variables so they need to go the parsing ignored variables list to prevent multiple recipe parsing
  16. BB_HASHCONFIG_IGNORE_VARS += "NATIVELSBSTRING SSTATEPOSTUNPACKFUNCS BUILD_LDFLAGS"
  17. addhandler uninative_event_fetchloader
  18. uninative_event_fetchloader[eventmask] = "bb.event.BuildStarted"
  19. addhandler uninative_event_enable
  20. uninative_event_enable[eventmask] = "bb.event.ConfigParsed"
  21. python uninative_event_fetchloader() {
  22. """
  23. This event fires on the parent and will try to fetch the tarball if the
  24. loader isn't already present.
  25. """
  26. chksum = d.getVarFlag("UNINATIVE_CHECKSUM", d.getVar("BUILD_ARCH"))
  27. if not chksum:
  28. bb.fatal("Uninative selected but not configured correctly, please set UNINATIVE_CHECKSUM[%s]" % d.getVar("BUILD_ARCH"))
  29. loader = d.getVar("UNINATIVE_LOADER")
  30. loaderchksum = loader + ".chksum"
  31. if os.path.exists(loader) and os.path.exists(loaderchksum):
  32. with open(loaderchksum, "r") as f:
  33. readchksum = f.read().strip()
  34. if readchksum == chksum:
  35. if "uninative" not in d.getVar("SSTATEPOSTUNPACKFUNCS"):
  36. enable_uninative(d)
  37. return
  38. import subprocess
  39. try:
  40. # Save and restore cwd as Fetch.download() does a chdir()
  41. olddir = os.getcwd()
  42. tarball = d.getVar("UNINATIVE_TARBALL")
  43. tarballdir = os.path.join(d.getVar("UNINATIVE_DLDIR"), chksum)
  44. tarballpath = os.path.join(tarballdir, tarball)
  45. if not os.path.exists(tarballpath + ".done"):
  46. bb.utils.mkdirhier(tarballdir)
  47. if d.getVar("UNINATIVE_URL") == "unset":
  48. bb.fatal("Uninative selected but not configured, please set UNINATIVE_URL")
  49. localdata = bb.data.createCopy(d)
  50. localdata.setVar('FILESPATH', "")
  51. localdata.setVar('DL_DIR', tarballdir)
  52. # Our games with path manipulation of DL_DIR mean standard PREMIRRORS don't work
  53. # and we can't easily put 'chksum' into the url path from a url parameter with
  54. # the current fetcher url handling
  55. premirrors = bb.fetch2.mirror_from_string(localdata.getVar("PREMIRRORS"))
  56. for line in premirrors:
  57. try:
  58. (find, replace) = line
  59. except ValueError:
  60. continue
  61. if find.startswith("http"):
  62. localdata.appendVar("PREMIRRORS", " ${UNINATIVE_URL}${UNINATIVE_TARBALL} %s/uninative/%s/${UNINATIVE_TARBALL}" % (replace, chksum))
  63. srcuri = d.expand("${UNINATIVE_URL}${UNINATIVE_TARBALL};sha256sum=%s" % chksum)
  64. bb.note("Fetching uninative binary shim %s (will check PREMIRRORS first)" % srcuri)
  65. fetcher = bb.fetch2.Fetch([srcuri], localdata, cache=False)
  66. fetcher.download()
  67. localpath = fetcher.localpath(srcuri)
  68. if localpath != tarballpath and os.path.exists(localpath) and not os.path.exists(tarballpath):
  69. # Follow the symlink behavior from the bitbake fetch2.
  70. # This will cover the case where an existing symlink is broken
  71. # as well as if there are two processes trying to create it
  72. # at the same time.
  73. if os.path.islink(tarballpath):
  74. # Broken symbolic link
  75. os.unlink(tarballpath)
  76. # Deal with two processes trying to make symlink at once
  77. try:
  78. os.symlink(localpath, tarballpath)
  79. except FileExistsError:
  80. pass
  81. # ldd output is "ldd (Ubuntu GLIBC 2.23-0ubuntu10) 2.23", extract last option from first line
  82. glibcver = subprocess.check_output(["ldd", "--version"]).decode('utf-8').split('\n')[0].split()[-1]
  83. if bb.utils.vercmp_string(d.getVar("UNINATIVE_MAXGLIBCVERSION"), glibcver) < 0:
  84. 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")))
  85. cmd = d.expand("\
  86. mkdir -p ${UNINATIVE_STAGING_DIR}-uninative; \
  87. cd ${UNINATIVE_STAGING_DIR}-uninative; \
  88. tar -xJf ${UNINATIVE_DLDIR}/%s/${UNINATIVE_TARBALL}; \
  89. ${UNINATIVE_STAGING_DIR}-uninative/relocate_sdk.py \
  90. ${UNINATIVE_STAGING_DIR}-uninative/${BUILD_ARCH}-linux \
  91. ${UNINATIVE_LOADER} \
  92. ${UNINATIVE_LOADER} \
  93. ${UNINATIVE_STAGING_DIR}-uninative/${BUILD_ARCH}-linux/${bindir_native}/patchelf-uninative \
  94. ${UNINATIVE_STAGING_DIR}-uninative/${BUILD_ARCH}-linux${base_libdir_native}/libc*.so*" % chksum)
  95. subprocess.check_output(cmd, shell=True, text=True, stderr=subprocess.STDOUT)
  96. with open(loaderchksum, "w") as f:
  97. f.write(chksum)
  98. enable_uninative(d)
  99. except RuntimeError as e:
  100. bb.warn(str(e))
  101. except bb.fetch2.BBFetchException as exc:
  102. bb.warn("Disabling uninative as unable to fetch uninative tarball: %s" % str(exc))
  103. bb.warn("To build your own uninative loader, please bitbake uninative-tarball and set UNINATIVE_TARBALL appropriately.")
  104. except subprocess.CalledProcessError as exc:
  105. bb.warn("Disabling uninative as unable to install uninative tarball:")
  106. bb.warn(str(exc))
  107. bb.warn(exc.stdout)
  108. bb.warn("To build your own uninative loader, please bitbake uninative-tarball and set UNINATIVE_TARBALL appropriately.")
  109. finally:
  110. os.chdir(olddir)
  111. }
  112. python uninative_event_enable() {
  113. """
  114. This event handler is called in the workers and is responsible for setting
  115. up uninative if a loader is found.
  116. """
  117. enable_uninative(d)
  118. }
  119. def enable_uninative(d):
  120. loader = d.getVar("UNINATIVE_LOADER")
  121. if os.path.exists(loader):
  122. bb.debug(2, "Enabling uninative")
  123. d.setVar("NATIVELSBSTRING", "universal")
  124. d.appendVar("SSTATEPOSTUNPACKFUNCS", " uninative_changeinterp")
  125. d.appendVarFlag("SSTATEPOSTUNPACKFUNCS", "vardepvalueexclude", "| uninative_changeinterp")
  126. d.appendVar("BUILD_LDFLAGS", " -Wl,--allow-shlib-undefined -Wl,--dynamic-linker=${UNINATIVE_LOADER} -pthread")
  127. d.appendVarFlag("BUILD_LDFLAGS", "vardepvalueexclude", "| -Wl,--allow-shlib-undefined -Wl,--dynamic-linker=${UNINATIVE_LOADER} -pthread")
  128. d.appendVarFlag("BUILD_LDFLAGS", "vardepsexclude", "UNINATIVE_LOADER")
  129. d.prependVar("PATH", "${UNINATIVE_STAGING_DIR}-uninative/${BUILD_ARCH}-linux${bindir_native}:")
  130. python uninative_changeinterp () {
  131. import subprocess
  132. import stat
  133. import oe.qa
  134. if not (bb.data.inherits_class('native', d) or bb.data.inherits_class('crosssdk', d) or bb.data.inherits_class('cross', d)):
  135. return
  136. sstateinst = d.getVar('SSTATE_INSTDIR')
  137. for walkroot, dirs, files in os.walk(sstateinst):
  138. for file in files:
  139. if file.endswith(".so") or ".so." in file:
  140. continue
  141. f = os.path.join(walkroot, file)
  142. if os.path.islink(f):
  143. continue
  144. s = os.stat(f)
  145. 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)):
  146. continue
  147. elf = oe.qa.ELFFile(f)
  148. try:
  149. elf.open()
  150. except oe.qa.NotELFFileError:
  151. continue
  152. if not elf.isDynamic():
  153. continue
  154. os.chmod(f, s[stat.ST_MODE] | stat.S_IWUSR)
  155. subprocess.check_output(("patchelf-uninative", "--set-interpreter", d.getVar("UNINATIVE_LOADER"), f), stderr=subprocess.STDOUT)
  156. os.chmod(f, s[stat.ST_MODE])
  157. }