入口lib/oe/rootfs.py
:: create_rootfs
377 def create_rootfs(d, manifest_dir=None, progress_reporter=None, logcatcher=None):
378 env_bkp = os.environ.copy()
379
380 img_type = d.getVar('IMAGE_PKGTYPE')
381
382 cls = get_class_for_type(img_type)
383 cls(d, manifest_dir, progress_reporter, logcatcher).create()
384 os.environ.clear()
385 os.environ.update(env_bkp)
根据IMAGE_PKGTYPE
生成对象,并调用create
方法。
367 def get_class_for_type(imgtype):
368 import importlib
369 mod = importlib.import_module('oe.package_manager.' + imgtype + '.rootfs')
370 return mod.PkgRootfs
目录结构lib/oe/package_manager/deb/rootfs.py
,同目录下还有ipk和rpm。这样可知,IMAGE_PKGTYPE
只有ipk、rpm和deb
。
上面返回的类是PkgRootfs
,看看继承关系:
class PkgRootfs(DpkgOpkgRootfs):
class DpkgOpkgRootfs(Rootfs):
class Rootfs(object, metaclass=ABCMeta):
上面调用的方法是create
方法,该方法组织了生成rootfs的整体逻辑流程,该方法在基类Rootfs
中:
187 def create(self):
188 ¦ bb.note("###### Generate rootfs #######")
189 ¦ pre_process_cmds = self.d.getVar("ROOTFS_PREPROCESS_COMMAND")
190 ¦ post_process_cmds = self.d.getVar("ROOTFS_POSTPROCESS_COMMAND")
191 ¦ rootfs_post_install_cmds = self.d.getVar('ROOTFS_POSTINSTALL_COMMAND')
192 # $WORKDIR/rootfs
193 ¦ bb.utils.mkdirhier(self.image_rootfs)
194 # $WORKDIR/deploy-core-image-minimal-image-complete
195 ¦ bb.utils.mkdirhier(self.deploydir)
196
197 ¦ execute_pre_post_process(self.d, pre_process_cmds)
202 ¦ # call the package manager dependent create method
203 ¦ self._create() #在子类中实现
#sysconfig = /etc
205 ¦ sysconfdir = self.image_rootfs + self.d.getVar('sysconfdir')
206 ¦ bb.utils.mkdirhier(sysconfdir)
#etc/version中写的是BUILDNAME这个变量的值 默认为空
207 ¦ with open(sysconfdir + "/version", "w+") as ver:
208 ¦ ¦ ver.write(self.d.getVar('BUILDNAME') + "\n")
210 ¦ execute_pre_post_process(self.d, rootfs_post_install_cmds)
211
212 ¦ self.pm.run_intercepts()
213 #一些IMAGE_FEATURE在通过POST_PROCESS_CMDS实现
214 ¦ execute_pre_post_process(self.d, post_process_cmds)
#USE_DEVFS默认为“1”
230 ¦ if self.d.getVar('USE_DEVFS') != "1":
231 ¦ ¦ self._create_devfs()
232
233 ¦ self._uninstall_unneeded()
234
238 ¦ self._insert_feed_uris()
239
240 ¦ self._run_ldconfig()
244
245 ¦ self._cleanup()
devfs相关
342 """
343 Create devfs:
344 * IMAGE_DEVICE_TABLE is the old name to an absolute path to a device table file
345 * IMAGE_DEVICE_TABLES is a new name for a file, or list of files, seached
346 ¦ for in the BBPATH
347 If neither are specified then the default name of files/device_table-minimal.txt
348 is searched for in the BBPATH (same as the old version.)
349 """ _create_devfs(self)
350 def _create_devfs(self):
351 ¦ devtable_list = []
352 ¦ devtable = self.d.getVar('IMAGE_DEVICE_TABLE')
353 ¦ if devtable is not None:
354 ¦ ¦ devtable_list.append(devtable)
355 ¦ else:
356 ¦ ¦ devtables = self.d.getVar('IMAGE_DEVICE_TABLES')
357 ¦ ¦ if devtables is None:
358 ¦ ¦ ¦ devtables = 'files/device_table-minimal.txt'
359 ¦ ¦ for devtable in devtables.split():
360 ¦ ¦ ¦ devtable_list.append("%s" % bb.utils.which(self.d.getVar('BBPATH'), devtable))
361
362 ¦ for devtable in devtable_list:
363 ¦ ¦ self._exec_shell_cmd(["makedevs", "-r",
364 ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ self.image_rootfs, "-D", devtable])
_uninstall_unneeded相关:
252 def _uninstall_unneeded(self):
253 ¦ # Remove the run-postinsts package if no delayed postinsts are found
254 ¦ delayed_postinsts = self._get_delayed_postinsts()
255 ¦ if delayed_postinsts is None:
256 ¦ ¦ if os.path.exists(self.d.expand("${IMAGE_ROOTFS}${sysconfdir}/init.d/run-postinsts")) or os.path.exists(self.d.expand("${IMAGE_ROOTFS}${systemd_system_unitdir}/run-postinsts.service")
257 ¦ ¦ ¦ self.pm.remove(["run-postinsts"])
258
259 ¦ image_rorfs = bb.utils.contains("IMAGE_FEATURES", "read-only-rootfs",
260 ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ True, False, self.d)
261 ¦ image_rorfs_force = self.d.getVar('FORCE_RO_REMOVE')
262
263 ¦ if image_rorfs or image_rorfs_force == "1":
264 ¦ ¦ # Remove components that we don't need if it's a read-only rootfs
265 ¦ ¦ unneeded_pkgs = self.d.getVar("ROOTFS_RO_UNNEEDED").split()
266 ¦ ¦ pkgs_installed = image_list_installed_packages(self.d)
267 ¦ ¦ # Make sure update-alternatives is removed last. This is
268 ¦ ¦ # because its database has to available while uninstalling
269 ¦ ¦ # other packages, allowing alternative symlinks of packages
270 ¦ ¦ # to be uninstalled or to be managed correctly otherwise.
271 ¦ ¦ provider = self.d.getVar("VIRTUAL-RUNTIME_update-alternatives")
272 ¦ ¦ pkgs_to_remove = sorted([pkg for pkg in pkgs_installed if pkg in unneeded_pkgs], key=lambda x: x == provider)
273
274 ¦ ¦ # update-alternatives provider is removed in its own remove()
275 ¦ ¦ # call because all package managers do not guarantee the packages
276 ¦ ¦ # are removed in the order they given in the list (which is
277 ¦ ¦ # passed to the command line). The sorting done earlier is
278 ¦ ¦ # utilized to implement the 2-stage removal.
279 ¦ ¦ if len(pkgs_to_remove) > 1:
280 ¦ ¦ ¦ self.pm.remove(pkgs_to_remove[:-1], False)
281 ¦ ¦ if len(pkgs_to_remove) > 0:
282 ¦ ¦ ¦ self.pm.remove([pkgs_to_remove[-1]], False)
283
284 ¦ if delayed_postinsts:
285 ¦ ¦ self._save_postinsts()
286 ¦ ¦ if image_rorfs:
287 ¦ ¦ ¦ bb.warn("There are post install scripts "
288 ¦ ¦ ¦ ¦ ¦ "in a read-only rootfs")
289
290 ¦ post_uninstall_cmds = self.d.getVar("ROOTFS_POSTUNINSTALL_COMMAND")
291 ¦ execute_pre_post_process(self.d, post_uninstall_cmds)
292
293 ¦ runtime_pkgmanage = bb.utils.contains("IMAGE_FEATURES", "package-management",
294 ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ True, False, self.d)
295 ¦ if not runtime_pkgmanage:
296 ¦ ¦ # Remove the package manager data files
297 ¦ ¦ self.pm.remove_packaging_data()
这段简单的说就是处理4种情况
- delayed_postinsts相关(删除或者不删除)
- 如果是read-only-rootfs或者read-only-rootfs-force,则删除ROOTFS_RO_UNNEEDED中定义的package。
- 执行
ROOTFS_POSTUNINSTALL_COMMAND
中的命令 - 删除
package_management
(如果IMAGE_FEATURES中没有package-management
)。
90 def _insert_feed_uris(self):
91 ¦ if bb.utils.contains("IMAGE_FEATURES", "package-management",
92 ¦ ¦ ¦ ¦ ¦ ¦True, False, self.d):
93 ¦ ¦ self.pm.insert_feeds_uris(self.d.getVar('PACKAGE_FEED_URIS') or "",
94 ¦ ¦ ¦ self.d.getVar('PACKAGE_FEED_BASE_PATHS') or "",
95 ¦ ¦ ¦ self.d.getVar('PACKAGE_FEED_ARCHS'))
PACKAGE_FEED_URI
这个概念应该是非常关键的。
def _run_ldconfig(self)
对与rootfs生成不关键。
98 """
99 The _cleanup() method should be used to clean-up stuff that we don't really
100 want to end up on target. For example, in the case of RPM, the DB locks.
101 The method is called, once, at the end of create() method.
102 """
103 @abs _cleanup(self)
104 def _cleanup(self):
105 ¦ pass
实现为虚,看到子类了再看。
大流程结束!!
_create的实现
123 class PkgRootfs(DpkgOpkgRootfs):
124 def __init__(self, d, manifest_dir, progress_reporter=None, logcatcher=None):
125 ¦ super(PkgRootfs, self).__init__(d, progress_reporter, logcatcher)
132 ¦ bb.utils.remove(self.image_rootfs, True)
133 ¦ bb.utils.remove(self.d.getVar('MULTILIB_TEMP_ROOTFS'), True)
134 ¦ self.manifest = PkgManifest(d, manifest_dir)
135 ¦ self.pm = DpkgPM(d, d.getVar('IMAGE_ROOTFS'),
136 ¦ ¦ ¦ ¦ ¦ ¦d.getVar('PACKAGE_ARCHS'),
137 ¦ ¦ ¦ ¦ ¦ ¦d.getVar('DPKG_ARCH'))
140 def _create(self):
141 ¦ pkgs_to_install = self.manifest.parse_initial_manifest()
144
145 ¦ alt_dir = self.d.expand("${IMAGE_ROOTFS}/var/lib/dpkg/alternatives")
146 ¦ bb.utils.mkdirhier(alt_dir)
147
148 ¦ # update PM index files
149 ¦ self.pm.write_index()
152
158 ¦ self.pm.update()
162
163 ¦ for pkg_type in self.install_order:
164 ¦ ¦ if pkg_type in pkgs_to_install:
165 ¦ ¦ ¦ self.pm.install(pkgs_to_install[pkg_type],
166 ¦ ¦ ¦ ¦ ¦ ¦ ¦ [False, True][pkg_type == Manifest.PKG_TYPE_ATTEMPT_ONLY])
167 ¦ ¦ ¦ self.pm.fix_broken_dependencies()
173
174 ¦ self.pm.install_complementary()
178
179 ¦ self._setup_dbg_rootfs(['/var/lib/dpkg'])
180
181 ¦ self.pm.fix_broken_dependencies()
182
183 ¦ self.pm.mark_packages("installed")
184
185 ¦ self.pm.run_pre_post_installs()
主要是2个对象:
self.manifest = PkgManifest
self.pm = DpkgPM(
manifest
的作用是得到需要安装的包列表 pkgs_to_install = self.manifest.parse_initial_manifest()
。
剩下基本就是pm的操作:
- self.pm.write_index()
- self.pm.update()
- self.pm.install(pkgs_to_install[pkg_type], [False, True][pkg_type == Manifest.PKG_TYPE_ATTEMPT_ONLY])
- self.pm.fix_broken_dependencies()
- self.pm.install_complementary()
- self.pm.mark_packages("installed")
- self.pm.run_pre_post_installs()
最后 _setup_dbg_rootfs(['/var/lib/dpkg'])
这个功能被 IMAGE_GEN_DEBUGFS
控制,默认为“0”,所以先不管。
DpkgPM
9 +-- 72 lines: class DpkgIndexer(Indexer):----------------------------------------------------------------------------------------------------------------------------------------------------------
81
82 +-- 16 lines: class PMPkgsList(PkgsList):----------------------------------------------------------------------------------------------------------------------------------------------------------
98
99 +-- 66 lines: class OpkgDpkgPM(PackageManager):----------------------------------------------------------------------------------------------------------------------------------------------------
165
166 +--338 lines: class DpkgPM(OpkgDpkgPM):-----------------
22 +-- 7 lines: def create_index(arg):---------------------------------------------------------------------------------------------------------------------------------------------------------------
29
30 +-- 60 lines: def opkg_query(cmd_output):----------------------------------------------------------------------------------------------------------------------------------------------------------
90
91 +-- 5 lines: def failed_postinsts_abort(pkgs, log_path):------------------------------------------------------------------------------------------------------------------------------------------
96
97 +-- 45 lines: def generate_locale_archive(d, rootfs, target_arch, localedir):----------------------------------------------------------------------------------------------------------------------
142
143 +-- 8 lines: class Indexer(object, metaclass=ABCMeta):--------------------------------------------------------------------------------------------------------------------------------------------
151
152 +-- 8 lines: class PkgsList(object, metaclass=ABCMeta):-------------------------------------------------------------------------------------------------------------------------------------------
160
161 +--287 lines: class PackageManager(object, metaclass=ABCMeta):-------------------------------------------------------------------------------------------------------------------------------------
448
449 +-- 82 lines: def create_packages_dir(d, subrepo_dir, deploydir, taskname, filterbydependencies):--------------------------------------------------------------------------------------------------
531
532
533 +-- 24 lines: def generate_index_files(d):----------------------------------------------------------
大体结构和继承关系。
def create_packages_dir(d, subrepo_dir, deploydir, taskname, filterbydependencies):
这个方法比较复杂,主要是里面的数据结构比较麻烦。
代码逻辑大致明白,结合着加log的方法,弄明白了这个方法到底完成了什么。
首先,传入的参数
deploydir
指向一个目录,该目录中存放了编译好的package;当前例子中该目录的值为/home/zhangsong/work/about_yocto/build_dir/build6/tmp/deploy/deb
subrepo_dir
指向一个目录,该目录构建了一个本地库(apt库);但是这个方法并未创建仓库,而是将仓库中所有的deb都方进来。当前例子中该目录的值为/home/zhangsong/work/about_yocto/build_dir/build6/tmp/work/raspberrypi4_64-poky-linux/core-image-minimal/1.0-r0/oe-rootfs-repo
然后:这个方法是被do_rootfs
调用的(简单的这么说),后续的逻辑简单的描述就是——do_rootfs
所依赖的包(包含do_package_write_deb
的recipe)编译打包产生的deb,都放在subrepo_dir
中。效果如下:
zhangsong@zhangsong-ThinkPad-W541:~/work/about_yocto/build_dir/build6/tmp/work/raspberrypi4_64-poky-linux/core-image-minimal/1.0-r0/oe-rootfs-repo$ tree all/
all/
├── autoconf-archive_2021.02.19-r0_all.deb
├── autoconf-archive-doc_2021.02.19-r0_all.deb
├── ca-certificates_20211016-r0_all.deb
├── ca-certificates-dbg_20211016-r0_all.deb
├── ca-certificates-dev_20211016-r0_all.deb
├── ca-certificates-doc_20211016-r0_all.deb
├── Packages
├── Packages.gz
├── Release
├── run-postinsts_1.0-r10_all.deb
├── run-postinsts-dbg_1.0-r10_all.deb
├── run-postinsts-dev_1.0-r10_all.deb
├── tzdata_2021e-r0_all.deb
├── tzdata-africa_2021e-r0_all.deb
├── tzdata-americas_2021e-r0_all.deb
├── tzdata-antarctica_2021e-r0_all.deb
├── tzdata-arctic_2021e-r0_all.deb
├── tzdata-asia_2021e-r0_all.deb
├── tzdata-atlantic_2021e-r0_all.deb
├── tzdata-australia_2021e-r0_all.deb
├── tzdata-core_2021e-r0_all.deb
├── tzdata-europe_2021e-r0_all.deb
├── tzdata-misc_2021e-r0_all.deb
├── tzdata-pacific_2021e-r0_all.deb
├── tzdata-posix_2021e-r0_all.deb
├── tzdata-right_2021e-r0_all.deb
├── update-rc.d_0.8-r0_all.deb
├── update-rc.d-dbg_0.8-r0_all.deb
└── update-rc.d-dev_0.8-r0_all.deb
这是其中一个目录,每个目录是一个arch
。