SDK、eSDK、toolchain之间的关系
toolchain 属于 sdk;sdk属于esdk(可以这样简单的描述)
toolchain
工具链,没啥说的。
sdk
在toolchain之上添加了一些库。
esdk
在sdk的基础上,添加了devtool。
相关信息可以看这里
预总结:文章目的是搞清楚toolchain、sdk、esdk是如何产生的。
bitbake image -c populate_sdk —— 从这里开始
从该命令看出,sdk跟rootfs是紧密相关的(官方文档也说明了这一点)。
populate_sdk代码在populate_sdk_base.bbclass中,至于rootfs如何继承的目前没有理清,暂时mark一下,以后再看。
这直接看代码:
109 def populate_sdk_common(d):
110 from oe.sdk import populate_sdk
111 from oe.manifest import create_manifest, Manifest
112
113 # Handle package exclusions
114 excl_pkgs = (d.getVar("PACKAGE_EXCLUDE") or "").split()
115 inst_pkgs = (d.getVar("PACKAGE_INSTALL") or "").split()
116 inst_attempt_pkgs = (d.getVar("PACKAGE_INSTALL_ATTEMPTONLY") or "").split()
117
118 d.setVar('PACKAGE_INSTALL_ORIG', ' '.join(inst_pkgs))
119 d.setVar('PACKAGE_INSTALL_ATTEMPTONLY', ' '.join(inst_attempt_pkgs))
120
121 for pkg in excl_pkgs:
122 ¦ if pkg in inst_pkgs:
123 ¦ ¦ bb.warn("Package %s, set to be excluded, is in %s PACKAGE_INSTALL (%s). It will be removed from the list." % (pkg, d.getVar('PN'), inst_pkgs))
124 ¦ ¦ inst_pkgs.remove(pkg)
125
126 ¦ if pkg in inst_attempt_pkgs:
127 ¦ ¦ bb.warn("Package %s, set to be excluded, is in %s PACKAGE_INSTALL_ATTEMPTONLY (%s). It will be removed from the list." % (pkg, d.getVar('PN'), inst_pkgs))
128 ¦ ¦ inst_attempt_pkgs.remove(pkg)
129
130 d.setVar("PACKAGE_INSTALL", ' '.join(inst_pkgs))
131 d.setVar("PACKAGE_INSTALL_ATTEMPTONLY", ' '.join(inst_attempt_pkgs))
132
133 pn = d.getVar('PN')
134 runtime_mapping_rename("TOOLCHAIN_TARGET_TASK", pn, d)
135 runtime_mapping_rename("TOOLCHAIN_TARGET_TASK_ATTEMPTONLY", pn, d)
136
137 ld = bb.data.createCopy(d)
138 ld.setVar("PKGDATA_DIR", "${STAGING_DIR}/${SDK_ARCH}-${SDKPKGSUFFIX}${SDK_VENDOR}-${SDK_OS}/pkgdata")
139 runtime_mapping_rename("TOOLCHAIN_HOST_TASK", pn, ld)
140 runtime_mapping_rename("TOOLCHAIN_HOST_TASK_ATTEMPTONLY", pn, ld)
141 d.setVar("TOOLCHAIN_HOST_TASK", ld.getVar("TOOLCHAIN_HOST_TASK"))
142 d.setVar("TOOLCHAIN_HOST_TASK_ATTEMPTONLY", ld.getVar("TOOLCHAIN_HOST_TASK_ATTEMPTONLY"))
143
144 # create target/host SDK manifests
145 create_manifest(d, manifest_dir=d.getVar('SDK_DIR'),
146 ¦ ¦ ¦ ¦ manifest_type=Manifest.MANIFEST_TYPE_SDK_HOST)
147 create_manifest(d, manifest_dir=d.getVar('SDK_DIR'),
148 ¦ ¦ ¦ ¦ manifest_type=Manifest.MANIFEST_TYPE_SDK_TARGET)
149
150 populate_sdk(d)
151
152 fakeroot python do_populate_sdk() {
153 populate_sdk_common(d)
154 }
关键步骤:
- 设置
PACKAGE_INSTALL
- 设置
PACKAGE_INSTALL_ATTEMPTONLY
- 设置
TOOLCHAIN_TARGET_TASK
- 设置
TOOLCHAIN_HOST_TASK
- 设置
TOOLCHAIN_HOST_TASK_ATTEMPTONLY
- create_manifest for
MANIFEST_TYPE_SDK_HOST
- create_manifest for
MANIFEST_TYPE_SDK_TARGET
populate_sdk
以core-image-minimal
为例
export PACKAGE_INSTALL="packagegroup-core-boot run-postinsts "
PACKAGE_INSTALL_ATTEMPTONLY=""
TOOLCHAIN_TARGET_TASK="packagegroup-core-standalone-sdk-target target-sdk-provides-dummy packagegroup-core-boot run-postinsts "
TOOLCHAIN_TARGET_TASK_ATTEMPTONLY=" "
TOOLCHAIN_HOST_TASK="nativesdk-packagegroup-sdk-host packagegroup-cross-canadian-qemux86"
TOOLCHAIN_HOST_TASK_ATTEMPTONLY=""
明显TOOLCHAIN_TARGET_TASK TOOLCHAIN_HOST_TASK
是重点,所以
先看一下runtime_mapping_rename
做了啥。
520 def runtime_mapping_rename (varname, pkg, d):
521 #bb.note("%s before: %s" % (varname, d.getVar(varname)))
522
523 new_depends = {}
524 deps = bb.utils.explode_dep_versions2(d.getVar(varname) or "")
525 for depend in deps:
526 ¦ new_depend = get_package_mapping(depend, pkg, d)
527 ¦ new_depends[new_depend] = deps[depend]
528
529 d.setVar(varname, bb.utils.join_deps(new_depends, commasep=False))
530
531 #bb.note("%s after: %s" % (varname, d.getVar(varname)))
494 def get_package_mapping (pkg, basepkg, d):
495 import oe.packagedata
496
497 data = oe.packagedata.read_subpkgdata(pkg, d)
498 key = "PKG_%s" % pkg
499
500 if key in data:
501 ¦ # Have to avoid undoing the write_extra_pkgs(global_variants...)
502 ¦ if bb.data.inherits_class('allarch', d) and not d.getVar('MULTILIB_VARIANTS') \
503 ¦ ¦ and data[key] == basepkg:
504 ¦ ¦ return pkg
505 ¦ return data[key]
506
507 return pkg
185 def explode_dep_versions2(s, *, sort=True): #这里看注释就够了
186 """
187 Take an RDEPENDS style string of format:
188 "DEPEND1 (optional version) DEPEND2 (optional version) ..."
189 and return a dictionary of dependencies and versions.
190 """
目前看懂这3个函数需要明白packagedata
,先mark后续再看。
看create_manifest做了啥。
333 def create_manifest(d, final_manifest=False, manifest_dir=None,
334 ¦ ¦ ¦ ¦ manifest_type=Manifest.MANIFEST_TYPE_IMAGE):
335 manifest_map = {'rpm': RpmManifest,
336 ¦ ¦ ¦ ¦ 'ipk': OpkgManifest,
337 ¦ ¦ ¦ ¦ 'deb': DpkgManifest}
338
339 manifest = manifest_map[d.getVar('IMAGE_PKGTYPE')](d, manifest_dir, manifest_type)
340
341 if final_manifest:
342 ¦ manifest.create_final()
343 else:
344 ¦ manifest.create_initial()
311 class DpkgManifest(Manifest):
312 def create_initial(self):
313 ¦ with open(self.initial_manifest, "w+") as manifest:
314 ¦ ¦ manifest.write(self.initial_manifest_file_header)
315
316 ¦ ¦ for var in self.var_maps[self.manifest_type]:
317 ¦ ¦ ¦ pkg_list = self.d.getVar(var)
318
319 ¦ ¦ ¦ if pkg_list is None:
320 ¦ ¦ ¦ ¦ continue
321
322 ¦ ¦ ¦ for pkg in pkg_list.split():
323 ¦ ¦ ¦ ¦ manifest.write("%s,%s\n" %
324 ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ (self.var_maps[self.manifest_type][var], pkg))
25 var_maps = {
26 ¦ MANIFEST_TYPE_IMAGE: {
27 ¦ ¦ "PACKAGE_INSTALL": PKG_TYPE_MUST_INSTALL,
28 ¦ ¦ "PACKAGE_INSTALL_ATTEMPTONLY": PKG_TYPE_ATTEMPT_ONLY,
29 ¦ ¦ "LINGUAS_INSTALL": PKG_TYPE_LANGUAGE
30 ¦ },
31 ¦ MANIFEST_TYPE_SDK_HOST: {
32 ¦ ¦ "TOOLCHAIN_HOST_TASK": PKG_TYPE_MUST_INSTALL,
33 ¦ ¦ "TOOLCHAIN_HOST_TASK_ATTEMPTONLY": PKG_TYPE_ATTEMPT_ONLY
34 ¦ },
35 ¦ MANIFEST_TYPE_SDK_TARGET: {
36 ¦ ¦ "TOOLCHAIN_TARGET_TASK": PKG_TYPE_MUST_INSTALL,
37 ¦ ¦ "TOOLCHAIN_TARGET_TASK_ATTEMPTONLY": PKG_TYPE_ATTEMPT_ONLY
38 ¦ }
39 }
80 ¦ self.vars_to_split = ["PACKAGE_INSTALL",
81 ¦ ¦ ¦ ¦ ¦ ¦ ¦ "TOOLCHAIN_HOST_TASK",
82 ¦ ¦ ¦ ¦ ¦ ¦ ¦ "TOOLCHAIN_TARGET_TASK"]
简单的说, 就是在SDK_DIR下创建manifest文件,分别写入TOOLCHAIN_HOST_TASK TOOLCHAIN_TARGET_TASK
的值。
看populate_sdk做了啥
408 def populate_sdk(d, manifest_dir=None):
409 env_bkp = os.environ.copy()
410
411 img_type = d.getVar('IMAGE_PKGTYPE')
412 if img_type == "rpm":
413 ¦ RpmSdk(d, manifest_dir).populate()
414 elif img_type == "ipk":
415 ¦ OpkgSdk(d, manifest_dir).populate()
416 elif img_type == "deb":
417 ¦ DpkgSdk(d, manifest_dir).populate()
418
419 os.environ.clear()
420 os.environ.update(env_bkp)
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'))
304 class DpkgSdk(Sdk):
305 def __init__(self, d, manifest_dir=None):
306 ¦ super(DpkgSdk, self).__init__(d, manifest_dir)
307
308 ¦ self.target_conf_dir = os.path.join(self.d.getVar("APTCONF_TARGET"), "apt")
309 ¦ self.host_conf_dir = os.path.join(self.d.getVar("APTCONF_TARGET"), "apt-sdk")
310
311 ¦ self.target_manifest = DpkgManifest(d, self.manifest_dir,
312 ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ Manifest.MANIFEST_TYPE_SDK_TARGET)
313 ¦ self.host_manifest = DpkgManifest(d, self.manifest_dir,
314 ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ Manifest.MANIFEST_TYPE_SDK_HOST)
315
316 ¦ deb_repo_workdir = "oe-sdk-repo"
317 ¦ if "sdk_ext" in d.getVar("BB_RUNTASK"):
318 ¦ ¦ deb_repo_workdir = "oe-sdk-ext-repo"
319
320 ¦ self.target_pm = DpkgPM(d, self.sdk_target_sysroot,
321 ¦ ¦ ¦ ¦ ¦ ¦ ¦ self.d.getVar("PACKAGE_ARCHS"),
322 ¦ ¦ ¦ ¦ ¦ ¦ ¦ self.d.getVar("DPKG_ARCH"),
323 ¦ ¦ ¦ ¦ ¦ ¦ ¦ self.target_conf_dir,
324 ¦ ¦ ¦ ¦ ¦ ¦ ¦ deb_repo_workdir=deb_repo_workdir)
325
326 ¦ self.host_pm = DpkgPM(d, self.sdk_host_sysroot,
327 ¦ ¦ ¦ ¦ ¦ ¦ ¦ self.d.getVar("SDK_PACKAGE_ARCHS"),
328 ¦ ¦ ¦ ¦ ¦ ¦ ¦ self.d.getVar("DEB_SDK_ARCH"),
329 ¦ ¦ ¦ ¦ ¦ ¦ ¦ self.host_conf_dir,
330 ¦ ¦ ¦ ¦ ¦ ¦ ¦ deb_repo_workdir=deb_repo_workdir)
339 def _populate_sysroot(self, pm, manifest):
340 ¦ pkgs_to_install = manifest.parse_initial_manifest()
341
342 ¦ pm.write_index()
343 ¦ pm.update()
344
345 ¦ for pkg_type in self.install_order:
346 ¦ ¦ if pkg_type in pkgs_to_install:
347 ¦ ¦ ¦ pm.install(pkgs_to_install[pkg_type],
348 ¦ ¦ ¦ ¦ ¦ ¦ [False, True][pkg_type == Manifest.PKG_TYPE_ATTEMPT_ONLY])
350 def _populate(self):
351 ¦ execute_pre_post_process(self.d, self.d.getVar("POPULATE_SDK_PRE_TARGET_COMMAND"))
352
353 ¦ bb.note("Installing TARGET packages")
354 ¦ self._populate_sysroot(self.target_pm, self.target_manifest)
355
356 ¦ self.target_pm.install_complementary(self.d.getVar('SDKIMAGE_INSTALL_COMPLEMENTARY'))
357
358 ¦ self.target_pm.run_intercepts(populate_sdk='target')
359
360 ¦ execute_pre_post_process(self.d, self.d.getVar("POPULATE_SDK_POST_TARGET_COMMAND"))
361
362 ¦ self._copy_apt_dir_to(os.path.join(self.sdk_target_sysroot, "etc", "apt"))
363
364 ¦ if not bb.utils.contains("SDKIMAGE_FEATURES", "package-management", True, False, self.d):
365 ¦ ¦ self.target_pm.remove_packaging_data()
366
367 ¦ bb.note("Installing NATIVESDK packages")
368 ¦ self._populate_sysroot(self.host_pm, self.host_manifest)
369 ¦ self.install_locales(self.host_pm)
370
371 ¦ self.host_pm.run_intercepts(populate_sdk='host')
372
373 ¦ execute_pre_post_process(self.d, self.d.getVar("POPULATE_SDK_POST_HOST_COMMAND"))
374
375 ¦ self._copy_apt_dir_to(os.path.join(self.sdk_output, self.sdk_native_path,
376 ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ "etc", "apt"))
377
378 ¦ if not bb.utils.contains("SDKIMAGE_FEATURES", "package-management", True, False, self.d):
379 ¦ ¦ self.host_pm.remove_packaging_data()
380
381 ¦ native_dpkg_state_dir = os.path.join(self.sdk_output, self.sdk_native_path,
382 ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦"var", "lib", "dpkg")
383 ¦ self.mkdirhier(native_dpkg_state_dir)
384 ¦ for f in glob.glob(os.path.join(self.sdk_output, "var", "lib", "dpkg", "*")):
385 ¦ ¦ self.movefile(f, native_dpkg_state_dir)
386 ¦ self.remove(os.path.join(self.sdk_output, "var"), True)
代码略微有些长,简单来说,就是创建2个PM——self.target_pm self.host_pm
,分别管理target_sysroot 和 host_sysroot,然后分别使用2个manifest,将manifest中记录的包安装进去。
需要安装的包看上面。
那么,这些被安装的包首先需要编译出来的,在哪编译的?
310 do_populate_sdk[depends] += "${@' '.join([x + ':do_populate_sysroot' for x in d.getVar('SDK_DEPENDS').split()])} ${@d.getVarFlag('do_rootfs', 'depends', False)}"
311 do_populate_sdk[rdepends] = "${@' '.join([x + ':do_package_write_${IMAGE_PKGTYPE} ' + x + ':do_packagedata' for x in d.getVar('SDK_RDEPENDS').split()])}"
48 SDK_RDEPENDS = "${TOOLCHAIN_TARGET_TASK} ${TOOLCHAIN_HOST_TASK}"
49 SDK_DEPENDS = "virtual/fakeroot-native xz-native cross-localedef-native nativesdk-qemuwrapper-cross ${@' '.join(["%s-qemuwrapper-cross" % m for m in d.getVar("MULTILIB_VARIANTS").split()])} qemuwrapper-cross"
这下完全清楚了。