使用 Jenkins 的嵌入式 Linux 开发模型

Embedded Linux Develoment Model with Jenkins

提问人:PhilBot 提问时间:6/22/2012 更新时间:6/25/2012 访问量:4942

问:

我是一个小型团队(4 - 5 人)的一员,从事嵌入式 linux 项目。我们正在使用 Buildroot 和 Linaro 工具链来构建我们的目标。我们使用 git 进行版本控制,使用 Jenkins 进行夜间构建。

这是我们第一次尝试这样的项目,我一直没有找到任何描述这种环境开发模型的资源。

现在,在每晚构建之后,我创建了一个 Buildroot 'output' 目录的压缩包,其中包含 u-boot 映像和根文件系统。这可以直接从 Jenkins 的“存档”页面下载,以获取上次成功的构建。

我们中的一些人将从事较低级别的开发,一些人将从事用户空间开发(QT)。我们的问题是决定在这样的环境中开发最有效/最简化的方法,因为人们将在项目范围内的不同领域工作。用户空间的家伙们可以下载包含所有内容的压缩包,并将他们的应用程序合并到 rfs 中以在板上运行和调试,但是我们应该如何处理在较低级别的开发中完成的工作?基本上,我们应该如何将工件分发给团队?我非常感谢任何想法。

Linux 构建 嵌入式 持续集成 Jenkins

评论


答:

19赞 Ben 6/25/2012 #1

我最近花了一些时间为一个基于 OpenEmbedded 的 linux 项目重组构建环境。我对 Buildroot 没有直接经验,但我希望 OpenEmbedded 与您正在使用的足够相似。我将描述我的设置,如果幸运的话,您会在这里找到一些有用的东西......

问题

有三个软件组件可以单独安装(即彼此独立):引导加载程序(u-boot);内核 (Linux);和文件系统映像。我们的最终产品随附这三个组件的打包版本。也就是说,已经过 QA 测试并已知可以协同工作的 u-boot、linux 和文件系统映像版本。但是,可以独立升级任何一个组件(例如安装新的内核映像),以创建尚未一起测试的软件组件的组合。

用户空间应用程序也存在此问题。将文件系统映像安装到目标中后,可以独立于其他文件系统对象更新一个或多个用户空间二进制文件(假设您的文件系统不是只读的)。您如何知道现在安装的用户空间应用程序的特定组合可以协同工作?如何确定在此特定单元中运行的二进制文件的组合是否与经过 QA 认证的二进制文件的组合相同?我如何知道软件的“版本”是什么?

我需要解决的另一个问题,与您在问题中概述的问题相同,是如何允许在软件堆栈的不同部分(内核、根文件系统、用户空间 Qt 应用程序等)上工作的开发人员一起工作?

解决方案

我通过以下方式解决了这个问题和“版本”问题:

  1. 将 rootfs 和 sysroot 存储在 git 存储库中。
  2. 自由使用 git 子模块。

将目标的根文件系统和系统根文件存储在 git 存储库中最初以错误的方式摩擦我(将输出文件存储在版本控制中,什么?!),但它提供了以下优点:

  1. 只要构建用户空间应用程序所需的时间(即几十秒),就可以内置 JFFS2 文件系统映像(rootfs + 我们的自定义用户空间应用程序)。开发人员不再需要首先从头开始构建 rootfs(使用 OpenEmbedded 需要几个小时)。
  2. 版本控制的所有其他优点(随着时间的推移可以很容易地跟踪对 rootfs 的更改、发布标签、分支等)。
  3. 我最初考虑将 rootfs 和 sysroot 存储为 tarball,但我喜欢 git 在每个文件的基础上跟踪更改的想法。

目录结构如下所示(为了保护无辜者,一些名称已更改):

\---proj [*]             # Name of your project
    +---u-boot [*]
    +---linux [*]
    +---toolchain [*]
    \---fs [*]           # Filesystem stuff.
        +---oe [*]       # OpenEmbedded.
        +---qt [*]       # Qt framework.
        +---apps [*]     # Custom user-space applications.
        \---bin [*]      # Revision controlled binaries
            +---rootfs   # Target root filesystem, output of OpenEmbedded.
            \---sysroot  # System root, output of OpenEmbedded (headers, etc).

每个加星标的目录 [*] 都是一个 git 仓库,每个 git 仓库都是其父级的一个子模块。

构建环境是从顶级 Makefile 初始化的,它本质上是递归的 和 .所有开发人员都会这样做:git submodule initgit submodule update

$ git clone [email protected]:proj proj
$ cd proj
$ make git-init

然后,用户空间开发人员可以立即构建:

$ make --directory proj/fs/apps all       # Build apps
$ make --directory proj/fs install        # Create JFFS2 image

文件系统维护者可以更新 rootfs:

$ cd proj/fs/oe
$ # Modify build recipes and other OpenEmbedded black magic stuff.
$ make
$ # Go make coffee while oe builds every package on the planet.
$ cd proj/bin    # OE writes output files here.
$ git commit     # Commit latest rootfs and sysroot.

软件版本控制

从顶级 makefile () 可以构建所有软件组件(内核、u-boot、文件系统映像)。使用以下 git 命令,makefile 将描述当前软件版本的单个环境变量(例如)导出到所有子 make 进程。版本要么是来自 git 存储库的标签,要么是 SHA(例如 ,或 )。proj/MakefileVER_TAGv1.0471087ec254e8e353bb46c533823fc4ece3485b4471087ec254e8e353bb46c533823fc4ece3485b4-modified

git rev-parse HEAD                 # Get current SHA
git status --porcelain | wc -c     # Is working copy modified?
git describe --exact-match HEAD    # Is the working copy a tag?

如果任何项目子目录中的单个文件已被修改,则始终是 。然后,这个单一变量作为编译时常量传递给所有构建(u-boot、内核、用户空间应用程序等)。VER_TAGxxxx-modifiedVER_TAG

在运行时,自定义用户空间应用程序会累积所有组件的值,如果它们都报告相同的值,则该字符串将成为产品报告的正式版本。如果即使一个值与其他值不同,那么软件堆栈就不是从相同的顶级 SHA 构建的,并且不能发布到野外(用于测试的 QA、用于制造的生产等)。VER_TAGVER_TAG

如果软件组件不是从顶级生成文件(例如)构建的,那么该组件将是未定义的,并且生成的软件堆栈仅供“内部使用”。也就是说,所有软件组件的“发布”只能通过从顶级 makefile 构建来实现。make --directory proj/fs/apps allVER_TAG

作为参考,linux 通过 procfs 中的自定义文件进行报告,u-boot 通过 linux 命令行 () 报告,每个用户空间应用程序通过进程间通信进行报告。VER_TAG/proc/cmdline

总结

一个警告。我一个月前才开发了这个构建环境,所以不能声称它的健壮性,但现在它似乎保持在一起......

如果您有具体问题或要点想要澄清,我很乐意更新我的答案。

评论

0赞 PhilBot 6/26/2012
感谢您的详细回答。其中很多都很有意义,我可能会用 Buildroot 做类似的事情。
1赞 Alan Mimms 5/15/2018
这么多年后,您还会推荐这个解决方案吗?