sdk.py 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  1. from abc import ABCMeta, abstractmethod
  2. from oe.utils import execute_pre_post_process
  3. from oe.manifest import *
  4. from oe.package_manager import *
  5. import os
  6. import shutil
  7. import glob
  8. import traceback
  9. def generate_locale_archive(d, rootfs):
  10. # Pretty sure we don't need this for SDK archive generation but
  11. # keeping it to be safe...
  12. target_arch = d.getVar('SDK_ARCH')
  13. locale_arch_options = { \
  14. "arm": ["--uint32-align=4", "--little-endian"],
  15. "armeb": ["--uint32-align=4", "--big-endian"],
  16. "aarch64": ["--uint32-align=4", "--little-endian"],
  17. "aarch64_be": ["--uint32-align=4", "--big-endian"],
  18. "sh4": ["--uint32-align=4", "--big-endian"],
  19. "powerpc": ["--uint32-align=4", "--big-endian"],
  20. "powerpc64": ["--uint32-align=4", "--big-endian"],
  21. "mips": ["--uint32-align=4", "--big-endian"],
  22. "mipsisa32r6": ["--uint32-align=4", "--big-endian"],
  23. "mips64": ["--uint32-align=4", "--big-endian"],
  24. "mipsisa64r6": ["--uint32-align=4", "--big-endian"],
  25. "mipsel": ["--uint32-align=4", "--little-endian"],
  26. "mipsisa32r6el": ["--uint32-align=4", "--little-endian"],
  27. "mips64el": ["--uint32-align=4", "--little-endian"],
  28. "mipsisa64r6el": ["--uint32-align=4", "--little-endian"],
  29. "i586": ["--uint32-align=4", "--little-endian"],
  30. "i686": ["--uint32-align=4", "--little-endian"],
  31. "x86_64": ["--uint32-align=4", "--little-endian"]
  32. }
  33. if target_arch in locale_arch_options:
  34. arch_options = locale_arch_options[target_arch]
  35. else:
  36. bb.error("locale_arch_options not found for target_arch=" + target_arch)
  37. bb.fatal("unknown arch:" + target_arch + " for locale_arch_options")
  38. localedir = oe.path.join(rootfs, d.getVar("libdir_nativesdk"), "locale")
  39. # Need to set this so cross-localedef knows where the archive is
  40. env = dict(os.environ)
  41. env["LOCALEARCHIVE"] = oe.path.join(localedir, "locale-archive")
  42. for name in os.listdir(localedir):
  43. path = os.path.join(localedir, name)
  44. if os.path.isdir(path):
  45. try:
  46. cmd = ["cross-localedef", "--verbose"]
  47. cmd += arch_options
  48. cmd += ["--add-to-archive", path]
  49. subprocess.check_output(cmd, env=env, stderr=subprocess.STDOUT)
  50. except Exception as e:
  51. bb.fatal("Cannot create locale archive: %s" % e.output)
  52. class Sdk(object, metaclass=ABCMeta):
  53. def __init__(self, d, manifest_dir):
  54. self.d = d
  55. self.sdk_output = self.d.getVar('SDK_OUTPUT')
  56. self.sdk_native_path = self.d.getVar('SDKPATHNATIVE').strip('/')
  57. self.target_path = self.d.getVar('SDKTARGETSYSROOT').strip('/')
  58. self.sysconfdir = self.d.getVar('sysconfdir').strip('/')
  59. self.sdk_target_sysroot = os.path.join(self.sdk_output, self.target_path)
  60. self.sdk_host_sysroot = self.sdk_output
  61. if manifest_dir is None:
  62. self.manifest_dir = self.d.getVar("SDK_DIR")
  63. else:
  64. self.manifest_dir = manifest_dir
  65. self.remove(self.sdk_output, True)
  66. self.install_order = Manifest.INSTALL_ORDER
  67. @abstractmethod
  68. def _populate(self):
  69. pass
  70. def populate(self):
  71. self.mkdirhier(self.sdk_output)
  72. # call backend dependent implementation
  73. self._populate()
  74. # Don't ship any libGL in the SDK
  75. self.remove(os.path.join(self.sdk_output, self.sdk_native_path,
  76. self.d.getVar('libdir_nativesdk').strip('/'),
  77. "libGL*"))
  78. # Fix or remove broken .la files
  79. self.remove(os.path.join(self.sdk_output, self.sdk_native_path,
  80. self.d.getVar('libdir_nativesdk').strip('/'),
  81. "*.la"))
  82. # Link the ld.so.cache file into the hosts filesystem
  83. link_name = os.path.join(self.sdk_output, self.sdk_native_path,
  84. self.sysconfdir, "ld.so.cache")
  85. self.mkdirhier(os.path.dirname(link_name))
  86. os.symlink("/etc/ld.so.cache", link_name)
  87. execute_pre_post_process(self.d, self.d.getVar('SDK_POSTPROCESS_COMMAND'))
  88. def movefile(self, sourcefile, destdir):
  89. try:
  90. # FIXME: this check of movefile's return code to None should be
  91. # fixed within the function to use only exceptions to signal when
  92. # something goes wrong
  93. if (bb.utils.movefile(sourcefile, destdir) == None):
  94. raise OSError("moving %s to %s failed"
  95. %(sourcefile, destdir))
  96. #FIXME: using umbrella exc catching because bb.utils method raises it
  97. except Exception as e:
  98. bb.debug(1, "printing the stack trace\n %s" %traceback.format_exc())
  99. bb.error("unable to place %s in final SDK location" % sourcefile)
  100. def mkdirhier(self, dirpath):
  101. try:
  102. bb.utils.mkdirhier(dirpath)
  103. except OSError as e:
  104. bb.debug(1, "printing the stack trace\n %s" %traceback.format_exc())
  105. bb.fatal("cannot make dir for SDK: %s" % dirpath)
  106. def remove(self, path, recurse=False):
  107. try:
  108. bb.utils.remove(path, recurse)
  109. #FIXME: using umbrella exc catching because bb.utils method raises it
  110. except Exception as e:
  111. bb.debug(1, "printing the stack trace\n %s" %traceback.format_exc())
  112. bb.warn("cannot remove SDK dir: %s" % path)
  113. def install_locales(self, pm):
  114. # This is only relevant for glibc
  115. if self.d.getVar("TCLIBC") != "glibc":
  116. return
  117. linguas = self.d.getVar("SDKIMAGE_LINGUAS")
  118. if linguas:
  119. import fnmatch
  120. # Install the binary locales
  121. if linguas == "all":
  122. pm.install_glob("nativesdk-glibc-binary-localedata-*.utf-8", sdk=True)
  123. else:
  124. for lang in linguas.split():
  125. pm.install("nativesdk-glibc-binary-localedata-%s.utf-8" % lang)
  126. # Generate a locale archive of them
  127. generate_locale_archive(self.d, oe.path.join(self.sdk_host_sysroot, self.sdk_native_path))
  128. # And now delete the binary locales
  129. pkgs = fnmatch.filter(pm.list_installed(), "nativesdk-glibc-binary-localedata-*.utf-8")
  130. pm.remove(pkgs)
  131. else:
  132. # No linguas so do nothing
  133. pass
  134. class RpmSdk(Sdk):
  135. def __init__(self, d, manifest_dir=None, rpm_workdir="oe-sdk-repo"):
  136. super(RpmSdk, self).__init__(d, manifest_dir)
  137. self.target_manifest = RpmManifest(d, self.manifest_dir,
  138. Manifest.MANIFEST_TYPE_SDK_TARGET)
  139. self.host_manifest = RpmManifest(d, self.manifest_dir,
  140. Manifest.MANIFEST_TYPE_SDK_HOST)
  141. rpm_repo_workdir = "oe-sdk-repo"
  142. if "sdk_ext" in d.getVar("BB_RUNTASK"):
  143. rpm_repo_workdir = "oe-sdk-ext-repo"
  144. self.target_pm = RpmPM(d,
  145. self.sdk_target_sysroot,
  146. self.d.getVar('TARGET_VENDOR'),
  147. 'target',
  148. rpm_repo_workdir=rpm_repo_workdir
  149. )
  150. self.host_pm = RpmPM(d,
  151. self.sdk_host_sysroot,
  152. self.d.getVar('SDK_VENDOR'),
  153. 'host',
  154. "SDK_PACKAGE_ARCHS",
  155. "SDK_OS",
  156. rpm_repo_workdir=rpm_repo_workdir
  157. )
  158. def _populate_sysroot(self, pm, manifest):
  159. pkgs_to_install = manifest.parse_initial_manifest()
  160. pm.create_configs()
  161. pm.write_index()
  162. pm.update()
  163. pkgs = []
  164. pkgs_attempt = []
  165. for pkg_type in pkgs_to_install:
  166. if pkg_type == Manifest.PKG_TYPE_ATTEMPT_ONLY:
  167. pkgs_attempt += pkgs_to_install[pkg_type]
  168. else:
  169. pkgs += pkgs_to_install[pkg_type]
  170. pm.install(pkgs)
  171. pm.install(pkgs_attempt, True)
  172. def _populate(self):
  173. execute_pre_post_process(self.d, self.d.getVar("POPULATE_SDK_PRE_TARGET_COMMAND"))
  174. bb.note("Installing TARGET packages")
  175. self._populate_sysroot(self.target_pm, self.target_manifest)
  176. self.target_pm.install_complementary(self.d.getVar('SDKIMAGE_INSTALL_COMPLEMENTARY'))
  177. execute_pre_post_process(self.d, self.d.getVar("POPULATE_SDK_POST_TARGET_COMMAND"))
  178. if not bb.utils.contains("SDKIMAGE_FEATURES", "package-management", True, False, self.d):
  179. self.target_pm.remove_packaging_data()
  180. bb.note("Installing NATIVESDK packages")
  181. self._populate_sysroot(self.host_pm, self.host_manifest)
  182. self.install_locales(self.host_pm)
  183. execute_pre_post_process(self.d, self.d.getVar("POPULATE_SDK_POST_HOST_COMMAND"))
  184. if not bb.utils.contains("SDKIMAGE_FEATURES", "package-management", True, False, self.d):
  185. self.host_pm.remove_packaging_data()
  186. # Move host RPM library data
  187. native_rpm_state_dir = os.path.join(self.sdk_output,
  188. self.sdk_native_path,
  189. self.d.getVar('localstatedir_nativesdk').strip('/'),
  190. "lib",
  191. "rpm"
  192. )
  193. self.mkdirhier(native_rpm_state_dir)
  194. for f in glob.glob(os.path.join(self.sdk_output,
  195. "var",
  196. "lib",
  197. "rpm",
  198. "*")):
  199. self.movefile(f, native_rpm_state_dir)
  200. self.remove(os.path.join(self.sdk_output, "var"), True)
  201. # Move host sysconfig data
  202. native_sysconf_dir = os.path.join(self.sdk_output,
  203. self.sdk_native_path,
  204. self.d.getVar('sysconfdir',
  205. True).strip('/'),
  206. )
  207. self.mkdirhier(native_sysconf_dir)
  208. for f in glob.glob(os.path.join(self.sdk_output, "etc", "rpm*")):
  209. self.movefile(f, native_sysconf_dir)
  210. for f in glob.glob(os.path.join(self.sdk_output, "etc", "dnf", "*")):
  211. self.movefile(f, native_sysconf_dir)
  212. self.remove(os.path.join(self.sdk_output, "etc"), True)
  213. class OpkgSdk(Sdk):
  214. def __init__(self, d, manifest_dir=None):
  215. super(OpkgSdk, self).__init__(d, manifest_dir)
  216. self.target_conf = self.d.getVar("IPKGCONF_TARGET")
  217. self.host_conf = self.d.getVar("IPKGCONF_SDK")
  218. self.target_manifest = OpkgManifest(d, self.manifest_dir,
  219. Manifest.MANIFEST_TYPE_SDK_TARGET)
  220. self.host_manifest = OpkgManifest(d, self.manifest_dir,
  221. Manifest.MANIFEST_TYPE_SDK_HOST)
  222. self.target_pm = OpkgPM(d, self.sdk_target_sysroot, self.target_conf,
  223. self.d.getVar("ALL_MULTILIB_PACKAGE_ARCHS"))
  224. self.host_pm = OpkgPM(d, self.sdk_host_sysroot, self.host_conf,
  225. self.d.getVar("SDK_PACKAGE_ARCHS"))
  226. def _populate_sysroot(self, pm, manifest):
  227. pkgs_to_install = manifest.parse_initial_manifest()
  228. if (self.d.getVar('BUILD_IMAGES_FROM_FEEDS') or "") != "1":
  229. pm.write_index()
  230. pm.update()
  231. for pkg_type in self.install_order:
  232. if pkg_type in pkgs_to_install:
  233. pm.install(pkgs_to_install[pkg_type],
  234. [False, True][pkg_type == Manifest.PKG_TYPE_ATTEMPT_ONLY])
  235. def _populate(self):
  236. execute_pre_post_process(self.d, self.d.getVar("POPULATE_SDK_PRE_TARGET_COMMAND"))
  237. bb.note("Installing TARGET packages")
  238. self._populate_sysroot(self.target_pm, self.target_manifest)
  239. self.target_pm.install_complementary(self.d.getVar('SDKIMAGE_INSTALL_COMPLEMENTARY'))
  240. execute_pre_post_process(self.d, self.d.getVar("POPULATE_SDK_POST_TARGET_COMMAND"))
  241. if not bb.utils.contains("SDKIMAGE_FEATURES", "package-management", True, False, self.d):
  242. self.target_pm.remove_packaging_data()
  243. bb.note("Installing NATIVESDK packages")
  244. self._populate_sysroot(self.host_pm, self.host_manifest)
  245. self.install_locales(self.host_pm)
  246. execute_pre_post_process(self.d, self.d.getVar("POPULATE_SDK_POST_HOST_COMMAND"))
  247. if not bb.utils.contains("SDKIMAGE_FEATURES", "package-management", True, False, self.d):
  248. self.host_pm.remove_packaging_data()
  249. target_sysconfdir = os.path.join(self.sdk_target_sysroot, self.sysconfdir)
  250. host_sysconfdir = os.path.join(self.sdk_host_sysroot, self.sysconfdir)
  251. self.mkdirhier(target_sysconfdir)
  252. shutil.copy(self.target_conf, target_sysconfdir)
  253. os.chmod(os.path.join(target_sysconfdir,
  254. os.path.basename(self.target_conf)), 0o644)
  255. self.mkdirhier(host_sysconfdir)
  256. shutil.copy(self.host_conf, host_sysconfdir)
  257. os.chmod(os.path.join(host_sysconfdir,
  258. os.path.basename(self.host_conf)), 0o644)
  259. native_opkg_state_dir = os.path.join(self.sdk_output, self.sdk_native_path,
  260. self.d.getVar('localstatedir_nativesdk').strip('/'),
  261. "lib", "opkg")
  262. self.mkdirhier(native_opkg_state_dir)
  263. for f in glob.glob(os.path.join(self.sdk_output, "var", "lib", "opkg", "*")):
  264. self.movefile(f, native_opkg_state_dir)
  265. self.remove(os.path.join(self.sdk_output, "var"), True)
  266. class DpkgSdk(Sdk):
  267. def __init__(self, d, manifest_dir=None):
  268. super(DpkgSdk, self).__init__(d, manifest_dir)
  269. self.target_conf_dir = os.path.join(self.d.getVar("APTCONF_TARGET"), "apt")
  270. self.host_conf_dir = os.path.join(self.d.getVar("APTCONF_TARGET"), "apt-sdk")
  271. self.target_manifest = DpkgManifest(d, self.manifest_dir,
  272. Manifest.MANIFEST_TYPE_SDK_TARGET)
  273. self.host_manifest = DpkgManifest(d, self.manifest_dir,
  274. Manifest.MANIFEST_TYPE_SDK_HOST)
  275. self.target_pm = DpkgPM(d, self.sdk_target_sysroot,
  276. self.d.getVar("PACKAGE_ARCHS"),
  277. self.d.getVar("DPKG_ARCH"),
  278. self.target_conf_dir)
  279. self.host_pm = DpkgPM(d, self.sdk_host_sysroot,
  280. self.d.getVar("SDK_PACKAGE_ARCHS"),
  281. self.d.getVar("DEB_SDK_ARCH"),
  282. self.host_conf_dir)
  283. def _copy_apt_dir_to(self, dst_dir):
  284. staging_etcdir_native = self.d.getVar("STAGING_ETCDIR_NATIVE")
  285. self.remove(dst_dir, True)
  286. shutil.copytree(os.path.join(staging_etcdir_native, "apt"), dst_dir)
  287. def _populate_sysroot(self, pm, manifest):
  288. pkgs_to_install = manifest.parse_initial_manifest()
  289. pm.write_index()
  290. pm.update()
  291. for pkg_type in self.install_order:
  292. if pkg_type in pkgs_to_install:
  293. pm.install(pkgs_to_install[pkg_type],
  294. [False, True][pkg_type == Manifest.PKG_TYPE_ATTEMPT_ONLY])
  295. def _populate(self):
  296. execute_pre_post_process(self.d, self.d.getVar("POPULATE_SDK_PRE_TARGET_COMMAND"))
  297. bb.note("Installing TARGET packages")
  298. self._populate_sysroot(self.target_pm, self.target_manifest)
  299. self.target_pm.install_complementary(self.d.getVar('SDKIMAGE_INSTALL_COMPLEMENTARY'))
  300. execute_pre_post_process(self.d, self.d.getVar("POPULATE_SDK_POST_TARGET_COMMAND"))
  301. self._copy_apt_dir_to(os.path.join(self.sdk_target_sysroot, "etc", "apt"))
  302. if not bb.utils.contains("SDKIMAGE_FEATURES", "package-management", True, False, self.d):
  303. self.target_pm.remove_packaging_data()
  304. bb.note("Installing NATIVESDK packages")
  305. self._populate_sysroot(self.host_pm, self.host_manifest)
  306. self.install_locales(self.host_pm)
  307. execute_pre_post_process(self.d, self.d.getVar("POPULATE_SDK_POST_HOST_COMMAND"))
  308. self._copy_apt_dir_to(os.path.join(self.sdk_output, self.sdk_native_path,
  309. "etc", "apt"))
  310. if not bb.utils.contains("SDKIMAGE_FEATURES", "package-management", True, False, self.d):
  311. self.host_pm.remove_packaging_data()
  312. native_dpkg_state_dir = os.path.join(self.sdk_output, self.sdk_native_path,
  313. "var", "lib", "dpkg")
  314. self.mkdirhier(native_dpkg_state_dir)
  315. for f in glob.glob(os.path.join(self.sdk_output, "var", "lib", "dpkg", "*")):
  316. self.movefile(f, native_dpkg_state_dir)
  317. self.remove(os.path.join(self.sdk_output, "var"), True)
  318. def sdk_list_installed_packages(d, target, rootfs_dir=None):
  319. if rootfs_dir is None:
  320. sdk_output = d.getVar('SDK_OUTPUT')
  321. target_path = d.getVar('SDKTARGETSYSROOT').strip('/')
  322. rootfs_dir = [sdk_output, os.path.join(sdk_output, target_path)][target is True]
  323. img_type = d.getVar('IMAGE_PKGTYPE')
  324. if img_type == "rpm":
  325. arch_var = ["SDK_PACKAGE_ARCHS", None][target is True]
  326. os_var = ["SDK_OS", None][target is True]
  327. return RpmPkgsList(d, rootfs_dir).list_pkgs()
  328. elif img_type == "ipk":
  329. conf_file_var = ["IPKGCONF_SDK", "IPKGCONF_TARGET"][target is True]
  330. return OpkgPkgsList(d, rootfs_dir, d.getVar(conf_file_var)).list_pkgs()
  331. elif img_type == "deb":
  332. return DpkgPkgsList(d, rootfs_dir).list_pkgs()
  333. def populate_sdk(d, manifest_dir=None):
  334. env_bkp = os.environ.copy()
  335. img_type = d.getVar('IMAGE_PKGTYPE')
  336. if img_type == "rpm":
  337. RpmSdk(d, manifest_dir).populate()
  338. elif img_type == "ipk":
  339. OpkgSdk(d, manifest_dir).populate()
  340. elif img_type == "deb":
  341. DpkgSdk(d, manifest_dir).populate()
  342. os.environ.clear()
  343. os.environ.update(env_bkp)
  344. def get_extra_sdkinfo(sstate_dir):
  345. """
  346. This function is going to be used for generating the target and host manifest files packages of eSDK.
  347. """
  348. import math
  349. extra_info = {}
  350. extra_info['tasksizes'] = {}
  351. extra_info['filesizes'] = {}
  352. for root, _, files in os.walk(sstate_dir):
  353. for fn in files:
  354. if fn.endswith('.tgz'):
  355. fsize = int(math.ceil(float(os.path.getsize(os.path.join(root, fn))) / 1024))
  356. task = fn.rsplit(':',1)[1].split('_',1)[1].split(',')[0]
  357. origtotal = extra_info['tasksizes'].get(task, 0)
  358. extra_info['tasksizes'][task] = origtotal + fsize
  359. extra_info['filesizes'][fn] = fsize
  360. return extra_info
  361. if __name__ == "__main__":
  362. pass