external-toolchain.bbclass 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. # This class provides everything necessary for a recipe to pull bits from an
  2. # external toolchain:
  3. # - Automatically sets LIC_FILES_CHKSUM based on LICENSE if appropriate
  4. # - Searches the external toolchain sysroot and alternate locations for the
  5. # patterns specified in the FILES variables, with support for checking
  6. # alternate locations within the sysroot as well
  7. # - Automatically PROVIDES/RPROVIDES the non-external-suffixed names
  8. # - Usual bits to handle packaging of existing binaries
  9. # - Automatically skips the recipe if its files aren't available in the
  10. # external toolchain
  11. # Since these are prebuilt binaries, there are no source files to checksum for
  12. # LIC_FILES_CHKSUM, so use the license from common-licenses
  13. inherit common-license
  14. # We don't extract anything which will create S, and we don't want to see the
  15. # warning about it
  16. S = "${WORKDIR}"
  17. # Prebuilt binaries, no need for any default dependencies
  18. INHIBIT_DEFAULT_DEPS = "1"
  19. # Missing build deps don't matter when we don't build anything
  20. INSANE_SKIP:${PN} += "build-deps"
  21. EXTERNAL_PN ?= "${@PN.replace('-external', '')}"
  22. PROVIDES += "${EXTERNAL_PN}"
  23. LICENSE = "CLOSED"
  24. LIC_FILES_CHKSUM = "${COMMON_LIC_CHKSUM}"
  25. # Packaging requires objcopy/etc for split and strip
  26. PACKAGE_DEPENDS += "virtual/${MLPREFIX}${TARGET_PREFIX}binutils"
  27. do_configure[noexec] = "1"
  28. do_compile[noexec] = "1"
  29. EXTERNAL_PV_PREFIX ?= ""
  30. EXTERNAL_PV_SUFFIX ?= ""
  31. PV:prepend = "${@'${EXTERNAL_PV_PREFIX}' if '${EXTERNAL_PV_PREFIX}' else ''}"
  32. PV:append = "${@'${EXTERNAL_PV_SUFFIX}' if '${EXTERNAL_PV_SUFFIX}' else ''}"
  33. EXTERNAL_EXTRA_FILES ?= ""
  34. # Skip this recipe if we don't have files in the external toolchain
  35. EXTERNAL_AUTO_PROVIDE ?= "0"
  36. EXTERNAL_AUTO_PROVIDE:class-target ?= "1"
  37. # We don't care if this path references other variables
  38. EXTERNAL_TOOLCHAIN[vardepvalue] = "${EXTERNAL_TOOLCHAIN}"
  39. # We don't want to rebuild if the path to the toolchain changes, only if the
  40. # toolchain changes
  41. external_toolchain_do_install[vardepsexclude] += "EXTERNAL_TOOLCHAIN"
  42. EXTERNAL_INSTALL_SOURCE_PATHS[vardepsexclude] += "EXTERNAL_TOOLCHAIN"
  43. # Propagate file permissions mode from owner to the rest of the user
  44. # so the toolchain bits would be available for everyone to use even in the
  45. # directories with root permissions.
  46. EXTERNAL_PROPAGATE_MODE ?= "0"
  47. python () {
  48. # Skipping only matters up front
  49. if d.getVar('BB_WORKERCONTEXT', True) == '1':
  50. return
  51. if not d.getVar('TCMODE', True).startswith('external'):
  52. raise bb.parse.SkipPackage("External toolchain not configured (TCMODE not set to an external toolchain).")
  53. # We're not an available provider if there's no external toolchain
  54. if not d.getVar("EXTERNAL_TOOLCHAIN", True):
  55. raise bb.parse.SkipPackage("External toolchain not configured (EXTERNAL_TOOLCHAIN not set).")
  56. if not bb.utils.to_boolean(d.getVar('EXTERNAL_AUTO_PROVIDE', d)):
  57. return
  58. sysroots, mirrors, premirrors = oe.external.get_file_search_metadata(d)
  59. search_patterns = []
  60. pattern = d.getVar('EXTERNAL_PROVIDE_PATTERN', True)
  61. if pattern:
  62. search_patterns.append(pattern)
  63. else:
  64. files = oe.external.gather_pkg_files(d)
  65. search_patterns.extend(filter(lambda f: '.debug' not in f, files))
  66. expanded = oe.external.expand_paths(search_patterns, mirrors, premirrors)
  67. paths = oe.external.search_sysroots(expanded, sysroots)
  68. if not any(f for p, f in paths):
  69. raise bb.parse.SkipPackage('No files found in external toolchain sysroot for: {}'.format(', '.join(search_patterns)))
  70. }
  71. fakeroot python do_install () {
  72. bb.build.exec_func('external_toolchain_do_install', d)
  73. pass # Sentinel
  74. }
  75. def external_toolchain_propagate_mode (d, installdest):
  76. import stat
  77. propagate = d.getVar('EXTERNAL_PROPAGATE_MODE', True)
  78. if propagate == '0':
  79. return
  80. for root, dirs, files in os.walk(installdest):
  81. for bit in dirs + files:
  82. path = os.path.join(root, bit)
  83. try:
  84. bitstat = os.stat(path)
  85. except ValueError:
  86. continue
  87. else:
  88. newmode = bitstat.st_mode
  89. if bitstat.st_mode & stat.S_IRUSR:
  90. newmode |= stat.S_IRGRP | stat.S_IROTH
  91. if bitstat.st_mode & stat.S_IXUSR:
  92. newmode |= stat.S_IXGRP | stat.S_IXOTH
  93. os.chmod(path, newmode)
  94. python external_toolchain_do_install () {
  95. import subprocess
  96. installdest = d.getVar('D', True)
  97. sysroots, mirrors, premirrors = oe.external.get_file_search_metadata(d)
  98. files = oe.external.gather_pkg_files(d)
  99. oe.external.copy_from_sysroots(files, sysroots, mirrors, premirrors, installdest)
  100. if 'do_install_extra' in d:
  101. bb.build.exec_func('do_install_extra', d)
  102. external_toolchain_propagate_mode(d, installdest)
  103. }
  104. external_toolchain_do_install[vardeps] += "${@' '.join('FILES:%s' % pkg for pkg in '${PACKAGES}'.split())}"
  105. # Change do_install's CWD to EXTERNAL_TOOLCHAIN for convenience
  106. do_install[dirs] = "${D} ${EXTERNAL_TOOLCHAIN}"
  107. python () {
  108. # Deal with any do_install:append
  109. install = d.getVar('do_install', False)
  110. try:
  111. base, appended = install.split('# Sentinel', 1)
  112. except ValueError:
  113. pass
  114. else:
  115. d.setVar('do_install', base)
  116. if appended.strip():
  117. d.setVar('do_install_added', appended)
  118. d.setVarFlag('do_install_added', 'func', '1')
  119. d.appendVarFlag('do_install', 'postfuncs', ' do_install_added')
  120. }
  121. # Toolchain shipped binaries weren't necessarily built ideally
  122. WARN_QA:remove = "ldflags textrel"
  123. ERROR_QA:remove = "ldflags textrel"
  124. # Debug files may well have already been split out, or stripped out
  125. INSANE_SKIP:${PN} += "already-stripped"
  126. RPROVIDES:${PN} += "${EXTERNAL_PN}"
  127. RPROVIDES:${PN}-dev += "${EXTERNAL_PN}-dev"
  128. RPROVIDES:${PN}-staticdev += "${EXTERNAL_PN}-staticdev"
  129. RPROVIDES:${PN}-dbg += "${EXTERNAL_PN}-dbg"
  130. RPROVIDES:${PN}-doc += "${EXTERNAL_PN}-doc"
  131. RPROVIDES:${PN}-locale += "${EXTERNAL_PN}-locale"
  132. LOCALEBASEPN = "${EXTERNAL_PN}"
  133. FILES:${PN} = ""
  134. FILES:${PN}-dev = ""
  135. FILES:${PN}-staticdev = ""
  136. FILES:${PN}-doc = ""
  137. FILES:${PN}-locale = ""
  138. def debug_paths(d):
  139. l = d.createCopy()
  140. l.finalize()
  141. paths = []
  142. exclude = [
  143. l.getVar('datadir', True),
  144. l.getVar('includedir', True),
  145. ]
  146. for p in l.getVar('PACKAGES', True).split():
  147. if p.endswith('-dbg'):
  148. continue
  149. for f in (l.getVar('FILES:%s' % p, True) or '').split():
  150. if any((f == x or f.startswith(x + '/')) for x in exclude):
  151. continue
  152. d = os.path.dirname(f)
  153. b = os.path.basename(f)
  154. paths.append('/usr/lib/debug{0}/{1}.debug'.format(d, b))
  155. paths.append('{0}/.debug/{1}'.format(d, b))
  156. paths.append('{0}/.debug/{1}.debug'.format(d, b))
  157. return set(paths)
  158. FILES:${PN}-dbg = "${@' '.join(debug_paths(d))}"