zeerd's blog         Search     Categories     Tags     Feed

闲来生雅趣,无事乐逍遥。对窗相望雪,一盏茶香飘。

通过Yocto整理工程依赖关系与授权信息

#License #Yocto @SystemIntegration


Contents:

如果需要知道Yocto生成的images里面的软件包的依赖关系及授权信息,则可以通过Yocto自身的两个功能来实现。

以Yocto默认的core-image-minimal为例。

每一次使用Yocto生成Image,都会默认生成一份License列表,保存的位置如下():

user@debian:~/yocto/build$ ls tmp/deploy/licenses/core-image-minimal-${machine}-${datetime}/license.manifest

而使用“-g”参数可以获取到软件包依赖结果:

user@debian:~/yocto/build$ bitbake -g core-image-minimal
Loading cache: 100% |#############################################################| ETA:  00:00:00
Loaded 5171 entries from dependency cache.
NOTE: Resolving any missing task queue dependencies
NOTE: Preparing RunQueue
NOTE: PN build list saved to 'pn-buildlist'
NOTE: PN dependencies saved to 'pn-depends.dot'
NOTE: Package dependencies saved to 'package-depends.dot'
NOTE: Task dependencies saved to 'task-depends.dot'

其中的“package-depends.dot”即为软件包依赖关系。

接下来,可以使用如下脚本(dep.py)对这两个文件进行收集整理,生成基于FreeMind的依赖关系图。


#!/usr/bin/python
# -*- coding: utf-8 -*-

import sqlite3, os, sys

root = sys.argv[1]
dpfile = sys.argv[2]
licfile = sys.argv[3]

searched = {}
licenses = {}

db = sqlite3.connect(":memory:")

def dict_factory(cursor, row):
    d = {}
    for idx, col in enumerate(cursor.description):
        d[col[0]] = row[idx]
    return d

db.row_factory = dict_factory

cu = db.cursor()
cu.execute("\
    create table if not exists depends \
    ( \
        id INTEGER PRIMARY KEY ASC, \
        project TEXT, \
        depend TEXT\
    )")

def make_db():
    cu = db.cursor()
    for line in open(dpfile):
        line=line.strip('\n')

        if line.find(" -> ") >= 0:
            aline = line.split(' ')
            if len(aline) >= 3:
                project = aline[0].replace("\"", "")
                depend = aline[2].replace("\"", "")
                if aline[1] == "->":
                    cu.execute("\
                        select * from depends \
                        where \
                            project='%s' and depend='%s'" % (project, depend))
                    f = cu.fetchone()
                    if not f:
                        cu.execute("\
                            insert into depends \
                            values (NULL, '%s', '%s')" % (project, depend))

def show_depends(db, proj, depelvel):

    searched[proj] = proj

    if depelvel == 1:
        output.write("<map version=\"1.0.1\">\n")
        output.write("<node \
                          COLOR=\"#000000\" \
                          CREATED=\"1498714017621\" \
                          ID=\"ID_1\" \
                          MODIFIED=\"1498714017621\" \
                          TEXT=\""+proj+"\">\n")
        output.write("<icon BUILTIN=\"list\"/>\n")

    depelvel = depelvel + 1

    cu = db.cursor()
    cu.execute("select d.* from depends as d \
                  where d.project='"+proj+"' order by d.depend")
    for row in cu:
        output.write("<node \
                          COLOR=\"#000000\" \
                          CREATED=\"1498714017621\" \
                          FOLDED=\"true\" \
                          ID=\"ID_1\" \
                          MODIFIED=\"1498714017621\" \
                          STYLE=\"bubble\">\n")
        if depelvel <= 10:
            if depelvel-1 == 1:
                output.write("<cloud/>\n");
            output.write("<icon BUILTIN=\"full-"+str(depelvel-1)+"\"/>\n");
        else:
            output.write("<icon BUILTIN=\"freemind_butterfly\"/>\n");
        output.write("<richcontent TYPE=\"NODE\">")
        output.write("<html><head></head><body width=\"\">")

        output.write(row['depend'])

        if row['depend'] in licenses:
            output.write("<hr/>")
            output.write(licenses[row['depend']])

        output.write("</body></html>")
        output.write("</richcontent>\n")

        if not row['depend'] in searched:
            show_depends(db, row['depend'], depelvel)

        output.write("</node>\n")

    depelvel = depelvel - 1

    if depelvel == 1:
        output.write("</node>\n")
        output.write("</map>\n")

def load_licenses():
    for line in open(licfile):
        line=line.strip('\n')
        aline = line.split(' ')

        if line.find("RECIPE NAME: ") >= 0:
            recipe = aline[2]
        if line.find("LICENSE: ") >= 0:
            licenses[recipe] = line.replace("LICENSE: ", "")

load_licenses()

make_db()

output = open(root+".mm", 'w')
show_depends(db, root, 1)
output.close()

db.close()

使用方法:

user@debian:~/yocto/build$ ./dep.py core-image-minimal package-depends.dot tmp/deploy/licenses/core-image-minimal-${machine}-${datetime}/license.manifest

等待片刻,就会生成一个名为“core-image-minimal.mm”的文件,使用FreeMind打开,即可以看到附带授权信息的软件包依赖关系图。

后记:

以上方法还存在一个缺陷,即“package-depends.dot”中的依赖关系是基于Yocto中的“PREFERRED_PROVIDER”设定的,而“license.manifest”不是。所以部分软件包到License的对应关系会缺失。如果需要等到更加完整的关系图,则还需要整理一下“PREFERRED_PROVIDER”对照关系。