rootfs生成过程详细分析

入口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个对象:

  1. self.manifest = PkgManifest
  2. self.pm = DpkgPM(

manifest的作用是得到需要安装的包列表 pkgs_to_install = self.manifest.parse_initial_manifest()

剩下基本就是pm的操作:

  1. self.pm.write_index()
  2. self.pm.update()
  3. self.pm.install(pkgs_to_install[pkg_type], [False, True][pkg_type == Manifest.PKG_TYPE_ATTEMPT_ONLY])
  4. self.pm.fix_broken_dependencies()
  5. self.pm.install_complementary()
  6. self.pm.mark_packages("installed")
  7. 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的方法,弄明白了这个方法到底完成了什么。

首先,传入的参数

  1. deploydir指向一个目录,该目录中存放了编译好的package;当前例子中该目录的值为/home/zhangsong/work/about_yocto/build_dir/build6/tmp/deploy/deb
  2. 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


换个思路写

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,284评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,115评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,614评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,671评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,699评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,562评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,309评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,223评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,668评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,859评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,981评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,705评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,310评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,904评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,023评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,146评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,933评论 2 355

推荐阅读更多精彩内容