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