翻译: buildroot 用户手册 (更新中...)

Buildroot 用户手册


Table of Contents

I. Getting started
1. About Buildroot
2. System requirements
2.1. Mandatory packages
2.2. Optional packages
3. Getting Buildroot
4. Buildroot quick start
5. Community resources
II. User guide
6. Buildroot configuration
6.1. Cross-compilation toolchain
6.2. /dev management
6.3. init system
7. Configuration of other components
8. General Buildroot usage
8.1. make tips
8.2. Understanding when a full rebuild is necessary
8.3. Understanding how to rebuild packages
8.4. Offline builds
8.5. Building out-of-tree
8.6. Environment variables
8.7. Dealing efficiently with filesystem images
8.8. Details about packages
8.9. Graphing the dependencies between packages
8.10. Graphing the build duration
8.11. Graphing the filesystem size contribution of packages
8.12. Top-level parallel build
8.13. Integration with Eclipse
8.14. Advanced usage
9. Project-specific customization
9.1. Recommended directory structure
9.2. Keeping customizations outside of Buildroot
9.3. Storing the Buildroot configuration
9.4. Storing the configuration of other components
9.5. Customizing the generated target filesystem
9.6. Adding custom user accounts
9.7. Customization after the images have been created
9.8. Adding project-specific patches
9.9. Adding project-specific packages
9.10. Quick guide to storing your project-specific customizations
10. Using SELinux in Buildroot
10.1. Enabling SELinux support
10.2. SELinux policy tweaking
11. Frequently Asked Questions & Troubleshooting
11.1. The boot hangs after Starting network…
11.2. Why is there no compiler on the target?
11.3. Why are there no development files on the target?
11.4. Why is there no documentation on the target?
11.5. Why are some packages not visible in the Buildroot config menu?
11.6. Why not use the target directory as a chroot directory?
11.7. Why doesn’t Buildroot generate binary packages (.deb, .ipkg…)?
11.8. How to speed-up the build process?
12. Known issues
13. Legal notice and licensing
13.1. Complying with open source licenses
13.2. Complying with the Buildroot license
14. Beyond Buildroot
14.1. Boot the generated images
14.2. Chroot
III. Developer guide
15. How Buildroot works
16. Coding style
16.1. Config.in file
16.2. The .mk file
16.3. The documentation
16.4. Support scripts
17. Adding support for a particular board
18. Adding new packages to Buildroot
18.1. Package directory
18.2. Config files
18.3. The .mk file
18.4. The .hash file
18.5. Infrastructure for packages with specific build systems
18.6. Infrastructure for autotools-based packages
18.7. Infrastructure for CMake-based packages
18.8. Infrastructure for Python packages
18.9. Infrastructure for LuaRocks-based packages
18.10. Infrastructure for Perl/CPAN packages
18.11. Infrastructure for virtual packages
18.12. Infrastructure for packages using kconfig for configuration files
18.13. Infrastructure for rebar-based packages
18.14. Infrastructure for Waf-based packages
18.15. Infrastructure for Meson-based packages
18.16. Integration of Cargo-based packages
18.17. Infrastructure for Go packages
18.18. Infrastructure for QMake-based packages
18.19. Infrastructure for packages building kernel modules
18.20. Infrastructure for asciidoc documents
18.21. Infrastructure specific to the Linux kernel package
18.22. Hooks available in the various build steps
18.23. Gettext integration and interaction with packages
18.24. Tips and tricks
18.25. Conclusion
19. Patching a package
19.1. Providing patches
19.2. How patches are applied
19.3. Format and licensing of the package patches
19.4. Integrating patches found on the Web
20. Download infrastructure
21. Debugging Buildroot
22. Contributing to Buildroot
22.1. Reproducing, analyzing and fixing bugs
22.2. Analyzing and fixing autobuild failures
22.3. Reviewing and testing patches
22.4. Work on items from the TODO list
22.5. Submitting patches
22.6. Reporting issues/bugs or getting help
22.7. Using the run-tests framework
23. DEVELOPERS file and get-developers
24. Release Engineering
24.1. Releases
24.2. Development
IV. Appendix
25. Makedev syntax documentation
26. Makeusers syntax documentation
27. Migrating from older Buildroot versions
27.1. Migrating to 2016.11
27.2. Migrating to 2017.08
 

Buildroot 2021.02.3 manual generated on 2021-06-12 15:00:38 UTC from git revision 5293208a57

Buildroot 手册是由 Buildroot 得开发者编写,遵从 GNU General Public License, version 2. 请参考: license 查看 license 全文。

Copyright © 2004-2020 The Buildroot developers

logo.png

Part I. Getting started

Chapter 1. About Buildroot

Buildroot 是一个利用交叉编译和自动化技术,简化 Linux 系统或者嵌入式系统编译的工具。

为了做到这一点, Buildroot 能够为您的目标生成交叉编译工具链、根文件系统、Linux 内核 image 和引导加载程序。 Buildroot 可独立用于这些选项的任意组合(例如,您可以使用现有的交叉编译工具链,并仅使用 Buildroot 构建您的根文件系统)。

Buildroot 主要对使用嵌入式系统的人有用。 嵌入式系统通常使用的处理器不是每个人都习惯在他的 PC 中使用的常规 x86 处理器(也可以是 PowerPC 处理器、MIPS 处理器、ARM 处理器等)。

Buildroot 支持多种处理器及其变体; 此外它还带有几个现成可用的默认板级配置。 除此之外,还有许多第三方项目基于 Buildroot 或开发他们 BSP, [1] or SDK [2]



[1] BSP: Board Support Package

[2] SDK: Software Development Kit

Chapter 2. System requirements

Buildroot 目前被设计为仅能运行再 Linux 上。

虽然 Buildroot 本身会构建编译所需的大多数主机包,但预计某些标准 Linux 实用程序已经安装在主机系统上。 下面你将看到 HOST 端 MUST 和 OPTION 安装的应用。 (请注意,再不同的发行版本上可能软件包名存在差别)

2.1. Mandatory packages

  • 编译/构建工具:

    • which
    • sed
    • make (version 3.81 or any later)
    • binutils
    • build-essential (only for Debian based systems)
    • gcc (version 4.8 or any later)
    • g++ (version 4.8 or any later)
    • bash
    • patch
    • gzip
    • bzip2
    • perl (version 5.8.7 or any later)
    • tar
    • cpio
    • unzip
    • rsync
    • file (must be in /usr/bin/file)
    • bc
  • 源代码拉取工具:

    • wget

2.2. Optional packages

  • 推荐安装:

    Buildroot中的一些特性或实用程序(如legal info或图形生成工具)具有附加的依赖关系。 尽管对于简单的构建来说它们不是必需的,但是仍然强烈建议使用它们

    • python (version 2.7 or any later)
  • Configuration interface dependencies:

    对于这些库,您需要同时安装运行时和开发数据,这在许多发行版中是分开打包的。 开发包通常有一个 -dev 或者 -devel 的后缀。

    • ncurses5 用于配置 menuconfig 接口
    • qt5 用于配置 xconfig 接口
    • glib2, gtk2 and glade2 用于配置 gconfig 接口
  • 源(代码)获取工具:

    再 offical 发布中,大多数 package 都是用 wget ftp, http or https 获取. 少数软件包只能通过版本控制系统获得。此外,Buildroot 还可以通过其他工具下载源代码, 比如: rsync / scp (参考:Chapter 20, Download infrastructure 获取更多信息). 如果使用上面那些方法获取 package,则需要在主机系统上安装相应的工具:

    • bazaar
    • cvs
    • git
    • mercurial
    • rsync
    • scp
    • subversion
  • 与 java 相关, 如果需要为目标系统构建 Java Classpath:

    • The javac compiler
    • The jar tool
  • 文档生成相关:

    • asciidoc, version 8.6.3 or higher
    • w3m
    • python with the argparse module (automatically present in 2.7+ and 3.2+)
    • dblatex (required for the pdf manual only)
  • 图像生成相关工具:

    • graphviz to use graph-depends and <pkg>-graph-depends
    • python-matplotlib to use graph-build

Chapter 3. Getting Buildroot

Buildroot 每隔四个月释放一个版本,二月,五月,八月, 十一月。 Release 版本号的格式为 YYY.MM,比如说:2013.02, 2014.08。

获取 tarball 请访问: http://buildroot.org/downloads/.

为方便起见,Buildroot 源代码树中的 support/misc/Vagrantfile 提供了一个 Vagrantfile, 用于快速设置具有所需依赖项的虚拟机。

如果要在 Linux 或 Mac Os X 上设置独立的 buildroot 环境,请将此行粘贴到终端上:

curl -O https://buildroot.org/downloads/Vagrantfile; vagrant up

如果您在 Windows 上,请将此粘贴到 powershell 中:

(new-object System.Net.WebClient).DownloadFile("https://buildroot.org/downloads/Vagrantfile","Vagrantfile"); vagrant up

如果您想跟踪开发,您可以使用 daily snapshots 或克隆 Git 存储库。参考获取更多信息: Download page

Chapter 4. Buildroot quick start

Important : 你能,而且你也应该 用 nornal user 去 build 你的工程。 There 无需成为 root 用户即可配置和使用 Buildroot。 通过以普通用户身份运行所有命令, 您可以保护系统免受编译和安装过程中出现不良软件包的行为所影响。

使用 buildroot 的第一步是要创建一个配置文件。 Buildroot 有一个非常好的配置工具(你可以在 Linux kernel 或者 BusyBox 这中看到该工具)。

在 buildroot 工程目录,运行

 $ make menuconfig

可以基于最原始的配置来进行配置, 或者运行

 $ make nconfig

创建一个新的配置, 或者运行

 $ make xconfig

创建一个基于 Qt-based 的配置。 或者运行

 $ make gconfig

创建一个 GTK-based 的配置。

所有这些 “make” 命令都需要构建一个配置实用程序(包括接口), 因此您可能需要为配置的实用程序,同时配置其他相关的库安装 “开发”(依赖) 包。 参考 Chapter 2, System requirements 获取更多信息, 尤其是 optional requirements 列举了一些可能与你目标相关的依赖。

对于配置工具菜单中的每个条目,您都可以找到描述条目用途相关的帮助。 参考 Chapter 6, Buildroot configuration 获取更多关于配置方面的一些说明。

一旦配置完成之后,配置工具会生成一个 .config 文件,该文件包含所有的配置, 并且该文件在 build 的时候被顶层的 Makefile 所加载(引用)。

开始 build,只需运行

 $ make

通常情况下,Buildroot 并不支持 top-level 并行建构( build), 所以即便运行 make -jN 也是没用的(无意义的)。 但这里有个实验性质的,支持 top-level 并行建构的版本,参考 Section 8.12, “Top-level parallel build”.

make 执行后,通常情况下会经过一下步骤:

  • 下载依赖源文件(required);
  • 配置,构建和安装 cross-compilation toolchain 或者导入外部 toolchain;
  • 配置 / 构建 / 安装 被配置(选择)的安装包:
  • 构建内核 image (image)(如果选择了的话);
  • 构建 bootloader image (image)(如果选择了的话);
  • 根据配置文件系统格式,创建根文件系统;

Buildroot 的输出被存储在 output/ 目录. Buildroot 会在该目录为每一个目标板级(board)生成一个子目录。

  • images/ 目录存放所有编译出来的 image (包括 kernel image, bootloader and root filesystem images) 这些 image 即使你需要保存(烧录 / 烧写 / 安装)到你的目标系统中的。
  • build/ 目录存放所有构建组件的地方 (这包括主机上 Buildroot 所需的工具和为目标编译的包)。 每一个组件,在该目录中都有一个属于自己的子目录。
  • host/ 目录包含为主机构建的工具和目标 toolchain 的 sysroot。 前者是为主机编译的工具的安装,这些工具是正确执行 Buildroot 所需的,包括交叉编译工具链。 后者是类似于根文件系统层次结构的层次结构。 它包含所有用户空间包的头文件和库,这些包提供和安装其他包使用的库。 然而,这个目录并 不是 目标的根文件系统: 它包含很多 development files, unstripped binaries 和 libraries,这些文件太大了,一般对于嵌入式系统承受不了(也不需要)。 这些 development files 主要用于在建构时充当其他库和应用程序的的依赖。
  • staging/ 是一个 symlink, 链接到 target toolchain 的 sysroot, host/ 目录则为了向后兼容而存在的。(待完善)
  • target/ 目录包含 几乎 目标板级的完整 rootfs 文件系统: 除了 dev / sys / proc ... 等由系统生成的文件外。 (Buildroot 无法创建它们,因为 Buildroot 不以 root 身份运行,也不想以 root 身份运行)。 此外,它没有正确的权限(例如,busybox 二进制文件的 setuid)。 所以这个目录中的文件 并不应该直接应用到你的系统中 . 相反,你应该用生成在 images/ 目录中的 image . 如果你想用 NFS 的方式 boot 你的系统,你应该以 root 用户的身份解压 images/ 目录中 tarball image。 与 staging/ 相比, target/ 仅包含运行所选目标应用程序所需的文件和库: 开发文件(头文件等)不存在,二进制文件被剥离。

make menuconfig|nconfig|gconfig|xconfigmake 这些命令参数, 是最基本的,让你简单和快速编译所有配置特性和应用,生成 images 的方法。

更多关于 make 命令参数的使用方法,请参考 Section 8.1, “ make tips”.

Chapter 5. Community resources

与其他开源项目一样,Buildroot 有着不同的方式在其社区内外共享信息。

如果你正在寻求帮助,或者想要为 buildroot 做贡献, 下面是一些可取的途径:

Mailing List

Buildroot 有一个用于讨论和开发的邮件列表。 它是 Buildroot 用户和开发人员的主要交互方式。

只有订阅了 Buildroot mailing list 的人才能够像该 mailing list post 邮件, 你可以访问 mailing list info page 进行订阅。

你也可以将邮件发送到 gmane.comp.lib.uclibc.buildroot 托管的mailing list archives, 打包在提交之前,请先搜索一下你的提交,因为有可能已经有人 post 相关问题了。

IRC

Buildroot 的 IRC channel #buildroot 托管在 OFTC. 在这里能方便的交流一些已知的问题和做一些讨论。

当在 IRC channel 里面询问问题 / 分享日志或者代码的时候,请使用 code sharing website, 比如 http://code.bulix.org.

请注意,对于某些问题,发布到 mailing list 可能会更好,因为它可以覆盖更多人,包括开发人员和用户。

Bug tracker
Bugs 可以通过 mailing list 来提交, 或者通过 Buildroot bugtracker. 请在提交 BUG 前先阅读 Section 22.6, “Reporting issues/bugs or getting help” 中的内容
Wiki
Buildroot wiki page
被托管于
eLinux
wiki. 它包含一些有用的链接、过去和即将发生的事件的概述以及待办事项列表。
Patchwork

Patchwork 是一个基于 Web 的补丁跟踪系统,旨在促进对开源项目的贡献和管理。 已发送到邮件列表的补丁被系统 “捕获”,并显示在网页上。 任何引用补丁的评论也会附加到补丁页面。 有关 Patchwork 的更多信息,请参阅 http://jk.ozlabs.org/projects/patchwork/.

Buildroot 的 Patchwork 网站主要供 Buildroot 的维护者使用,以确保不会错过补丁。 当然也被 Buildroot 补丁审查者使用 (参考 Section 22.3.1, “Applying Patches from Patchwork”). 但是,自从该网站将补丁及其相应的评论评论公开到干净简洁的 Web 界面中, 它对所有 Buildroot 开发人员也都变得非常有用。

Buildroot patch management 的接口在 http://patchwork.buildroot.org.

Part II. User guide

Chapter 6. Buildroot configuration

所有 make *config 中的配置选项都有详细的 help 信息。

同时 make *config 还提供了一个搜索工具。 阅读各个选项的前端菜单中的帮助信息以了解如何使用它:

  • menuconfig, 可以输入键盘上的 / 开始搜索你想要的信息;
  • xconfig , 即可以在键盘上输入 Ctrl + f 开始搜索你想要的信息;

menuconfig 中使用搜索工具搜索到结果时, 结果的左方都会出现与搜索结果关联的数字, 直接输入数字,即可跳转到相应的选项位置。 或者你也可以按照帮助信息从选项表中一步一步找到你的目标选项, 从而避免错过依赖关系。

虽然条目的菜单结构和帮助文本应该是做到能自我解释, 但还是有许多 topics 在帮助文本中不容易涵盖,需要额外的解释,因此在以下部分中涵盖。

6.1. Cross-compilation toolchain

编译工具链是一组工具,允许您为系统编译代码。 它由一个编译器(在我们的例子中,gcc), 二进制工具如汇编器和链接器(在我们的例子中,binutils)组成和一个 C 标准库 GNU Libc, uClibc-ng).

你的系统如果安装了开发环境,那么系统就已经有一个编译工具链, 您可以使用它来编译在您的系统上运行的应用程序。 如果您使用的是 PC,则您的编译工具链在 x86 处理器上运行并为 x86 处理器生成代码。 在大多数 Linux 系统下,编译工具链使用 GNU libc(glibc)作为 C 标准库。 这个编译工具链被称为 “host compilation toolchain”, 而你工作的系统则叫 “host system”。 [3].

编译工具链由你的 distribution 提供, Buildroot 与它无关(除了用它来构建交叉编译工具链和其他运行在开发主机上的工具)。

如上所述,系统附带的编译工具链是用来编译运行在你 host 机器上的程序的。 但由于您的嵌入式系统具有不同的处理器,因此您需要一个交叉编译工具链 -- 一个在您的 host system 上运行但为您的 target system 生成代码的 compilation toolchain。 例如,如果您的主机系统使用 x86,而您的目标系统使用 ARM,则您主机上的常规编译工具链在 x86 上运行并为 x86 生成代码,而交叉编译工具链在 x86 上运行并为 ARM 生成代码。

Buildroot 为交叉编译工具链提供了两种解决方案:

  • internal toolchain backend, 在 configuration interface 被称为 Buildroot toolchain
  • external toolchain backend, 在 configuration interface 被称为 External toolchain

Toolchain 的菜单中 Toolchain Type 选项可以选择使用哪种。 选择一个解决方案后,会出现许多额外的配置选项,以下部分将详细介绍这些选项。

6.1.1. Internal toolchain backend

internal toolchain backend 是 Buildroot 构建你目标系统的应用或则库时,构建的交叉编译工具的后端(后背工具 / backend)。

其中后背工具有一下几个 C 库: uClibc-ng / glibc / musl

一旦你选择了这个 backend, 一些选项将会出现。 重要的是他让你:

  • 更改用于构建工具链的 Linux 内核头文件的版本。 这里值得详细解释一下。 在建构 cross-compilation toolchain 的 C library 的时候, 该库提供了一套 Linux 用户层访问 Linux kernel 的接口。 而这些 C 库的时候必须通过 Linux kernel headers 指定的接口。 (即来自内核的 .h 文件), 它定义了用户空间和内核之间的接口(系统调用、数据结构等)。 由于此接口向后兼容, 用于构建工具链的 Linux 内核头文件的版本不需要 完全 匹配嵌入式系统上运行的 Linux 内核的版本。 它们只需要与您打算运行的 Linux 内核版本相同或更早的版本。 如果您使用的内核头文件比您在嵌入式系统上运行的 Linux 内核更新, 那么 C 库可能正在使用您的 Linux 内核未提供的接口。
  • 改变建构 GCC compiler, binutils 和 C 库的的版本。
  • 选择多个工具链选项(仅限 uClibc): 工具链是否应具有 RPC 支持(主要用于 NFS)、宽字符支持、locale 支持(用于国际化)、C++ 支持或 thread 支持。 根据您选择的选项,Buildroot 菜单中可见的用户空间应用程序和库的数量会发生变化:许多应用程序和库需要启用某些工具链选项。 当需要某个工具链选项才能启用这些包时,大多数包都会显示 comment。 如果需要,您可以通过运行 make uclibc-menuconfig 进一步细化 uClibc 配置。 但是请注意,Buildroot 中的所有包都针对 Buildroot 中捆绑的默认 uClibc 配置进行了测试: 如果您通过从 uClibc 中删除此功能来改动原有配置,则某些包可能不会构建。

值得注意的是,无论 config 中的哪个选项被修改了, 都应该重新 build 整个 toolchain 和 系统,详情请见 Section 8.2, “Understanding when a full rebuild is necessary”.

internal toochain 的优势:

  • 与 Buildroot 有良好的整合;
  • 快速,只建立必要的东西;

internal toochain 的劣势:

  • 清理整个工程(执行完make clean)后需要重建整个 toolchain, 这需要花费不少时间。 如果你试图减少建构工程所花费的时间,可以考虑使用 External toolchain backend
  • 我认为还应该加一个:无法使用某些 vendor 的私有指令优化硬件模块;

6.1.2. External toolchain backend

external toolchain backend 允许 Buildroot 使用已有的交叉编译工具链编译库和应用。 Buildroot 知道许多知名的交叉编译工具链 (比如来自Linaro 的 arm 交叉编译工具链, 来自 Sourcery CodeBench 用于 ARM,x86-64,PowerPC 和 MIPS 的交叉编译工具链)。 并且 Buildroot 能够自动下载它们,或者可以指向一个定制的工具链(可以是下载地址,也可以本地地址)。

此外,你有三个方式使用 external toolchain:

  • 使用预置 external toolchain 配置文件,让Buildroot下载、提取和安装工具链。 Buildroot 已经内置了一些 CodeSourcery 和 Linaro 工具链。 只需从可选的的工具链中选择 toolchain 中的工具链配置文件。 这绝对是最简单的解决方案。
  • 使用预置的 external toolchain 配置文件, 但是不需要 Buildroot 下载工具链,您可以告诉 Buildroot 您的工具链已经安装在您的系统上的何处。 只需在 toolchain 中选择可用的工具链配置文件, 取消选择 Download toolchain automatically, 并用交叉编译工具链的路径填充toolchain path text 条目。
  • 使用完全自定义的 external toolchain。 这对于使用 crosstool-NG 或 Buildroot 本身生成的工具链特别有用。 为此,请在 toolchain 列表中选择 Custom toolchain。 您需要填写Toochain pathToolchain prefixExternal toochain C library 选项。 然后,您必须告诉 Buildroot 您的外部工具链支持什么。 如果外部工具链使用了 GLBC 库, 你必须声明是否支持 C++,以及它是否具有内置RPC支持。 如果外部工具链使用了 uClibc 库, 那么你必须告诉 Buildroot 是否支持 RPC、宽字符、区域设置、程序调用、线程和C++。 在执行开始时,Buildroot 会告诉您所选选项是否与工具链配置匹配。

我们的外部工具链支持已经通过 CodeSourcery 和 Linaro 的工具链进行了测试, 这些工具链由 crosstool-NG , 或者由 Buildroot 自己生成。 一般来说,所有支持 sysroot 功能的工具链都应该可以用。 如果没有,请与开发商联系。

我们不支持 OpenEmbedded 或 Yocto 生成的工具链或SDK, 因为这些工具链不是纯工具链(即编译器、BiUTILS、C 和 C++ 库)。 相反,这些工具链附带了大量的预编译库和程序。 因此,Buildroot 无法导入工具链的 sysroot, 因为它可能包含数百兆字节的预编译库,这些库通常由 Buildroot 构建。

我们也不支持使用发行版工具链(即您的发行版安装的 gcc / binutils / C库)作为为目标构建软件的工具链。 这是因为您的分发工具链不是一个 “纯” 工具链(即仅与 C/C++ 库), 所以我们不能将它正确地导入到 Buildroot 构建环境中。 因此,即使您正在为 x86 或 x86_64 目标构建系统, 也必须使用 Buildroot 或 crosstool-NG 生成交叉编译工具链。

如果你想为你的工程生成定制的可用于 Buildroot 的 toolchain, 我们建议你使用 buildroot 本身区建构之。 (参考 Section 6.1.3, “Build an external toolchain with Buildroot”) 或者 crosstool-NG

优点:

  • 允许使用知名的和经过测试过的交叉编译工具。
  • 避免构建工程时再花额外的时间构建 toolchain, 这对嵌入式 Linux 系统的编译通常意味着会节省大量的时间。

劣势:

  • 如果你的预置 toolchain 有 bug, 可能很难推动 vendor 去修复, 除非你自己使用 buildroot 或者 Crosstool-NG 构建。

6.1.3. Build an external toolchain with Buildroot

Buildroot internal toolchain 选项能创建一个 external toolchain。 下面是创建一个 internal toolchain 并将之给自己(或者其他工程)重复利用起来的步骤。

参考一下信息,创建一个新的 Buildroot 的配置:

  • 为你的目标 CPU (架构) 选择一个合适的 目标选项
  • Toolchain 菜单,保持 Toolchain type 选项的值为默认的 Buildroot toolchain, 并根据需要配置您的工具链;
  • System configuration 菜单, 选择 None 作为 Init system 的值, 选择 none 作为 /bin/sh 的值;
  • Target packages 菜单, disable BusyBox 选项;
  • Filesystem images 菜单, disable tar the root filesystem 选项;

之后, 我们可以开始激活 Buildroot 构建 SDK 了。 这个流程将会为我们生成一个包含 toolchain 的 tarball。

make sdk

SDK 的 tarball 在 $(O)/images 目录下面, 名字类似于 arm-buildroot-linux-uclibcgnueabi_sdk-buildroot.tar.gz. 保存这个 tarball, 并可将之设置为 buildroot 的 external toolchain。或者用之去做其他开发。

在其他 Buildroot 项目的 Toolchain 菜单中:

  • 设置 Toolchain type External toolchain
  • 设置 Toolchain Custom toolchain
  • 设置 Toolchain origin Toolchain to be downloaded and installed
  • 设置 Toolchain URL file:///path/to/your/sdk/tarball.tar.gz

External toolchain wrapper

当使用外部工具链时,Buildroot 生成一个 wrapper 程序,透明地将适当的选项(根据配置)传递给 external toolchain。 如果您需要调试此 wrapper 以准确检查传递的参数,您可以将环境变量 BR2_DEBUG_WRAPPER 设置为以下任一值:

  • 0, 或者空值(不设置): 不会 debug
  • 1: 在一行显示所有的 argument
  • 2: 将每一个 argument 显示到每一行

6.2. /dev management

在 Linux 系统中, /dev 目录包含一些特殊的文件,称为 device files,通过内核生成的这些文件允许用户层的应用去访问、管理硬件设备。 如果没有这些 device files, 你的用户层应用可能并不能使用硬件设备,即使 Linux kernel 已经安装相关驱动。

System configuration, /dev management, Buildroot 提供了四个不同的方案去处理 /dev 目录:

  • 第一种方式为 Static using device table. 这是在 Linux 中处理设备文件的古老(经典)方式。 使用这种方法,设备文件永久存储在根文件系统中(即它们在重新启动后仍然存在), 即使硬件设备从系统中添加或删除,也不会自动创建和删除这些设备文件。 因此 Buildroot 用 device table 创建了一组标准的设备文件, 默认被存储在 Buildroot 源码的 system/device_table_dev.txt 位置。 这些文件将会在 Buildroot 生成最后 rootfs image 的时候被使用, 因此你并不能在 output/target 找到 device filesBR2_ROOTFS_STATIC_DEVICE_TABLE 选项可以更改其他的文件作为 Buildroot 生成 device files 的配置。 因此,如果你用了这种方法,但是 Buildroot 并没有内置你想要的配置,那么此时你可以在 board/<yourcompany>/<yourproject>/device_table_dev.txt 路径创建一个属于你的 device files 的描述文档(配置文件)。 然后你可以将 BR2_ROOTFS_STATIC_DEVICE_TABLE 设置为 system/device_table_dev.txt board/<yourcompany>/<yourproject>/device_table_dev.txt. 关于 device table 格式的更多信息,请参考 Chapter 25, Makedev syntax documentation.
  • 第二个方案是使用 Dynamic using devtmpfs onlydevtmpfs 是 Linux 2.6.32 以来引入的一个 Linux kernel 虚拟文件系统(veritual filesystem),(如果你使用一个更老的内核,那么这不是一个合适的方案)。 当 devtmpfs mount 到 /dev 目录的时候,该内核将会在 virtual filesystem 上根据系统中现有的硬件设备动态的生成 device files 。 使用 devtmpfs 需要首先将 kernel 中 CONFIG_DEVTMPFSCONFIG_DEVTMPFS_MOUNT 配置 enable。 如果你选用了该选项,当你使用 Buildroot 便宜内置的 linux kernel 的时候 Buildroot 会确保内核 enable 该两项配置。 但如果你用的是外部 kernel,那么你自己要对这两个选项负责(如果该两个选项没有使能,你可能会面临系统无法启动的风险)。
  • 第三个方案是 Dynamic using devtmpfs + mdev, 这个方法同样依赖于 devtmpfs (因此内核也必须配置上 CONFIG_DEVTMPFSCONFIG_DEVTMPFS_MOUNT 两个选项), 但该方法在此基础上加上了 mdev 的用户空间程序。 mdev 是属于 Busybox 的一部分, 并且在设备被删除和增加的时候内核都会调用之。 在 /etc/mdev.conf 配置文件的帮助下, mdev 可以用来设置设备的特殊权限或所有权,以及当 device 出现或者消失时执行哪个脚本或应用程序。 基本上,他允许 userspace 对设备的事件(添加 / 删除)做出相应响应。比如, mdev 可以用在设备出现时自当加载内核模块。 如果您的设备需要股价, mdev 同样也可以被设置为发现设备后马上将固件推送到设备中。 mdevudev 的轻量级实现(因为它仅实现了 udev 的少量特性)。 关于 mdev 的更多信息或者配置语法,请参考 http://git.busybox.net/busybox/tree/docs/mdev.txt.
  • 第四个方案是 Dynamic using devtmpfs + eudev, 这个方法同样依赖于 devtmpfs,像上面一样,但是还需要加上 eudev 用户空间的守护进程( daemon )。 eudev 是一个跑在应用层后台的守护进程, 它捕从内核中捕获设备被加入或者去除的事件。 它是一个比 mdev 更加重量级的解决方案,但是也提高了更高的灵活性, eudevudev 的独立版本, 他是大多数桌面发行版本中运行在最初用户空间中的 daemon,而现在是 Systemd 的一部分,关于更多信息请参考: http://en.wikipedia.org/wiki/Udev.

Buildroot developers 建议从 方案二 入手, 如果你有需求在用户空间获取设备的 added/removed 状态,或者需要动态的将 firmwares 推送到设备中, 则推荐使用 方案三

注意:如果 systemd 被选择作为系统的启动程序,则 /dev 将会由 systemd 提供的 udev 来管理。

6.3. init system

init 是内核启动的第一个用户空间的进程(PID 为 1), 它负责启动用户空间的服务和程序(比如说:web server, 图形应用,网络服务之类的)。

Buildroot 允许你使用三种不同类型的启动程序,你可以在 System configuration, Init system 中进行配置:

  • 第一个方案是 BusyBox。 在众多的程序中,BusyBox 实现了一个基本的 init 程序,这已经满足大多数嵌入式系统了。 Enable BR2_INIT_BUSYBOX 及会使 BusyBox 构建和安装 init 程序, 这是 Buildroot 的默认方案。BusyBox 的 init 程序启动后会读入 /etc/inittab 文件,该文件中记录者 init 应该干的事情, 关于 inittab 的语法可以参考 http://git.busybox.net/busybox/tree/examples/inittab (注意:BusyBox inittab 的语法很特殊:不要使用在网上随便下载的 inittab 文档 inittab)。 Buildroot 中的默认 inittab 被存储在 system/skeleton/etc/inittab。 除了挂在一些重要的文件系统之外,其主要工作是启动 /etc/init.d/rcS 中的 shell 脚本,并且启动 getty 应用 (该应用提供了一个登陆终端)。
  • 第二个方案是 systemV 。 这个方案使用传统的 sysvinit 作为启动应用,该应用被打包在 Buildroot package/sysvinit。 这是大多数 Linux 桌面发行版中使用的方案,不过最近,它们开始切换到最近的选择,比如 Upstart or Systemd。 sysvinit 同样使用 inittab 作为配置文件 (但是语法和 BusyBox 中的不同)。 与之一起被安装的默认 inittab 位于 package/sysvinit/inittab
  • 第三个方案是 systemd systemd 是 Linux 的新一代 init 程序。他和传统的 init 程序有很大的不同(比如 init )比如: 它有优秀的进行化能力,使用 socket 和 D_Bus activation 来启动服务,提供按需启动守护进程的功能, 使用 Linux grop 来管理进程,支持系统快照和恢复系统状态等操作 ...... 对于复杂的 嵌入式系统,systemd 是非常有用的,比如说那些需要通过 D-Bus 和 services互相通信的应用。 但需要注意的是 systemd 也带来了比较多的以来,比如: dbus, udev ... 关于 systemd 更多信息,请参考 http://www.freedesktop.org/wiki/Software/systemd.

Buildroot 的开发者默认推荐使用 BusyBox init ,他因为它对于大多数嵌入式系统来说都已经足够了。 如果你有更复杂的使用场景,那么使用 systemd 也是很不错的。



Chapter 7. Configuration of other components

注意,在你试图修改以下任何组件之前,请确保你已经对 Buildroot 进行过配置,并且已经 enable 过相关 package。

BusyBox

如果你已经 Busybox 配置文件,你可以直接修改 BR2_PACKAGE_BUSYBOX_CONFIG 指向该文件。 否则,Buildroot 将会启用默认的 BusyBox 配置文件。

如果需要在当前配置的基础上进行进一步配置,请运行 make busybox-menuconfig 打开 buildroot 配置工具进行配置。

另外,还可以通过环境变量的方式来指定 BusyBox 的配置文件,但是还是不推荐使用这种方式。参考: Section 8.6, “Environment variables” for more details.

uClibc
配置 uClibc 的方法和 Busybox 的类似。可以通过 BR2_UCLIBC_CONFIG 配置变量来指定你想要的 uClibc 的配置。 进行后续更改的命令为 make uclibc-menuconfig.
Linux kernel

如果你已经有 kernel 的配置文件,那么你可以使用 BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG 来指定该文件。

如果你还没有 kernel 的配置文件,那么你可以指定 Buildroot 的配置给 BR2_LINUX_KERNEL_USE_DEFCONFIG, 或者你可以创建一个空文件,并指定到 BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG 开始使用。

后续对配置文件进行更改,可以使用 make linux-menuconfig 打开 Linux kernel 的配置工具。

Barebox
配置 Barebox 的方法和配置 Linux kernel 的方法类似。与之相关联的配置变量有 BR2_TARGET_BAREBOX_USE_CUSTOM_CONFIGBR2_TARGET_BAREBOX_USE_DEFCONFIG。 而对配置文件进行修改的命令为 make barebox-menuconfig
U-Boot
配置 U-Boot (version 2015.04 or newer) 的方法和配置 Linux kernel 的方法类似。与之相关联的配置变量有 BR2_TARGET_UBOOT_USE_CUSTOM_CONFIGBR2_TARGET_UBOOT_USE_DEFCONFIG。 而对配置文件进行修改的命令为 make uboot-menuconfig

Chapter 8. General Buildroot usage

8.1.  make tips

这里有收集到一些运行 make 是的 tips, 可以帮助你更好的使用 buildroot。

显示 make 所有支持的 target

 $ make V=1 <target>

显示支持的所有 board 配置:

 $ make list-defconfigs

显示所有可用的 target: 

 $ make help

注意所有的 targets 都是一直可用的,但是一些在 .config 指定的 target 可能会隐藏起来。

  • busybox-menuconfig target 只有在 busybox 被 enable 的时候生效;
  • linux-menuconfiglinux-savedefconfig 只有在 linux enable 的时候生效;
  • uclibc-menuconfig 只有在 uClibc 被选择进 internal toolchain backend 的时候生效;
  • barebox-menuconfigbarebox-savedefconfig 只有在使能 barebox 的时候生效;
  • uboot-menuconfiguboot-savedefconfig 只有在 U-Boot 被使能的时候生效;

Cleaning:  当任何架构或工具链配置选项发生更改时,都需要显式清理。

删除所有构建物 (包括 output 目录的 build / host /staging trees / target trees / images / toolchain), 请使用:

 $ make clean

生成 menual: 目前 menual 的源码位于docs/manual 目录,使用如下命令可生成 manual:

$ make manual-clean
$ make manual

生成 menual 的位置在 output/docs/manual.

注意

为一个新的 target reset Buildroot:  删除所有建构过程产生的输出以及配置,请运行

 $ make distclean

注意:  如果 ccache 被 enabnle, 执行 make clean 或者 distclean 将不会清空被 buildroot 使用到得 compiler cache。 如果要删除之,请参考 Section 8.14.3, “Using ccache in Buildroot”.

Dumping the internal make variables:  如需要 dump 已知的变量及其值,请运行:

 $ make -s printvars VARS='VARIABLE1 VARIABLE2'
 VARIABLE1=value_of_variable
 VARIABLE2=value_of_variable

这可以使用如下变量调整输出格式:

  • VARS, 将列表限制为名称与指定的 make-patterns 匹配的变量 - 必须设置,否则不会打印任何内容
  • QUOTED_VARS, 如果设置为 YES, 将会打印单引号包围的值
  • RAW_VARS, 如果设置为 YES, 将会打印未扩展的值

比如:

 $ make -s printvars VARS=BUSYBOX_%DEPENDENCIES
 BUSYBOX_DEPENDENCIES=skeleton toolchain
 BUSYBOX_FINAL_ALL_DEPENDENCIES=skeleton toolchain
 BUSYBOX_FINAL_DEPENDENCIES=skeleton toolchain
 BUSYBOX_FINAL_PATCH_DEPENDENCIES=
 BUSYBOX_RDEPENDENCIES=ncurses util-linux
 $ make -s printvars VARS=BUSYBOX_%DEPENDENCIES QUOTED_VARS=YES
 BUSYBOX_DEPENDENCIES='skeleton toolchain'
 BUSYBOX_FINAL_ALL_DEPENDENCIES='skeleton toolchain'
 BUSYBOX_FINAL_DEPENDENCIES='skeleton toolchain'
 BUSYBOX_FINAL_PATCH_DEPENDENCIES=''
 BUSYBOX_RDEPENDENCIES='ncurses util-linux'
 $ make -s printvars VARS=BUSYBOX_%DEPENDENCIES RAW_VARS=YES
 BUSYBOX_DEPENDENCIES=skeleton toolchain
 BUSYBOX_FINAL_ALL_DEPENDENCIES=$(sort $(BUSYBOX_FINAL_DEPENDENCIES) $(BUSYBOX_FINAL_PATCH_DEPENDENCIES))
 BUSYBOX_FINAL_DEPENDENCIES=$(sort $(BUSYBOX_DEPENDENCIES))
 BUSYBOX_FINAL_PATCH_DEPENDENCIES=$(sort $(BUSYBOX_PATCH_DEPENDENCIES))
 BUSYBOX_RDEPENDENCIES=ncurses util-linux

引用变量的输出可以在 shell 脚本中重复使用,例如:

 $ eval $(make -s printvars VARS=BUSYBOX_DEPENDENCIES QUOTED_VARS=YES)
 $ echo $BUSYBOX_DEPENDENCIES
 skeleton toolchain

8.2. Understanding when a full rebuild is necessary

当你执行 make menuconfigmake xconfig 之类的命令修改了系统配置的时候,Buildroot 并不会试图去检测哪一部分是需要被重新建构的。 在某些情况下,可能只需要重新建构数个 package, 但有些时候可能需要重新建构整个系统。 但是以完全可靠的方式检测这一点非常困难,因此 Buildroot 开发者决定不尝试这样做。

相反,用户有责任知道何时需要完全重建。 但是,这里有一些经验法则可以帮助您了解如何使用 Buildroot:

  • 当目标架构配置发生变化时,需要进行完整的重建。 例如,更改架构、二进制格式或浮点策略会对整个系统产生影响。
  • 当 toolchain 配置更改时,通常需要完整的重建。 更改 toolchain 配置通常涉及更改编译器版本、C 库类型或其配置或其他一些基本配置项,这些更改对整个系统都有影响。
  • 当一个额外的包被添加到配置中时,不一定需要完全重建。 Buildroot 会检测到这个包从未被构建过,并且会构建它。 但是,如果这个包是一个库,而且可以被已经构建的包选择性使用时,Buildroot 将不会自动重建已经编译过的包。 要么您应该知道重建哪些包,并且您可以手动重建它们; 要么您应该进行完全重建。 例如,假设您使用 ctorrent 包构建了一个系统,但没有 openssl。 您的系统可以工作,但您意识到您希望在 ctorrent 中提供 SSL 支持,因此您在 Buildroot 配置中启用了 openssl 包 并重新启动构建。 Buildroot 会检测到 openssl 应该被构建并会构建它,但它不会检测到 ctorrent 也因当被重建, 以从 openssl 得到 OpenSSL 支持。 此时您要么必须完全重建,要么重建 ctorrent 本身。
  • 当从配置中删除一个包时,Buildroot 不会做任何特别的事情。 它不会从目标根文件系统或工具链 sysroot 中删除此包安装的安装文件。 莫需要完全重建才能摆脱这个包。 但是,通常您不一定需要立即删除此包:您可以等待下一个发布时间再从头开始构建。 (但你如果你发现当前调试出问题的时候,应当把这一点纳入考虑范围)
  • 当包的子选项(sub-options)改变时,包不会自动重建。 一般情况下,进行此类更改后,仅重新构建此包通常就足够了,除非启用包子选项会向包中添加一些对已构建的另一个包有用的功能。 同样,Buildroot 不会跟踪何时应该重新构建包:一旦构建了包,除非明确指示这样做,否则它永远不会重新构建。
  • 当对根文件系统(root fs)框架(skeleton)进行更改时,需要完全重建。 但是,当更改的内容是,文件覆盖、构建后脚本或 image 后脚本进行更改时,不需要完全重建: 在下一个 make 被调用时将考虑这些变化。
  • FOO_DEPENDENCIES 中列出的包被重建或删除时,包 foo 不会自动重建。 例如,如果一个包 bar 被设置 FOO_DEPENDENCIESFOO_DEPENDENCIES = bar, 并且 bar 包的配置发生更改,配置更改不会导致包 foo 自动重建。 在这种情况下,您可能需要在您的构建中重建任何在其 DEPENDENCIES 中引用 bar 的包,或者执行完整的重建以确保任何 bar 依赖包都是最新的。

一般来说,当您遇到构建错误并且您不确定所做的配置更改的潜在后果时,请进行完整的重建。 如果你得到同样的构建错误,那么你肯定这个错误与包的部分重建无关,如果这个错误发生在官方 Buildroot 的包中,请不要犹豫,马上向我们报告问题! 随着您对 Buildroot 的体验不断加深,您将逐渐了解何时真正需要完全重建,并且您将节省越来越多的时间。

作为参考,完全重建可通过如下命令进行:

$ make clean all

8.3. Understanding how to rebuild packages

一个被最多人问道的问题是,Buildroot 如何 rebuild 一个 package, 或者如何不用 rebuild 工程的情况下删除一个 package。

在不重建工程的情况下安全的删除一个 package 的方法在 Buildroot 中时不存在的。 这是因为 buildroot 基本不跟踪 package 安装了哪些文件到 output/stagingoutput/target 中, 同时也不会分析依赖当前删除 package 的 package 在删除之后需要做哪些操作。

从头开始重建单个包的最简单方法是在 output/build 中删除它的构建目录。 Buildroot 将从头开始重新提取、重新配置、重新编译和重新安装这个包。 您可以使用 make <package>-dirclean 命令要求 buildroot 执行此操作。

另一方面,如果您只想从编译步骤重新启动包的构建过程,您可以运行 make <package>-rebuild。 它将重新启动包的编译和安装,但不是从头开始: 它基本上相当于在 package 层面执行 makemake install ,所以它只会重建改变的文件。 (因为没有重新提取这个步骤,因此有时也不能保证改动文件被顺利更改,建议还是使用删除 output/build 目录的方法会更保险)

如果要从配置步骤重新启动包的构建过程,可以运行 make <package>-reconfigure。 它将重新启动包的配置、编译和安装。

<package>-rebuild 包含 <package>-reinstall<package>-reconfigure 包含 <package>-rebuild, 这些 targers 只作用于所指定的 <package>, 并且不触发重新创建根文件系统 image 。 如果需要重新创建根文件系统,还应该运行 makemake all

在内部,Buildroot 会创建名为 stamp files 的标记文件来追踪 package 被编译到哪一步。 他们被保存在 package 的 build 目录, output/build/<package>-<version>/ 的标记文件名为 .stamp_<step-name>。 上面详述的命令只是操作这些标记文件以强制 Buildroot 重新启动包构建过程的一组特定步骤。

更多关于 package 的特殊 target 信息请参考: Section 8.14.5, “Package-specific make targets”

8.4. Offline builds

 

 $ cd /tmp/build; make O=$PWD -C path/to/buildroot

所有输出文件都将位于 /tmp/build 下。 如果 O 路径不存在,Buildroot 将创建它。

注意: O 参数指定的路径可以是相对路径,也可以是绝对路径,但如果你填写的是相对路径,改路径是相对于 buildroot 工程一级目录的相对路径。而 不是 当前工作目录。

当你在 Buildroot 外进行建构的时候, Buildroot 的 .config 文件和缓存文件 将会保存在 output directory( -O 参数指定的)。 这意味着您可以安全地使用相同的源代码树并行运行多个构建,只要它们使用唯一的输出目录。

为了方便使用,Buildroot 在首次运行的时候会在输出目录生成一个 Makefile wrapper,因此之后你只需要在输出目录运行 make 即可,不在需要使用 O=<…> 或者 -C <…> 去指定。

8.6. Environment variables

 Buildroot 通用也支持一些环境变量,可在 make 的时候指定,或者设置到当前环境中:

  • HOSTCXX, 使用主机的 C++ 编译器
  • HOSTCC, 使用主机的 C 编译器
  • UCLIBC_CONFIG_FILE=<path/to/.config>,指向 uClibc 的配置文件。如果是使用的 internal toolchain, 则编译 uClibc 的时候用到。 注意 uClibc 的配置文件还可以通过 Buildroot 配置文件配置,而且主要还是推荐该种方式。
  • BUSYBOX_CONFIG_FILE=<path/to/.config>,指向 BusyBox 的配置文件。注意同样也可以通过 Busybox 的配置文件来配置,而且首推这种方式。
  • BR2_CCACHE_DIR 如果指定该环境变量,那么 Buildroot 将会自己的缓存缓存到该变量指定的目录。(前提是使能 ccache)
  • BR2_DL_DIR 覆盖指定下载 Buildroot 存储/获取下载资源的目录。 注意,DL 目录还可以在 Buildroot 的配置文件里面设置,参考 Section 8.14.4, “Location of downloaded packages” 获取更多关于 DL 目录的更多信息。
  • BR2_GRAPH_ALT, 如果设置且非空,则在构建时 graphs 时使用替代配色方案。
  • BR2_GRAPH_OUT 指定生成 graphs 时保存的文件格式 pdf (默认), 或者 png
  • BR2_GRAPH_DEPS_OPTS 将其它选项传递给依赖图(dependency graph); 参考 Section 8.9, “Graphing the dependencies between packages” 获取更多信息。
  • BR2_GRAPH_DOT_OPTS 完整的将值传递给 dot 应用绘制依赖图。
  • BR2_GRAPH_SIZE_OPTS 设置依赖图的大小;参考 Section 8.11, “Graphing the filesystem size contribution of packages” 获取更多信息。

下面是一个用用户根目录中的一个文件做为 uClibc 配置的例子:

 $ make UCLIBC_CONFIG_FILE=uClibc.config BUSYBOX_CONFIG_FILE=$HOME/bb.config

下面是一个用 host 中 gccg++ 编译辅助工具的例子:

 $ make HOSTCXX=g++-4.3-HEAD HOSTCC=gcc-4.3-HEAD

8.7. Dealing efficiently with filesystem images

文件系统 image ( image )可能会很大,这取决于你选择文件系统类型,包(package)数量,你是否提供了可用的空间... ... 但是, image 中的某些位置可能是空的 (比如,大部分内容为 zeroes 的文件);这些文件被称作 稀疏(sparse) 文件。

有很多工具可以有效地处理稀疏文件,并且只会存储或写入稀疏文件中非空的那些部分。

比如:

  • tar 接受 -S 选项来保证它仅存储非 0 的稀疏文件。

    • tar cf archive.tar -S [files…]将有效地将稀疏文件存储在 tarball 中。
    • tar xf archive.tar -S将有效地存储从 tarball 中提取的稀疏文件。
  • cp 接受 --sparse=WHEN 选项 (WHEN 为一下三个值 auto, never 或者 always):

    • 如果 source.file 是一个包含很多空值的文件, cp --sparse=always source.file dest.file 将会创建一个名为 dest.file 的稀疏文件。

其他工具可能有类似的选项。 请查阅它们各自的手册。

如果您需要转储文件系统 image (例如从一台机器转移到另一台机器),或者如果您需要发送它们(例如 &),你可以使用上面的方式生成压缩后的稀疏文件。

但是请注意,如果使用 dd 烧录的稀疏模式的文件系统 image 时可能会导致文件系统损坏(例如,ext2 文件系统的块位图(bitmap)可能已损坏;或您的文件系统中存在稀疏文件,则这些部分在 read back 时可能不会全为零)。 您应该只在构建机器上处理文件时使用稀疏文件,而不是在将它们传输到将在目标上使用的实际设备时使用。

8.8. Details about packages

Buildroot 可以生成一个 JSON 格式说明文档,描述当前配置中启用的包集,以及它们的依赖项、许可证和其他元数据。 该说明文档可用以下命令生成:

make show-info

Buildroot 还可以使用 pkg-stats 以 HTML 和 JSON 输出的形式生成有关包的详细信息。 这些详细信息甚至包括已知 CVE(安全漏洞)是否影响您当前配置中的包, 这些包是否有更新的上游版本。

make pkg-stats

8.9. Graphing the dependencies between packages

Buildroot 的工作之一是了解包之间的依赖关系,并确保它们以正确的顺序构建。 这些依赖项有时可能非常复杂,对于给定的系统,通常不容易理解为什么 Buildroot 将这样或那样的包带入构建中。

为了帮助理解依赖关系,从而更好地理解嵌入式 Linux 系统中不同组件的作用,Buildroot 能够生成依赖 package 之间的关系图。

运行下面的命令,将会生成一个包含整个系统的依赖图:

make graph-depends

生成该图的位置在 output/graphs/graph-depends.pdf.

如果你的系统非常大,这个图可能会变得非常的复杂难以阅读。因此 Buildroot 也可以专为您指定的 package 生成依赖图,如下:

make <pkg>-graph-depends

该图输出的位置为:output/graph/<pkg>-graph-depends.pdf

注意,该以来图由来自 Graphviz dot 工具生成。所以你必须下安装该工具才行。 在大多数发行版中,该工具的名称为 graphviz

通常情况下该工具生成的文件格式为 PDF,但是你可以通过 BR2_GRAPH_OUT 环境变量指定输出格式为:PNG, PostScript, SVG 或者其他。 如果想查看支持的格式可以在使用 dot 的时候携带 -T 参数查看。

BR2_GRAPH_OUT=svg make graph-depends

graph-depends 的行为可通过环境变量 BR2_GRAPH_DEPS_OPTS 进行设置。 可选的选项有:

  • --depth N, -d N, 限制依赖深度为N。默认为0(即不限制)。
  • --stop-on PKG, -s PKG, 设置以来关系终止的 PKG,当判断依赖的包符合该条件是则停止绘制(注意:匹配到得包还会显示在图中)。 PKG 可以是包名 、glob、或者以下关键字 virtual (停止于虚拟包), 或者 host (停止于主机包)。
  • --exclude PKG, -x PKG, 像 --stop-on, 但也从图中省略了匹配的 PKG
  • --transitive, --no-transitive, 使能或者禁止绘制传输依赖。默认是禁止。
  • --colors R,T,H,以逗号分隔的颜色列表,用于绘制根包(R), 目标包(T)和宿主包(H)。 默认为:lightblue, grey, gainsboro
BR2_GRAPH_DEPS_OPTS='-d 3 --no-transitive --colors=red,green,blue' make graph-depends

8.10. Graphing the build duration

当系统的构建需要很长时间时,有时能够了解哪些包的构建时间最长是有用的,看看是否可以采取任何措施来加快构建速度。 为了帮助这样的构建时间分析,Buildroot 收集每个包每个步骤的构建时间,并允许从这些数据生成图形。

使用如下指令生成统计图:

make graph-build

这将会在 output/graphs 目录生成一系列的文件:

  • build.hist-build.pdf,包含每个包的构建时间的直方图,按构建顺序排序。
  • build.hist-duration.pdf,每个包的构建时间的直方图,按持续时间排序(最长的在前)。
  • build.hist-name.pdf,每个包的构建时间的直方图,按包名排序。
  • build.pie-packages.pdf,每个包的构建时间的饼图。
  • build.pie-steps.pdf,在包构建过程的每个步骤中花费的全局时间的饼图。

这个 graph-build 目标需要安装 Python Matplotlib 和 Numpy 库(在大多数发行版中包名为python-matplotlibpython-numpy),如果您使用的是早于 2.7 的 Python 版本,则还有 argparse 模块(在大多数发行版中包名为python-argparse )。

默认情况下,图形的输出格式为 PDF,但可以使用 BR2_GRAPH_OUT 环境变量选择不同的格式。 支持的另外一种格式是 PNG:

BR2_GRAPH_OUT=png make graph-build

8.11. Graphing the filesystem size contribution of packages

当您的目标系统增长时,了解每个 Buildroot 包对整个根文件系统大小的贡献有时会很有用。 为了帮助进行此类分析,Buildroot 收集有关每个包安装的文件的数据,并使用这些数据生成图表和 CSV 文件,详细说明不同包的大小消耗。

可以使用下面的命令生成这些数据:

make graph-size

这将会生成:

  • output/graphs/graph-size.pdf,每个包对整个根文件系统大小消耗的贡献的饼图
  • output/graphs/package-size-stats.csv,每个包对整个根文件系统大小消耗的 CSV 文件。
  • output/graphs/file-size-stats.csv,给出了每个已安装文件对其所属包的大小贡献,以及对整个文件系统大小的贡献的 CSV 文件。

生成 graph-size 需要安装 Python Matplotlib 库(在大多数发行版中包名为python-matplotlib ), 如果您使用的是早于 2.7 的 Python 版本,您还需要安装 argparse 模块(在大多数发行版上为 python-argparse)。

就像编译时间图一样,支持 BR2_GRAPH_OUT 环境变量来调整输出文件格式。 有关此环境变量的详细信息,请参考 Section 8.9, “Graphing the dependencies between packages”

另外,还可通过 BR2_GRAPH_SIZE_OPTS 来设置更多参数:

  • --size-limit X, -l X, 该选项将小于百分 X 的包纳入 Others 组。 默认 X=0.01。可接受的值范围在 [0.0..1.0]
  • --iec, --binary, --si, --decimal, 使用 IEC (binary, powers of 1024) 或者 SI (decimal, powers of 1000; 默认) 作为前缀.
  • --biggest-first, 设置为降序排列。

注意  生成存储损耗图需要在工程完全 clean rebuild 之后,确保在运行 make graph-size 前先运行过 make clean all

要比较两个不同 Buildroot 编译的根文件系统大小,例如在调整配置后或切换到另一个 Buildroot 版本时,请使用 size-stats-compare 脚本。 它接受两个 file-size-stats.csv 文件(由 make graph-size 生成)作为输入。 有关更多详细信息,请参阅此脚本的帮助文本:

utils/size-stats-compare -h

8.12. Top-level parallel build

注意:  这个章节包含很多实验特性,可能会引发一些意料之外的情况。使用的时候注意风险:

Buildroot 一直可以在编译每个 package 的时候使用并行编译:Buildroot 将会使用 make -jN 来建构(非 make 类的采用类似 make 的方法启动编译)。 默认开启的线程数为 CPU 的数量 +1,但是你也可以使用 BR2_JLEVEL 选项来更改。

直到 2020.02 为止,Buildroot 一直都是以串行的方式在 PKG 之间建构,而不是并行的方式建构。从 2020.02 开始,Buildroot 实验性质的支持 top-level parallel build(顶级并行建构) ,这可以加速那些没有依赖关系的 PKG 的建构速度。这个特性目前还是以实验的方式在进行,并且在一些场景中无法使用。

如果想使用 top-level parallel build,你必须:

  1. 在 Buildroot 中使能(Enable)BR2_PER_PACKAGE_DIRECTORIES 选项;
  2. 在开始便宜 Buildroot 的时候使用 make -jN

在内部,BR2_PER_PACKAGE_DIRECTORIES 将会启用名为 per-package directories 的机制, 它将产生如下效果:

  • 与所有的 package 共享公共的 targethost 目录不同,设置该选项之后将会为每个 PKG 生成一个独立的 target host 目录,(目录路径分别为 $(O)/per-package/<pkg>/target/$(O)/per-package/<pkg>/host/) 这些文件夹将会在 <pkg> 构建开始时从包依赖项的相应文件夹中填充。 因此,编译器和所有其他工具将只能查看和访问由 <pkg> 明确列出的依赖项安装的文件。
  • 在构建结束时,全局 target host 将填充目录, 分别位于 $(O)/target$(O)/host。 这意味着在构建期间,这些文件夹将是空的,并且只有在构建的最后才会填充它们。

8.13. Integration with Eclipse

虽然一部分嵌入式 Linux 开发人员喜欢经典文本编辑器(如 Vim 或 Emacs)和基于命令行的界面,但许多其他嵌入式 Linux 开发人员喜欢更丰富的图形界面来完成他们的开发工作。 Eclipse 是最受欢迎的集成开发环境之一,Buildroot 可与 Eclipse 集成以简化 Eclipse 用户的开发工作。

在与 Eclipse 的集成后,Buildroot 在进行应用程序和库的编译、远程执行和远程调试流程都得到了简化。 但我们目前还没有将 Buildroot 配置和构建过程本身与 Eclipse 集成。 因此,我们 Eclipse 集成的典型使用流程是:

  • 使用 make menuconfig 或者 make xconfig 等 来配置你的 Buildroot;
  • 使用 make 来进行构建; Build your Buildroot system by running
  • 启动 Eclipse 来开发,执行,调试 Buildroot 中配置使用到的应用或者库。

关于 Buildroot 和 Eclipse 集成的更多细节请参考 https://github.com/mbats/eclipse-buildroot-bundle/wiki.

8.14. Advanced usage

8.14.1. Using the generated toolchain outside Buildroot

你也许会想要编译一些非 Buildroot 预置的 PKG (比如说你自己开发的或者未被集成的)。 你可以使用 Buildroot 生成的 toolchain 来进行编译。

Buildroot 生成的 toolchain 在 output/host/。最简单的使用方式是将 toolchain 的 bin 目录(output/host/bin/)加入到你的 PATH 环境变量中, 待生效后,你便可使用 ARCH-linux-gcc, ARCH-linux-objdump, ARCH-linux-ld 等工具来构建你自己的应用。

另外,Buildroot 还可以将编译好的 toolchain 和其他选择上的一些依赖库导出 SDK 开发套件, 执行 make sdk 即可。最终该命令把 output/host/ 中的内容打成一个名为 <TARGET-TUPLE>_sdk-buildroot.tar.gz (该名称可以用 BR2_SDK_PREFIX 来修改) 的压缩包输出到output/images/ 目录。

该 SDK (tarball) 可以发布给那些想要开发应用,但目前还未对应用进行 Buildroot 适配的开发者进行开发。

提取 SDK tarball 后,用户必须运行脚本 relocate-sdk.sh(位于SDK的顶部目录),以确保所有路径都更新为新的位置。

另外,如果你只想生成 SDK,但是不想对其进行打包(比如说你想将 host 移动到一个位置直接作为 SDK 使用),仅需执行 make prepare-sdk 即可。

为了方便使用,在你选择了 BR2_PACKAGE_HOST_ENVIRONMENT_SETUP 之后,Buildroot 将会在 output/host/ (SDK) 生成一个脚本 environment-setup。 这个脚本可将 . your/sdk/path/environment-setup 到处到环境变量中,这可帮助你使用 buildroot 的 sdk 来编译您的应用。 PATH 变量包含了 SDK 中的可执行文件,标准 autotools 执行时会选择合适的值, 并且 CONFIGURE_FLAGS 包含了运行 autotools 使用到的一些基础交叉编译选项配置文件( ./configure ), 它还提供了一些有用的命令。 但是请注意,一旦执行了此脚本,环境将一交叉编译为目的进行设置,如再用于本机编译将会产生意料之外的后果。

8.14.2. Using gdb in Buildroot

Buildroot 允许进行交叉调试(cross-debugging),其中调试器在构建机器上运行并与目标上的 gdbserver 通信以控制程序的执行。

To achieve this:

  • 如你使用 internal toolchain (由 Buildroot 建构), 你需要使能 BR2_PACKAGE_HOST_GDBBR2_PACKAGE_GDBBR2_PACKAGE_GDB_SERVER。 这将保证交叉编译平台 gdb (cross gdb) 和 gdbserver 被编译,并且 gdb server 被安装到你的目标系统中。
  • 如果你使用 external toolchain,你应该使能 BR2_TOOLCHAIN_EXTERNAL_GDB_SERVER_COPY, 在编译的时候 Buildroot 会将 external toolchain 中的 gdbserver 拷贝到目标系统中。如果你的 external toolchain 未包含平台 gdb (cross gdb) 或者 gdbserver, 你同样可以让 Buildroot 建构之, 你只需要使能一些选项,像 internal toolchain backend

现在,如果你想调试一个名为 foo 的程序,你应该在目标平台上以以下方式运行:

gdbserver :2345 foo

这将使 gdbserver 打开一个 2345 的监听端口,监听来自 cross gdb 的请求消息。

然后,在 host 主机上运行以下命令看来调试:

<buildroot>/output/host/bin/<tuple>-gdb -x <buildroot>/output/staging/usr/share/buildroot/gdbinit foo

当然 foo 必须是在当前目录可用的,而且在建构是需要启用 debugging symbols。 通常你需要从你建构 foo 的目录来执行,而不是 output/target/,因为该目录下的可执行文件大概率情况下是被 stripped 后的。

<buildroot>/output/staging/usr/share/buildroot/gdbinit 文件将会告诉 cross gdb 从哪里找到目标依赖的 libraries。

最后可以使用如下命令来连接目标进行调试:

(gdb) target remote <target ip address>:2345

8.14.3. 在 Buildroot 中使用 ccache

ccache 是一个编译缓存工具。 它保存编译过程中生成的每一个 obj 文件, 并且能够通过使用预先存在的目标(obj)文件跳过当前或者未来的相同源文件(具有相同编译器和相同参数)。 当需要频繁的从头开始多次进行几乎相同的构建时,它可以很好地加快构建过程。

Buildroot 集成了 ccache, 你可以在 Buildroot 的配置中使能该功能 Build options -> Enable compiler cache。 使能之后 ccache 将会被编译,而且在之后 host 和 target 的每一次编译中使用到。

ccache 的缓存保存于 $HOME/.buildroot-ccache 中,因此它也会被其他工程的 Buildroot 编译使用到, 如果你想清除该缓存,直接删除该目录即可。

你可以通过运行 make ccache-stats 来获取 cache 的统计信息(包含:大小,命中数,未命中数)等。

make 时使用的 ccache-optionsCCACHE_OPTIONS 环境变量提供了更多通用的配置,如:

# set cache limit size
make CCACHE_OPTIONS="--max-size=5G" ccache-options

# zero statistics counters
make CCACHE_OPTIONS="--zero-stats" ccache-options

ccache 对源文件和编译器选项进行散列。 如果编译器选项不同,则不会使用缓存的目标文件。 但是,许多编译器选项都包含到临时目录的绝对路径。 因此,在不同的输出目录中构建会导致许多缓存未命中。

为了避免该问题,buildroot 拥有一个 Use relative paths 的选项(BR2_CCACHE_USE_BASEDIR)。 这将会重写所有只想输出目录的绝对路径为相对路径,从而可以解决,更改输出目录而导致缓存未命中的问题。

相对路径的一个缺点是,目标文件内部也被改成相对路径。 因此可能会导致一些其他的问题,例如,除非您先 cd 到输出目录,否则调试器将找不到该文件。

请参考 ccache manual’s section on "Compiling in different directories" 获取更多关于路径方面的信息。

8.14.4. Location of downloaded packages

Builroot 下载的各种 tarball 都被存放在 BR2_DL_DIR,该环境变量默认为 dl。 如果你不想每次创建工程的哦时候都下载 tarballs,你可以从已经下载好的目录拷贝到新工程。

如果你维护多个 Buldroot 工程,你最好拥有一个共享的下载目录。这可以通过 BR2_DL_DIR 环境变量来指定该目录。 如果设置了该环境变量,buildroot 中的 BR2_DL_DIR 将会被覆盖。下面的这些行应该加载到 <~/.bashrc> 中:

 export BR2_DL_DIR=<shared download location>

下载目录同样可以被设置到 BR2_DL_DIR 指定的 .config 文件中, 不想其他大多数的选项,该选项会被环境变量 BR2_DL_DIR 覆盖。

8.14.5. Package-specific make targets

运行 make <package> 可构建和安装特定的包以及其依赖,

对于 Buildroot 的内置的基础依赖包,还有许多其他的 make target 可以调用,如:

make <package>-<target>

以下是包的一些 targets ( 以执行顺序排序 ):

command/targetDescription

source

获取源码(下载 tarball. 或者 clone 源仓库, 等);

depends

构架并且安装构建所需要的依赖项目;

extract

将源代码解压或者拷贝 ... 到 build 目录;

patch

应用补丁,如果有的话 ;

configure

运行配置命令,如果有的话;

build

运行编译命令;

install-staging

target package: 在包的暂存目录中运行安装命令,如果必要的话;

install-target

target package: 在目标目录中运行安装过程,如果必要的话;

install

target package: 运行之前的两个安装过程;

host package: 在 host 目录中运行 安装过程;

此外还有一些其他用途的 make targets:

command/targetDescription

show-depends

显示被建构包的依赖项;

show-recursive-depends

递归现实被建构包的依赖项目;

show-rdepends

现实被建构包的一级依赖(即包的直接依赖);

show-recursive-rdepends

递归的显示包的反向依赖关系(直接或者间接依赖之的包);

graph-depends

在当前板级的 Buildroot 环境中,生成包的依赖图, 查看 this section 获取更多详细信息;

graph-rdepends

生成包的反向依赖图(即包含直接或者间接依赖该包的图);

dirclean

删除整个包的构建(build)目录;

reinstall

重新执行安装命令;

rebuild

重新执行编译命令 - 这仅在使用了 OVERRIDE_SRCDIR 特性或者当你直接修改了 build 目录里的工程时才会触发。 (请注意,这里经常会导致你修改了代码,但没有编译进去的困惑)

reconfigure

重新运行配置命令,然后编译(rebuild)-- 该 rebuild 同样受制于上述 rebuild 所陈述的条件。

8.14.6. Using Buildroot during development

正常情况下,Buildroot 的操作为:下载 tarball, 解压,配置,编译和安装, 源码被解压到 output/build/<package>-<version> 目录,该目录为缓存目录,因此,只要你执行 make clean, 该目录将会被直接清除, 并且在下一次 make 被调用的时候重新创建。 即使使用 Git 或 Subversion 存储库作为包源代码的输入,Buildroot 也会为其创建一个 tarball,然后像处理 tarball 一样正常运行。

当 Buildroot 主要用作集成工具来构建和集成嵌入式 Linux 系统的所有组件时,这种行为非常适合。 但是,如果在开发系统的某些组件时也使用 Buildroot,这种行为就不是很方便了。一个替代的方法是,在对一个包的源代码做一个小小的改动,用 Buildroot 进行快速的重建(rebuild) .

output/build/<package>-<version> 目录中直接做修改并不是一个好的方案, 因为该目录在执行 make clean 之后将会被抹去,你的辛苦将会付之一炬。

因此 Buildroot 提供了一个特殊的机制应对这种情况(即 <pkg>_OVERRIDE_SRCDIR ): Therefore, Buildroot provides a specific mechanism for this use case: the <pkg>_OVERRIDE_SRCDIR mechanism. Buildroot 将会读取一个 override 文件,用户可以通过该文件告诉 Buildroot 指定包的源码路径。

覆盖文件的默认路径为 $(CONFIG_DIR)/local.mk,该路径由 BR2_PACKAGE_OVERRIDE_FILE 配置选项指定。 $(CONFIG_DIR) 的位置即是 Buildroot .config 文件的位置。 因此 local.mk 默认与 .config 同目录。

如果需要指定一些特殊的路径,则可以通过 BR2_PACKAGE_OVERRIDE_FILE 选项来配置。

Buildroot 将会从 override 文件中解析如下格式的数据:

<pkg1>_OVERRIDE_SRCDIR = /path/to/pkg1/sources
<pkg2>_OVERRIDE_SRCDIR = /path/to/pkg2/sources

比如:

LINUX_OVERRIDE_SRCDIR = /home/bob/linux/
BUSYBOX_OVERRIDE_SRCDIR = /home/bob/busybox/

当 Buildroot 发现给定的包拥有 <pkg>_OVERRIDE_SRCDIR 配置时, Buildroot 将不再执行下载,解压,打补丁等操作。 相反,Buildroot 将会直接使用该目录,并且在执行 make clean 的时候将不会动到给目录。 这允许你指定你自己的目录(可以是被 Git / Subversion 或者其他版本管理工具管理的工程), 为了做到这一点,Buildroot 将会使用 rsync 来将源代码(<pkg>_OVERRIDE_SRCDIR指定的)拷贝到构建目录中(output/build/<package>-custom/)。

这个机制最好与 make <pkg>-rebuildmake <pkg>-reconfigure 一起连用。 make <pkg>-rebuild all 将会 rsync <pkg>_OVERRIDE_SRCDIR 中指定的源码到 output/build/<package>-custom 目录中(得益于 rsync 的机制,rsync 仅仅会拷贝改动的文件 ),并为拷贝的包重启 build 过程。

以 Linux 包作为事例,开发者可以设置源码目录为 /home/bob/linux ,然后执行:

make linux-rebuild all

几秒钟过后 Buildroot 将会更新 kernel img 到 output/images 目录。 同样,也可以指定 BusyBox 的源码路径为 /home/bob/busybox, 然后执行:

make busybox-rebuild all

位于 output/images 目录的根文件系统 image 将包含你指定的 Busybox 工程中的内容。

巨型工程的源码可能有成千上百个与编译无关的文件,这哦文件会降低 rsync 的拷贝速度,一个可选的方案是,你可以使用 <pkg>_OVERRIDE_SRCDIR_RSYNC_EXCLUSIONS 跳过一些指定的文件。 比如,当你将 webkitgtk 应用与你的工程时,下面的配置将会排除测试文件(不会从源码目录拷贝这些文件到 build 目录)。

WEBKITGTK_OVERRIDE_SRCDIR = /home/bob/WebKit
WEBKITGTK_OVERRIDE_SRCDIR_RSYNC_EXCLUSIONS = \
        --exclude JSTests --exclude ManualTests --exclude PerformanceTests \
        --exclude WebDriverTests --exclude WebKitBuild --exclude WebKitLibraries \
        --exclude WebKit.xcworkspace --exclude Websites --exclude Examples

默认情况下,Buildroot 将不会同步 VCS 文件(比如: .git .svn 目录)。 一些包可能更倾向于引入这些文件(比如说在编译的时候鞋带上提交信息),此时,你可以使用如下方法将这些默认排除的文件添加回来。

LINUX_OVERRIDE_SRCDIR_RSYNC_EXCLUSIONS = --include .git

Chapter 9. Project-specific customization

通常情况下你给项目做的操作是:

  • 配置 Buildroot(包括构建选项和工具链、引导加载程序、内核、包和文件系统 image 类型选择)
  • 配置其他组建,比如 Linux 内核和 Busybox 等。
  • 自定义生成的文件系统 。

    • 添加或者覆盖目标文件系统上的文件 (使用 BR2_ROOTFS_OVERLAY)
    • 修改或者删除目标文件系统上的文件(使用 BR2_ROOTFS_POST_BUILD_SCRIPT
    • 生成文件系统 image 前执行预处理命令(使用BR2_ROOTFS_POST_BUILD_SCRIPT
    • 设置文件的归属和权限(读写执行等)(使用BR2_ROOTFS_DEVICE_TABLE
    • 添加自定义设备节点(使用BR2_ROOTFS_STATIC_DEVICE_TABLE
  • 添加自定义用户账户(使用 BR2_ROOTFS_USERS_TABLES
  • 在生成文件系统 image 前执行预处理命令(使用BR2_ROOTFS_POST_IMAGE_SCRIPT
  • 向指定包添加特定的补丁(使用 BR2_GLOBAL_PATCH_DIR
  • 添加特定项目的包

一个关于自定义 project-specific 的重要说明是: 请仔细考虑哪些更改确实是特定于项目的,哪些更改对项目外的开发人员也有用 . Buildroot 社区强烈推荐并鼓励向官方 Buildroot 项目提供改进、包和商业 Buildroot 项目的板级支持。 当然,有时不可能或也没有必要上传,因为这些变化是高度特定的或专有的。

本章描述如何定制客户自己的 Buildroot 项目,同时如何保存工程,从而,即便在执行 make clean 之后还是可以生成同样的固件, 通过一下建议的策略,你甚至可以在一个工程上支持多个板级的开发。

9.1. Recommended directory structure

当你将 Buildroot 项目应用于自定义项目的时候,你可能会创建一个或者多个存放在某处的工程。 大部分情况下这些工程的位置会在 Buildroot 里面配置,但是 Buildroot 的开发者还是对这些工程目录使用一些指定的结构。 本节将会介绍这部分内容。

下面是推荐的一个目录结构,你可以将该目录防止在 Buildroot 工程内部,也可以放在 Buildroot 工程外部(br2_external tree),这取决于你的选择。

+-- board/
|   +-- <company>/
|       +-- <boardname>/
|           +-- linux.config
|           +-- busybox.config
|           +-- <other configuration files>
|           +-- post_build.sh
|           +-- post_image.sh
|           +-- rootfs_overlay/
|           |   +-- etc/
|           |   +-- <some file>
|           +-- patches/
|               +-- foo/
|               |   +-- <some patch>
|               +-- libbar/
|                   +-- <some other patches>
|
+-- configs/
|   +-- <boardname>_defconfig
|
+-- package/
|   +-- <company>/
|       +-- Config.in (if not using a br2-external tree)
|       +-- <company>.mk (if not using a br2-external tree)
|       +-- package1/
|       |    +-- Config.in
|       |    +-- package1.mk
|       +-- package2/
|           +-- Config.in
|           +-- package2.mk
|
+-- Config.in (if using a br2-external tree)
+-- external.mk (if using a br2-external tree)
+-- external.desc (if using a br2-external tree)

本章将进一步提供有关上述文件的详细信息。

注意:如果你选择将此结构放置于 Buildroot 工程之外但是位于 br2-external tree 中时, <company> 和和可能需要的 <boardname> 组件是多余的,可以省略。

9.1.1. Implementing layered customizations

用户有几个相关联的项目需要进行同样的定制化是一个非常普遍的事情。想比喻复制这些定制化的项目,我们更推荐使用分层的方法来区分项目中不同的部分。

Buildroot 中几乎所有可用的自定义方法,如 post-build scripts 和 root filesystem overlays,都接受以空格分隔的项目列表。 指定的项目总是按顺序处理,从左到右。 通过创建多个这样的项目,一个用于通用自定义,另一个用于真正项目特定的自定义,您可以避免不必要的重复。 每个层通常由 board/<company> 内的单独目录体现。 根据您的项目,您甚至可以引入两个以上的层。

下面是一个拥有两个定制层(common fooboard)的例子:

+-- board/
    +-- <company>/
        +-- common/
        |   +-- post_build.sh
        |   +-- rootfs_overlay/
        |   |   +-- ...
        |   +-- patches/
        |       +-- ...
        |
        +-- fooboard/
            +-- linux.config
            +-- busybox.config
            +-- <other configuration files>
            +-- post_build.sh
            +-- rootfs_overlay/
            |   +-- ...
            +-- patches/
                +-- ...

比如,如果用户设置 BR2_GLOBAL_PATCH_DIR 为:

BR2_GLOBAL_PATCH_DIR="board/<company>/common/patches board/<company>/fooboard/patches"

第一个 patch 从 common 层引入,接下来的补丁则从 fooboard 层引入。

9.2. Keeping customizations outside of Buildroot

如之前 Section 9.1, “Recommended directory structure” 中所提到的,你可以将你的定制化项目存放在两个位置:

  • 直接放在 Buildroot 工程目录树中,通常会使用版本管理工具在一个分支上维护定制化的改动,这样可以很方便的升级 Buildroot.
  • 防止在 Buildroot 工程目录之外,使用 br2-external 机制, 该机制在允许保持包的清单,板级物料和配置文件都存放在 Buildroot tree 之外的同时,还能很好的将他们集成到构建逻辑中。 我们称这样的一个目录树为 br2-external tree。 本章解释 br-external tree 中有那些物料,和如何使用 br2-external 机制。

一个同志 Buildroot 使用一个或者多个 br2-external tree 的方法是,将 br2-external tree 的路径集合赋值给变量 BR2_EXTERNAL, 它将传递给任何 make 调用,调用之后将会将该 br2-external tree 的配置保存到输出(output)目录的隐藏文件 .br2-external.mk 中。 由此,buildroot 并不需要每一次编译建构都将 BR2_EXTERNAL 的配置都加载一遍, 但是,你还是可以通过修改 BR2_EXTERNAL 为新的值或者赋值为空来修改或者删除 br2-external tree 配置。

注意:  br2-external tree 的配置路径可以为相对路径也可以是绝对路径,但在加载之后都会被解释称绝对路径, 但需要注意的是,相对路径是相对 buildroot 住工程更目录来做为参考的,而 不是 输出目录作为参考的。

注意  如果你使用的是 Buildroot 2016.11 以前的版本,你需要先转换一下才能够在 2016.11 及以后的版本中使用它们, 参考 Section 27.1, “Migrating to 2016.11” 获得更多帮助信息。

一些例子:

buildroot/ $ make BR2_EXTERNAL=/path/to/foo menuconfig

从执行此命令以后, /path/to/foo 位置的 br2-external tree 将会被引用。

buildroot/ $ make
buildroot/ $ make legal-info

我们可以修改替换成另外的 br2-external tree。

buildroot/ $ make BR2_EXTERNAL=/where/we/have/bar xconfig

我们同样可以使用多个 br2-external trees:

buildroot/ $ make BR2_EXTERNAL=/path/to/foo:/where/we/have/bar menuconfig

或者终止使用任何 br2-external tree:

buildroot/ $ make BR2_EXTERNAL= xconfig

9.2.1. Layout of a br2-external tree

一个 br2-external tree 必须包含至少下面的三个文件:

  • external.desc
  • external.mk
  • Config.in

br2-external tree 除了必须包含这些强制性的文件,还可以包含一些其他的一些可选物料,如 configs/ 或者 provides/ 目录。它们也将会在接下来的几章介绍。

一个完整的 br2-external tree 的布局( layout )也会被介绍。

The external.desc file

external.desc 文件记录了 br2-external tree 的 namedescription

该文件的格式是基于行的,每行以一个关键字(Key)开头,后跟一个冒号和一个或多个空格,后跟分配给该关键字的值。 目前公认的关键词有两个:

  • name(mandatory / 强制):该字段定义了 br2-external tree 的名称,这里的名字必须使用 ASCII 字符集中的 [A-Za-z0-9_] 子集,其他的字符都是不允许的。 Buildroot 将 BR2_EXTERNAL_$(NAME)_PATH 变量设置为绝对路径,因此你可以使用该变量访问到你的 br2-external tree。 该变量同样可在 Kconfig 中起作用,因此你也可以通过该变量访问在您的 br2-external 工程中的 Kconfig, Makefile 或者其他文件。

    Note:  由于可以同时使用多个 br2-external tree,因此 Buildroot 使用此名称为这些树中的每一个生成变量。 该名称用于标识您的 br2-external tree,因此你需要确定一个真正描述您的 br2-external tree 的名称,以使其相对唯一,以免与来自另一个 br2-external tree 的名称发生冲突, 特别是如果您计划以某种方式与第三方共享您的 br2-external tree 或使用来自第三方的 br2-external tree 的时候。

  • desc(optional/ 可选),该字段为您的 br-exterbn 提供了一个简短的描述,该描述最好在一行内完成,没有固定一种格式(下面会介绍), 该字段将在展示 br2-external tree 的时候用到(比如:列举 defconfig 文件的时候或者执行 make menuconfig 的时候), 因此,该描述最好限制在 40 个字节以内。 此外该描述也可通过 BR2_EXTERNAL_$(NAME)_DESC 变量来访问。

下面是一个 br2-external trees 的 name 和其关联的 BR2_EXTERNAL_$(NAME)_PATH 变量的例子:

  • FOOBR2_EXTERNAL_FOO_PATH
  • BAR_42BR2_EXTERNAL_BAR_42_PATH

在接下来的例子中,我们假设 br2-external tree 的名字设置为 BAR_42

注意:  BR2_EXTERNAL_$(NAME)_PATHBR2_EXTERNAL_$(NAME)_DESC 变量在 Kconfig 和 Makefiles 文件中可用, 而且在执行 post-build, post-image, in-fakeroot 脚本的时该变量也被 export

The Config.in and external.mk files

这些文件(可能是空文件)可用于定义包的清单(比如像 Buildroot 内置的 foo/Config.infoo/foo.mk )或者其他客户自定义的 make 逻辑。

Buildroot 会 从 br2-external tree 自动包含 Config.in,并会在 make menuconfig 的最高级菜单显示, 并从 br2-external tree 的 external.mk 的文件中提取出其他的 makefile 构建整个工程配置框架。

这个文件主要用于存储包的配置清单。写 Config.in 的一个推荐做法如下:

source "$BR2_EXTERNAL_BAR_42_PATH/package/package1/Config.in"
source "$BR2_EXTERNAL_BAR_42_PATH/package/package2/Config.in"

然后 external.mk 文件如下:

include $(sort $(wildcard $(BR2_EXTERNAL_BAR_42_PATH)/package/*/*.mk))

然后,在 $(BR2_EXTERNAL_BAR_42_PATH)/package/package1$(BR2_EXTERNAL_BAR_42_PATH)/package/package2 创建一个通用的 Buildroot package 清单, 该清单还会在 Chapter 18, Adding new packages to Buildroot 做详细解释。 如果你喜欢,你还可以将所有的 packages 放到一个名为 <boardname> 的子目录,并相应的调整上述路径。

你也可以在 Config.in 自定义一些选项,并且在 external.mk 创建一些自定义的 make 逻辑。

The configs/ directory

你可以将自定义的一些 defconfigs 保存到 br2-external tree 的 configs 子目录中, 当你在 BR 中执行 make list-defconfigs 时会输出这个目录中的相应配置文件。 并且你也可以通过执行 make <name>_defconfig 来加载之。 在 make list-defconfigs 的输出中,br2-external tree 的 defconfig 将会输出在 External configs 下方。

注意:  如果一个 defconfig 文件有可能出现在多个 br2-external tree 中,那么只有最后一个 br2-external tree 中的配置会生效。 因此你也可以利用这条规则覆盖 buildroot 原生配置(或者另外的 br2-external tree 中的配置)。

The provides/ directory

对于某些包,Buildroot 提供了两个或者更多的 API 兼容的实现方式,比如 libjpeg 或者 jpeg-turbo,openssl 或者 libressl, there is one to select one of the known, pre-configured toolchains…

br2-external 可以通过提供一组定义这些替代方案的文件来扩充这些选择:

  • provides/toolchains.in 定义 pre-configured toolchains,这里的选项将会出现在 toolchain 选项中;
  • provides/jpeg.in 定义可选的 libjpeg 实现;
  • provides/openssl.in 定义可选的 openssl 实现;
  • provides/skeleton.in 定义可选的 skeleton 实现;
  • provides/init.in 定义可选的 init system 实现,这可以为你的启动工具选择默认的 skeleton;

Free-form content

你可以将所有的 board-specific 配置保存在此处(比如:内核配置,rootfs overlay(rootfs 的覆盖文件),或者任何其他配置文件),存在于该处的文件都可以通过 BR2_EXTERNAL_$(NAME)_PATH 来指定或者访问, 比如,你可以通过如下方式来设置全局的补丁目录,rootfs overlay 和内核配置(可以通过 make menuconfig 来修改这些配置):

BR2_GLOBAL_PATCH_DIR=$(BR2_EXTERNAL_BAR_42_PATH)/patches/
BR2_ROOTFS_OVERLAY=$(BR2_EXTERNAL_BAR_42_PATH)/board/<boardname>/overlay/
BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE=$(BR2_EXTERNAL_BAR_42_PATH)/board/<boardname>/kernel.config

Additional Linux kernel extensions

如果你有其他的 Linux 扩展(参考 Section 18.21.2, “linux-kernel-extensions”) 可以存储在 br2-external tree 的 linux/ 目录添加到工程中,

Example layout

下面是一个使用 br2-external tree 完整例子的目录树 (这个例子包含上面描述的内容,但这个例子仅仅是一个演示)

/path/to/br2-ext-tree/
  |- external.desc
  |     |name: BAR_42
  |     |desc: Example br2-external tree
  |     `----
  |
  |- Config.in
  |     |source "$BR2_EXTERNAL_BAR_42_PATH/toolchain/toolchain-external-mine/Config.in.options"
  |     |source "$BR2_EXTERNAL_BAR_42_PATH/package/pkg-1/Config.in"
  |     |source "$BR2_EXTERNAL_BAR_42_PATH/package/pkg-2/Config.in"
  |     |source "$BR2_EXTERNAL_BAR_42_PATH/package/my-jpeg/Config.in"
  |     |
  |     |config BAR_42_FLASH_ADDR
  |     |    hex "my-board flash address"
  |     |    default 0x10AD
  |     `----
  |
  |- external.mk
  |     |include $(sort $(wildcard $(BR2_EXTERNAL_BAR_42_PATH)/package/*/*.mk))
  |     |include $(sort $(wildcard $(BR2_EXTERNAL_BAR_42_PATH)/toolchain/*/*.mk))
  |     |
  |     |flash-my-board:
  |     |    $(BR2_EXTERNAL_BAR_42_PATH)/board/my-board/flash-image \
  |     |        --image $(BINARIES_DIR)/image.bin \
  |     |        --address $(BAR_42_FLASH_ADDR)
  |     `----
  |
  |- package/pkg-1/Config.in
  |     |config BR2_PACKAGE_PKG_1
  |     |    bool "pkg-1"
  |     |    help
  |     |      Some help about pkg-1
  |     `----
  |- package/pkg-1/pkg-1.hash
  |- package/pkg-1/pkg-1.mk
  |     |PKG_1_VERSION = 1.2.3
  |     |PKG_1_SITE = /some/where/to/get/pkg-1
  |     |PKG_1_LICENSE = blabla
  |     |
  |     |define PKG_1_INSTALL_INIT_SYSV
  |     |    $(INSTALL) -D -m 0755 $(PKG_1_PKGDIR)/S99my-daemon \
  |     |                          $(TARGET_DIR)/etc/init.d/S99my-daemon
  |     |endef
  |     |
  |     |$(eval $(autotools-package))
  |     `----
  |- package/pkg-1/S99my-daemon
  |
  |- package/pkg-2/Config.in
  |- package/pkg-2/pkg-2.hash
  |- package/pkg-2/pkg-2.mk
  |
  |- provides/jpeg.in
  |     |config BR2_PACKAGE_MY_JPEG
  |     |    bool "my-jpeg"
  |     `----
  |- package/my-jpeg/Config.in
  |     |config BR2_PACKAGE_PROVIDES_JPEG
  |     |    default "my-jpeg" if BR2_PACKAGE_MY_JPEG
  |     `----
  |- package/my-jpeg/my-jpeg.mk
  |     |# This is a normal package .mk file
  |     |MY_JPEG_VERSION = 1.2.3
  |     |MY_JPEG_SITE = https://example.net/some/place
  |     |MY_JPEG_PROVIDES = jpeg
  |     |$(eval $(autotools-package))
  |     `----
  |
  |- provides/init.in
  |     |config BR2_INIT_MINE
  |     |    bool "my custom init"
  |     |    select BR2_PACKAGE_MY_INIT
  |     |    select BR2_PACKAGE_SKELETON_INIT_MINE if BR2_ROOTFS_SKELETON_DEFAULT
  |     `----
  |
  |- provides/skeleton.in
  |     |config BR2_ROOTFS_SKELETON_MINE
  |     |    bool "my custom skeleton"
  |     |    select BR2_PACKAGE_SKELETON_MINE
  |     `----
  |- package/skeleton-mine/Config.in
  |     |config BR2_PACKAGE_SKELETON_MINE
  |     |    bool
  |     |    select BR2_PACKAGE_HAS_SKELETON
  |     |
  |     |config BR2_PACKAGE_PROVIDES_SKELETON
  |     |    default "skeleton-mine" if BR2_PACKAGE_SKELETON_MINE
  |     `----
  |- package/skeleton-mine/skeleton-mine.mk
  |     |SKELETON_MINE_ADD_TOOLCHAIN_DEPENDENCY = NO
  |     |SKELETON_MINE_ADD_SKELETON_DEPENDENCY = NO
  |     |SKELETON_MINE_PROVIDES = skeleton
  |     |SKELETON_MINE_INSTALL_STAGING = YES
  |     |$(eval $(generic-package))
  |     `----
  |
  |- provides/toolchains.in
  |     |config BR2_TOOLCHAIN_EXTERNAL_MINE
  |     |    bool "my custom toolchain"
  |     |    depends on BR2_some_arch
  |     |    select BR2_INSTALL_LIBSTDCPP
  |     `----
  |- toolchain/toolchain-external-mine/Config.in.options
  |     |if BR2_TOOLCHAIN_EXTERNAL_MINE
  |     |config BR2_TOOLCHAIN_EXTERNAL_PREFIX
  |     |    default "arch-mine-linux-gnu"
  |     |config BR2_PACKAGE_PROVIDES_TOOLCHAIN_EXTERNAL
  |     |    default "toolchain-external-mine"
  |     |endif
  |     `----
  |- toolchain/toolchain-external-mine/toolchain-external-mine.mk
  |     |TOOLCHAIN_EXTERNAL_MINE_SITE = https://example.net/some/place
  |     |TOOLCHAIN_EXTERNAL_MINE_SOURCE = my-toolchain.tar.gz
  |     |$(eval $(toolchain-external-package))
  |     `----
  |
  |- linux/Config.ext.in
  |     |config BR2_LINUX_KERNEL_EXT_EXAMPLE_DRIVER
  |     |    bool "example-external-driver"
  |     |    help
  |     |      Example external driver
  |     |---
  |- linux/linux-ext-example-driver.mk
  |
  |- configs/my-board_defconfig
  |     |BR2_GLOBAL_PATCH_DIR="$(BR2_EXTERNAL_BAR_42_PATH)/patches/"
  |     |BR2_ROOTFS_OVERLAY="$(BR2_EXTERNAL_BAR_42_PATH)/board/my-board/overlay/"
  |     |BR2_ROOTFS_POST_IMAGE_SCRIPT="$(BR2_EXTERNAL_BAR_42_PATH)/board/my-board/post-image.sh"
  |     |BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="$(BR2_EXTERNAL_BAR_42_PATH)/board/my-board/kernel.config"
  |     `----
  |
  |- patches/linux/0001-some-change.patch
  |- patches/linux/0002-some-other-change.patch
  |- patches/busybox/0001-fix-something.patch
  |
  |- board/my-board/kernel.config
  |- board/my-board/overlay/var/www/index.html
  |- board/my-board/overlay/var/www/my.css
  |- board/my-board/flash-image
  `- board/my-board/post-image.sh
        |#!/bin/sh
        |generate-my-binary-image \
        |    --root ${BINARIES_DIR}/rootfs.tar \
        |    --kernel ${BINARIES_DIR}/zImage \
        |    --dtb ${BINARIES_DIR}/my-board.dtb \
        |    --output ${BINARIES_DIR}/image.bin
        `----

该 br2-external tree 将会在 menuconfig 中可见 ,如下所示:

External options  --->
    *** Example br2-external tree (in /path/to/br2-ext-tree/)
    [ ] pkg-1
    [ ] pkg-2
    (0x10AD) my-board flash address

如果你使用超过一个 br2-external tree,那么 menuconfig 的输出将会像下面这样(假设第二个的名字是 FOO_27 但是在 external.desc 中没有 desc: 字段):

External options  --->
    Example br2-external tree  --->
        *** Example br2-external tree (in /path/to/br2-ext-tree)
        [ ] pkg-1
        [ ] pkg-2
        (0x10AD) my-board flash address
    FOO_27  --->
        *** FOO_27 (in /path/to/another-br2-ext)
        [ ] foo
        [ ] bar

此外,jpeg provider 也将出现在 jpeg 的选择列表中:

Target packages  --->
    Libraries  --->
        Graphics  --->
            [*] jpeg support
                jpeg variant ()  --->
                    ( ) jpeg
                    ( ) jpeg-turbo
                        *** jpeg from: Example br2-external tree ***
                    (X) my-jpeg
                        *** jpeg from: FOO_27 ***
                    ( ) another-jpeg

Toolchain 中的配置也类似:

Toolchain  --->
    Toolchain ()  --->
        ( ) Custom toolchain
            *** Toolchains from: Example br2-external tree ***
        (X) my custom toolchain

注意:  toolchain 的选项 toolchain/toolchain-external-mine/Config.in.options 将不会出现在 Toolchain 的菜单中, 它们必须显式的包含在 br2-external 的顶级 Config.in 中,而配置则会出现在 External options 菜单中 .

9.3. Storing the Buildroot configuration

Buildroot 的配置可一执行 make savedefconfig 来存储。

这将会在当前配置的基础上删除 Buildroot 的默认配置。该配置保存在名为 defconfig 的文件中,如果你想将此文件保存于其他地方,你可以修改 Buildroot 中的 BR2_DEFCONFIG 配置项, 或者执行 make savedefconfig BR2_DEFCONFIG=<path-to-defconfig> 来修改。

推荐的保存位置为 configs/<boardname>_defconfig。 如果你跟随该建议,那么嘎配置将会在执行 make help 的时候展示出来, 并且也可通过 make <boardname>_defconfig 来加载。

此外,你还可以拷贝该文件到另外的地方,并且通过执行 make defconfig BR2_DEFCONFIG=<path-to-defconfig-file> 重建。

9.4. Storing the configuration of other components

更改了 BusyBox、Linux 内核、Barebox、U-Boot 和 uClibc 的配置文件应该被妥善存储起来。 对于这些组件中的每一个,都存在一个 Buildroot 配置选项以指向输入的配置文件, 例如 BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE。 如果要保存它们的配置,则需要将这些配置选项设置为要保存配置文件的路径,然后使用下面描述的 helper target 来存储配置。

Section 9.1, “Recommended directory structure” 所介绍的, 我们推荐将配置文件的保存在路径到 board/<company>/<boardname>/foo.config

请确保在配置 BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE 之前你已经在该目录创建好配置文件,否则 Buildroot 在试图访问该文件的时候会发生异常错误, 你可以通过执行 make linux-menuconfig 等命令来创建相应的配置文件。

Buildroot 提供一些 helper targets 来使保存配置文件变得更简单。

  • make linux-update-defconfig 保存 linux 配置文件到 BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE 指定的路径。 它通过删除默认配置来简化配置文件。但是这个方法仅仅在内核版本大于 2.6.33 时才起作用。 对于更早的内核版本,可以使用 make linux-update-config.
  • make busybox-update-config 保存 Busybox 配置文件到 BR2_PACKAGE_BUSYBOX_CONFIG 指定路径。
  • make uclibc-update-config 保存 uClibc 配置文件到 BR2_UCLIBC_CONFIG 指定位置。
  • make barebox-update-defconfig 保存 busybox 配置文件到 BR2_TARGET_BAREBOX_CUSTOM_CONFIG_FILE 指定文件。
  • make uboot-update-defconfig 保存 UBoot 配置文件到 BR2_TARGET_UBOOT_CUSTOM_CONFIG_FILE 指定路径。
  • 对于 at91bootstrap3, 没有提供 helper target 来帮助你配置,你需要手动配置 BR2_TARGET_AT91BOOTSTRAP3_CUSTOM_CONFIG_FILE

9.5. Customizing the generated target filesystem

除了通过 make *config 更改配置之外,还有一些其他方法可以自定义生成的目标文件系统。

两个推荐的做法是(可以一起作用),文件系统覆盖和后期脚本建构。

跟文件系统覆盖(Root filesystem overlays) (BR2_ROOTFS_OVERLAY)

跟文件系统覆盖的起作用原理是,在执行配置构建之后,将一个文件树(包含目录和文件)直接覆盖到目标根文件系统上。 如果要启用此机制,请在 Buildroot 配置文件中(或者通过 make menuconfig 的 System configuration 选项 )修改 BR2_ROOTFS_OVERLAY 只想源树(rootfs overlay source tree)。 你可以指派多个源树,只需要将源树的路径用逗号分割即可。 如果指定相对路径,它将相对于 Buildroot tree 的一级目录录而言的。 版本控制系统的隐藏目录(如.git.svn.hg等,或者名为.empty 的文件和以 结尾的文件)在拷贝时将会被排除。

BR2_ROOTFS_MERGED_USR 被使能,源树不应当包含 /bin , /lib or /sbin 等目录, 因为 Buildroot 将会创建其 symbolic links 到相应的 /usr 目录。 在这个情况下,如果想要替换某些程序或者库,你应该将他们放在 /usr/bin, /usr/sbin and /usr/lib 目录。

Section 9.1, “Recommended directory structure” 展示的,推荐放置源树的路径在 board/<company>/<boardname>/rootfs-overlay

构建后执行的脚本(后文以 Post-build scripts 表示) (BR2_ROOTFS_POST_BUILD_SCRIPT)

Post-build scripts 是一个 shell 脚本,该脚本在 Buildroot 编译了所有配置选择的软件之后,组建 rootfs image 之前运行, 如果想使用这个特性,你可以创建一个空格分割的脚本路径列表,并将之赋值给 System configuration 目录中的 BR2_ROOTFS_POST_BUILD_SCRIPT 变量, 如果你指定的相对路径,那么,该路径会被解析为 Buildroot 一级目录的路径。

使用该机制,你剋删除或者修改你目标文件系统中的任何文件。 但你应该谨慎的使用这些特性。无论什么时候你发现了属于特定包的文件发生了某些错误或者不需要的特性,你首先应该要做的是修复该包(程序),而不是使用该机制去清理。

Section 9.1, “Recommended directory structure” 中所描述的,保存这些脚本的推荐目录是 board/<company>/<boardname>/post_build.sh

post-build scripts 运行的时候将 Buildroot tree 工程一级目录作为当前的工作目录。 目标的文件系统路径会作为第一个参数传递给每个脚本。 如果配置选项 BR2_ROOTFS_POST_SCRIPT_ARGS 不为空,这些参数也将传递给脚本。 所有脚本都将传递完全相同的参数集,不能向每个脚本传递不同的参数集。

此外,你可以在脚本中使用如下环境变量:

  • BR2_CONFIG:指向 Buildroot .config 文件
  • CONFIG_DIR: 包含 .config 文件的目录
  • HOST_DIR, STAGING_DIR, TARGET_DIR: 参考 Section 18.5.2, “generic-package reference”
  • BUILD_DIR: 提取包并编译的目录
  • BINARIES_DIR: 所有二进制文件(或者镜像)保存的目录
  • BASE_DIR: the base output directory

下面三个是为目标文件系统的定制化方法,但是并不推荐使用。

直接修改目标文件系统。

对于临时的修改,你可以直接修改位于 output/target/ 处的目标文件系统,然后使用 make 重建镜像。

该方法允许你对目标文件系统做任何操作,但是如果使用 make clean 清理了工程,那么所有该目录下的改动都将会被清除(丢失)。 在某些情况下,清除是必要的,参考 Section 8.2, “Understanding when a full rebuild is necessary” 阅读详细信息。 因此这个方法仅对于快速测试适用:因为改动不会在 make clean 命令执行后依旧存在 。 一旦你确认了你的更改,你应当确保在执行 make clean 之前,你已经能够保证这些改动长期存在了,你可以使用文件系统覆盖(filesystem overlay )或者 post-build script 或者为某些某些软件包打上补丁。

客制化 target skeleton (BR2_ROOTFS_SKELETON_CUSTOM)

根文件系统 image 是从目标骨架(target skeleton)创建的,所有包都将自己的文件安装在上面。在构建和安装任何包之前,框架被复制到目标目录 output/target。 默认目标框架提供标准的 Unix 文件系统布局和一些基本的初始化脚本和配置文件。

如果默认框架(在 system/skeleton 下可用)不符合您的需求,您通常会使用根文件系统覆盖或后期构建脚本来调整它。 但是,如果默认骨架与您需要的完全不同,则使用自定义骨架可能更合适。

要启用此功能,请启用配置选项 BR2_ROOTFS_SKELETON_CUSTOM 并将 BR2_ROOTFS_SKELETON_CUSTOM_PATH 设置为自定义骨架的路径。 Systen configuration 菜单中提供了这两个选项。 如果指定相对路径,则它将相对于 Buildroot 树的根。

克制化 skeletons 并不需要包含 /bin /lib 或者 /sbin 等文件, 因为这些文件会在建构的时候自动创建。 而且当你使能 BR2_ROOTFS_MERGED_USR 配置的时候,这些克制化的 skeleton 一定不能包含 /bin, /lib or /sbin 目录, 因为 Buildroot 会为这些目录创建软链接到 /usr 的相关目录。 在这一情况下,如果你想要预置一些二进制可执行文件或者库到工程中,你应该将之放置到 /usr/bin, /usr/sbin/usr/lib 目录。

不建议使用此方法,因为它会存在两个完整的 skeleton,这会导致 Buildroot 在以后针对默认 skeleton 进行修复和改进的时候你无法分享其红利。

Post-fakeroot scripts (BR2_ROOTFS_POST_FAKEROOT_SCRIPT)

在聚合最终 image 时,执行该过程的的途中某些部分需要 root 权限:比如在 /dev 中创建设备节点,设置文件和目录的权限或所有权……为了避免需要实际的 root 权限, Buildroot 使用 fakeroot 来模拟 root 权限。 这并不能完全替代实际成为 root 用户,但足以满足 Buildroot 的需求。

Post-fakeroot 脚本是一个 shell 脚本,这个脚本在 fakeroot 阶段之后, 从文件系统到处 image 之前被执行,

如果您需要调整文件系统以进行通常仅对 root 用户可用的修改,则 post-fakeroot 脚本会很有用。

注意:  我们还是建议您用现有的机制来创建 /dev (参考:Section 9.5.1, “Setting file permissions and ownership and adding custom devices nodes”), 或创建用户(参考: Section 9.6, “Adding custom user accounts”

注意:  post-build 脚本和 fakeroot 脚本的区别在于,post-build 并不是在 fakeroot 的上下文中运行。

注意: 使用 fakeroot 并不是创建一个 root 类型的文件,普通用户也是不能够实现的,该脚本仅仅是在内存中伪造文件系统权限和类型(常规,块,字符或设备)和 uid/gid 等。

9.5.1. Setting file permissions and ownership and adding custom devices nodes

有时需要在文件或设备节点上设置特定的权限( permissions )或所有权( ownership )。 例如,某些文件可能需要由 root 拥有。 由于构建后脚本不是以 root 身份运行的,因此您不能从那里进行此类更改,除非您在 post-build 中使用显式的 fakeroot。

相反,Buildroot 提供了一个明为 permission tables 的机制。 一个服从 makedev syntax 语法的通用文本文件。

如果你使用静态设备列表(也就是:不使用 devtmpfs, mdev, or (e)udev)那么你就可以使用同 device tables 的语法。 如果要使用这个特性,那么将您的 device tables 文件路径以空格区分的形式赋值给 BR2_ROOTFS_STATIC_DEVICE_TABLE 选项即可。

Section 9.1, “Recommended directory structure” 所介绍的,我们推荐保存该设备列表的位置为 board/<company>/<boardname>/

需要注意的是指定的权限和设备节点如果和指定程序(比如 FOO )相关的话,你应该在 .mk 中设置去设置包的变量 FOO_PERMISSIONSFOO_DEVICES , (参考 Section 18.5.2, “generic-package reference” 获取更多信息)。

9.6. Adding custom user accounts

有时候我们需要为目标系统添加一些指定用户。为了覆盖这部分需求, buildroot 提供了名为 users tables 的机制。 若想使用此功能,可以将符合固定格式的文件列表字符串复制给 BR2_ROOTFS_USERS_TABLES 即可,列表中文件以空格分割,文件格式请参考 makeusers syntax

Section 9.1, “Recommended directory structure” 介绍,我们推荐将这些文件存放在 board/<company>/<boardname>/ 目录。

需要注意的是,如果你指定的用户与某些应用相关,你应该在包的 .mk 文件中指定用户(设置 FOO_USERS)(参考Section 18.5.2, “generic-package reference”)。

9.7. Customization after the images have been created

post-build 脚本 (Section 9.5, “Customizing the generated target filesystem”) 在构建文件系统镜像,kernel,bootloader 之前运行。 post-image 脚本 可以在所有的 image 被创建之后执行一些指定操作。

比如,Post-image 脚本可以在你构建玩整个镜像之后将你的文件系统自动打包上传到你的 NFS 服务器, 或者任何你工程需要的克制化的动作。

如果要使用此特性,你可以将一个 post-image 列表赋值给 System configuration 选项中的 BR2_ROOTFS_POST_IMAGE_SCRIPT 变量。 如果你指定的是一个相对路径,那么该路径是相对 Buildroot 文件系统跟路径而言的。

和 post-build 脚本一样,post-image 脚本在运行时也以 Buildroot 树为当前工作目录。 指向 images 的路径将作为该脚本的第一个参数。如果 BR2_ROOTFS_POST_SCRIPT_ARGS 配置并不为空,那么该变量中保存的参数也将作为该脚本的参数被引入。 目前还不支持给每一个脚本定制一个参数集合。

还是和 post-build 一样,你可以在该脚本中使用如下环境变量: BR2_CONFIG, HOST_DIR, STAGING_DIR, TARGET_DIR, BUILD_DIR, BINARIES_DIR, CONFIG_DIR and BASE_DIR

该脚本应该由执行 Buildroot 构建过程的用户调用,不应该是 root 用户。因此,如果这些脚本中有一些 action 需要 root 权限则应该 fakeroot 或者 sudo 等机制,这些工作你应该交给脚本工程师处理。

9.8. Adding project-specific patches

有时将 extra 补丁应用于包很有用 -- 在 Buildroot 中提供的补丁之上再打补丁。 这可能用于支持项目中的自定义功能,例如,或在处理新架构时。

选项 BR2_GLOBAL_PATCH_DIR 可用于指定一组空格分开的目录列表,该目录中存在包的补丁。

对于指定 <packageversion> <packagename> 的软件包,补丁将会如以下顺序应用:

  1. 对于每一个 BR2_GLOBAL_PATCH_DIR 中定义的 <global-patch-dir> 目录,<package-patch-dir> 将会按照如下规则遍历:

    • 应用 <global-patch-dir>/<packagename>/<packageversion>/ 中的补丁,如果该目录存在;
    • 否则应用 <global-patch-dir>/<packagename> 中的补丁,如果该目录存在的情况下
  2. 存在于 <package-patch-dir> 中的补丁将会按照如下规则引用:

    • 如果一个 series 文件存在于包目录,则 patch 将会根据 series 文件描述的顺序加载;
    • 否则,patch 会以符合 *.patch 的字母(alphabetical)顺序被应用。 因此,为了确保他们有正确的顺序,我们极力推荐将 patch 文件名命名为如下格式: <number>-<description>.patch, 这里的 <number> 参考 patch 的应用顺序;

关于如何将补丁应用到包中的更多信息,请参考 Section 19.2, “How patches are applied”

BR2_GLOBAL_PATCH_DIR 选项是为包指定自定义补丁目录的首选方法。 它可用于为 buildroot 中的任何包指定补丁目录。 它还应该用于代替可用于 U-Boot 和 Barebox 等软件包的自定义补丁目录选项。 通过这样做,它将允许用户从一个顶级目录管理他们的补丁。

BR2_GLOBAL_PATCH_DIR 作为指定自定义补丁的首选方法的例外是 BR2_LINUX_KERNEL_PATCHBR2_LINUX_KERNEL_PATCH 应该用于指定在 URL 上可用的内核补丁。 注意: BR2_LINUX_KERNEL_PATCH 指定在 BR2_GLOBAL_PATCH_DIR 中可用的补丁之后应用的内核补丁,因为它 是从 Linux 包的 post-patch hook 完成的。

9.9. Adding project-specific packages

正常情况下,任何新的包都应该直接添加到 package 目录中,并从 upstream 中获取,如何向 Buildroot 中添加包已经在 Chapter 18, Adding new packages to Buildroot 解释得非常清楚了。 然而,你的工程任然可能需要一些 proprietary packages, 这些 proprietary packages 是不能被 upstreamed 的。 本节将解释如何将此类特定于项目的包保存在特定于项目的目录中。

Section 9.1, “Recommended directory structure” 介绍,指定的项目(project-specific)包我们推荐存放在package/<company>/ 目录,如果你使用了 br2-external tree 特性 (参考 Section 9.2, “Keeping customizations outside of Buildroot”) 推荐存放此类项目的地址为 br2-external tree 的 package/ 的目录内。

然而,Buildroot 也不知道这个包在哪个位置,除非我们执行一些额外的步骤。想 Chapter 18, Adding new packages to Buildroot 中解释的那样,一个 Buildroot 中的 package 信息基本由两个部分组成:一个 .mk 文件(描述如何去构建包),和一个 Config.in 文件 (描述该 package 中有哪些配置选项).

Buildroot 将会自动的包含工程更目录下子目录 package.mk 文件(符合 package/*/*.mk pattern 的文件 ), 如果你想让 Buildroot 识别到更深子目录中的 .mk 文件 (比如 package/<company>/package1/) 那么我们只需在工程根目录添加一个 .mk 文件即可,该文件中包含那些深层目录中的 .mk 文件的位置。 因此,创建一个 package/<company>/<company>.mk 文件包含如下内容(假设你仅仅需要添加一个位于 package/<company>/ 目录的工程 );

include $(sort $(wildcard package/<company>/*/*.mk))

对于 Config.in 文件,则需要创建一个 package/<company>/Config.in 文件,该文件包含所有你想要增加 package 的 Config.in 文件。 因为 kconfig 并不支持通配符,因此你必须提供一个详细的列表。例如:

source "package/<company>/package1/Config.in"
source "package/<company>/package2/Config.in"

package/Config.in 中包含 package/<company>/Config.in 文件, 为了方便日后 Buildroot 版本升级,该文件最好在 company-specific menu 中。

如果使用 br2-external tree,请参考 Section 9.2, “Keeping customizations outside of Buildroot” 获得如何使用这些文件的方法。

9.10. Quick guide to storing your project-specific customizations

本章前面已经描述了几种用于客制化的不同方法,本小节将会总结一下之前提到的方法,并一步一步说明如何实现, 因此,您可以跳过与您的项目无关的步骤。

  1. make menuconfig 配置 toolchain, packages 和内核。
  2. make linux-menuconfig 用于更新内核配置,和其他某些软件包类似,如: Busybox, ulibc, ...
  3. mkdir -p board/<manufacturer>/<boardname>
  4. 将如下选项设置到 board/<manufacturer>/<boardname>/<package>.config 中 (只要于他们相关):

    • BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE
    • BR2_PACKAGE_BUSYBOX_CONFIG
    • BR2_UCLIBC_CONFIG
    • BR2_TARGET_AT91BOOTSTRAP3_CUSTOM_CONFIG_FILE
    • BR2_TARGET_BAREBOX_CUSTOM_CONFIG_FILE
    • BR2_TARGET_UBOOT_CUSTOM_CONFIG_FILE
  5. 设置如下配置文件:

    • make linux-update-defconfig
    • make busybox-update-config
    • make uclibc-update-config
    • cp <output>/build/at91bootstrap3-*/.config board/<manufacturer>/<boardname>/at91bootstrap3.config
    • make barebox-update-defconfig
    • make uboot-update-defconfig
  6. 创建 board/<manufacturer>/<boardname>/rootfs-overlay/ 目录,并把你想要追加到 rootfs 的文件放入相应位置。 比如: board/<manufacturer>/<boardname>/rootfs-overlay/etc/inittab。 之后设置 BR2_ROOTFS_OVERLAYboard/<manufacturer>/<boardname>/rootfs-overlay.
  7. 创建一个 post-build 脚本 board/<manufacturer>/<boardname>/post_build.sh。 并设置 BR2_ROOTFS_POST_BUILD_SCRIPTboard/<manufacturer>/<boardname>/post_build.sh
  8. 如果有另外的权限需要设置,或者设备节点需要被创建,则创建 board/<manufacturer>/<boardname>/device_table.txt 文件,并将该目录设置到 BR2_ROOTFS_DEVICE_TABLE 中。
  9. 如果要增加另外的用户,则创建 board/<manufacturer>/<boardname>/users_table.txt 文件,并将之赋值给 BR2_ROOTFS_USERS_TABLES
  10. 如果要为某些 package 增加客制化补丁,将 board/<manufacturer>/<boardname>/patches/ 设置 BR2_GLOBAL_PATCH_DIR 选项中, 并将对应 package 的补丁放置到该目录下名为 package 名字的子目录下。每一个 patch 应该设置其名字为 <packagename>-<num>-<description>.patch
  11. 特别是对于 Linux 内核,还存在选项 BR2_LINUX_KERNEL_PATCH,其主要优点是它还可以从 URL 下载补丁。 如果你不需要这个,则 BR2_GLOBAL_PATCH_DIR 是一个更优的选择。 U-Boot、Barebox、at91bootstrap 和 at91bootstrap3 也有单独的选项,但这些选项与 BR2_GLOBAL_PATCH_DIR 相比没有任何优势,而且将来可能会被删除。
  12. 如果您需要添加特定于项目的包,请创建 package/<manufacturer>/ 并将您的包放在该目录中。 创建一个 <manufacturer>.mk 文件,其中包含所有包的 .mk 文件。 创建一个整体 Config.in 文件,该文件为所有包的 Config.in 文件提供源。 从 Buildroot 的 package/Config.in 文件中包含这个 Config.in 文件。
  13. make savedefconfig 保存 Buildroot 的配置.
  14. cp defconfig configs/<boardname>_defconfig 将该配置复制为你目标板级的配置,从而避免下一次保存覆盖。

Chapter 10. Using SELinux in Buildroot

SELinux 是一个强制执行内核访问控制策略的内核模块。 除了传统的文件访问权限和访问控制列表,SELinux 还允许为用户或者进程编写规则来访问特定的资源(文件/或者 sockets ...)

SELinux 拥有三种操作模式:

  • Disabled: 不使用策略中定义的规则
  • Permissive: 策略被应用,但未经授权的操作仅被简单地记录。 此模式通常用于对 SELinux 问题进行故障排除。
  • Enforcing: 使用策略中的规则,而且未经授权的操作都将被禁止。

在 Buildroot 中这些模式由变量 BR2_PACKAGE_REFPOLICY_POLICY_STATE_* 选项进行控制。 Linux Kernel 中也有一些配置选项可以影响 SELinux 的使能(参考 Linux kenel 中的 security/selinux/Kconfig ).

默认情况下 Buildroot 中的 SELinux 策略由 refpolicy 项目提供,由 BR2_PACKAGE_REFPOLICY 使能。

10.1. Enabling SELinux support

如要在 Buildroot 中支持 SELinux ,那么要将以下配置使能:

  • BR2_PACKAGE_LIBSELINUX
  • BR2_PACKAGE_REFPOLICY

此外,你选择的文件系统格式必须选择支持扩展属性。

10.2. SELinux policy tweaking

SELinux refpolicy 包含的模块可以在编译的时候使能或者禁止。 每一个 SELinux 的模块都包含数个规则, 同时,Buildroot 也提供了几种方法来使能或者禁止一些非基础模块。

  • <packagename>_SELINUX_MODULES 变量接受一个列表,可用于 enable refpolicy 中定义的 SELinux 模块
  • 同时包还提供了另外一些 SELinux 模块,通过将他们 (.fc, .if and .te 文件) 放在 package/<packagename>/selinux/ 来配置。
  • 此外,还可以在 BR2_REFPOLICY_EXTRA_MODULES_DIRS 选项中指定存放其他模块的目录。
  • 此外,还可以将 refpolicy 中列出的模块列表赋值给 BR2_REFPOLICY_EXTRA_MODULES_DEPENDENCIES 来启用。

Buildroot 同样支持完全替换 refpolicy。 这允许提供专为给定系统设计的完整自定义策略。 这样做时,上述所有机制都被禁用:其他配置的 SElinux 模块都不会被添加到策略中, 并且自定义策略中的所有可用模块都被启用并内置到最终的二进制策略中。 但请注意,自定义策略必须是官方 refpolicy 的分支。

如果想完全替换 refpolicy 你需要设置以下选项:

  • BR2_PACKAGE_REFPOLICY_CUSTOM_GIT
  • BR2_PACKAGE_REFPOLICY_CUSTOM_REPO_URL
  • BR2_PACKAGE_REFPOLICY_CUSTOM_REPO_VERSION

Chapter 11. Frequently Asked Questions & Troubleshooting

11.1. The boot hangs after Starting network…

如果在启动过程中出现以下消息之后挂起了(消息不一定要完全相似,这依赖于你选择了哪些依赖):

Freeing init memory: 3972K
Initializing random number generator... done.
Starting network...
Starting dropbear sshd: generating rsa key... generating dsa key... OK

这代表着你的系统在运行,但是 shell 可能并没有在串口终端(serial console)启用。 为了确保 system 启动后在串口终端运行 shell,你需要去 Buildroot 配置中,修改 System configurationRun a getty (login prompt) after boot 中配置, 并在子选项 getty options 指定好合适的端口和波特率。 这将自动生成 /etc/inittab 文件,以便 shell 可在正确的串口终端上启动。

11.2. Why is there no compiler on the target?

从 Buildroot-2012.11 开始, Buildroot 已经从目标版本上移除了本地编译器,因为:

  • 该功能既没有维护,也没有很好的测试,并且还经常发现存在缺陷。
  • 该功能仅适用于 Buildroot toolchain;
  • 大多数 Buildroot 的目标平台通常是小平台甚至是非常小的平台,它们有非常有限的资源(在 CPU, ram, mass-storage) 上, 在这种平台上执行编译,听起来就不合理。
  • Buildroot 旨在简化交叉编译,无需在目标上进行本地编译。

如果在你的系统上确实需要一个编译器,那么 buildroot 并不是一个适合你的工具。 在这种情况下,你可以选择一个 real distribution 工具, 类似下面的工具:

11.3. Why are there no development files on the target?

因为没有编译工具安装到目标系统上, 因此也并不需要浪费空间来存储 headers 或者 static libraries。

因此,自 2012.11 月以来,这些文件就一直从系统中删除。

11.4. Why is there no documentation on the target?

因为通常 Buildroot 的目标平台是 small 或者 very small 的硬件平台,其(CPU, ram, mass-storage)的资源通常都非常受限制,所以将文档类的数据存放在目标平台上也并不合理。

如果你无论如何都想要文档数据安装到你的目标平台上,Buildroot 也许也并不是你的合适工具,你应该找一些合适的 real distribution (参考: Section 11.2, “Why is there no compiler on the target?”)。

11.5. Why are some packages not visible in the Buildroot config menu?

如果一个包存在于 Buildroot 树中并且没有出现在配置菜单中,那很大可能这个包的依赖并没有满足。

如果想知道更多有关该包的信息,可以在 config menau 中搜索该包 (参考 Section 8.1, “ make tips”).

然后你可能发现,你需要递归的开启多个你直接依赖或者间接的依赖选项,才能使能你的 package.

由于某些包可能因为 toolchain 的一些选项而不可见,那么此时你应该完全重编整个工程 (参考 Section 8.1, “make tips” 获取更多信息).

11.6. Why not use the target directory as a chroot directory?

这里有几个不使用 chroot 的原因:

  • 文件的 ownerships, modes 和 permissions 设置不正确;
  • 设备节点不能被创建;

鉴于这些原因,使用目标目录作为新根目录通过 chroot 运行的命令很可能会失败。

如果您想在 chroot 中运行目标文件系统,或者作为 NFS 根运行,那么可以使用 images/ 中生成的 tarball 压缩包,并解压作为根使用。

11.7. Why doesn’t Buildroot generate binary packages (.deb, .ipkg…)?

关于 Buildroot 列表中一个经常被讨论到的主题是 ”package management“。 总而言之,我们的想法是,添加一些追踪 Buildroot package 安装了哪些文件的方法,目标是: with the goals of:

  • 当 package 从配置中删除(取消选择)的时候可以同时移除其安装的文件;
  • 可以在不重建整个文件系统镜像的情况下,生成一个二进制文件(ipk 或者其他格式)并将之安装到目标系统中;

通常情况下,大多数人很容易能想到的是:仅仅是追踪哪个包安装了那些文件,并在取消配置的时候删除这些安装文件。 但现实情况比这复杂得多:

  • 这不仅仅是要追踪 target/ 目录,而且还要追踪 host/<tuple>/sysroothost/ 目录. 各个 package 安装到这些目录的包都需要被追踪。
  • 当一个包从配置中移除的时候,我们不仅要做的是仅仅是移除其所依赖的文件,而是要连直接或者间接依赖此 package 的文件都需要被删除。 而且为了工程的完整性,还需要重建这些依赖包(因为有些依赖包在缺少部分依赖的时候还是可以使用的)。 比如: package A 选择性依赖于 openssl。而且两个都同时被配置/构建。 包 A 是使用 OpenSSL 构建的,支持加密。 稍后,OpenSSL 从配置中取消选择,但包 A 仍然存在(因为 OpenSSL 是一个可选的依赖项,这是可能的。)如果只删除 OpenSSL 文件,那么包 A 安装的文件就会损坏:它们使用的库是 不再出现在目标上。 虽然这在技术上是可行的,但它给 Buildroot 增加了很多复杂性,这与我们试图坚持的简单性背道而驰。
  • 除了前面的问题,还有一种情况是,Buildroot 甚至不知道有可选依赖项。 例如,1.0 版中的包 A 从未使用过 OpenSSL,但在 2.0 版中它会自动使用 OpenSSL(如果可用)。 如果 Buildroot .mk 文件没有被更新,以考虑到这一点,那么包 A 将不会成为 OpenSSL 的反向依赖项的一部分,并且不会在删除 OpenSSL 时被删除和重建。 当然,包 A 的 .mk 文件应该被修复,以包含该可选的依赖项,但当下,你可能会遇到不可重现的 Bug。
  • 还有请求是,允许将 menuconfig 中的更改动态应用于输出目录,而无需从头开始重建所有内容。 然而,这很难以可靠的方式实现:比如当包的子选项发生变化时会发生什么(我们必须检测到这一点,并从头开始重建包以及可能的所有反向依赖), 如果工具链选项发生变化会对当前工程产生什么影响, Buildroot 所做的事情是清晰而简单的,因此它的行为非常可靠,并且易于支持用户。 如果在 menuconfig 中修改了配置之后需要马上应用到下一次 make 中,那么它必须在所有情况下都能正常工作,并且不会出现一些奇怪的极端情况。 风险是获得错误报告,例如“我已启用包 A、B 和 C,然后运行 ​​make,然后禁用包 C 并启用包 D 并运行 make,然后重新启用包 C 并启用包 E,然后有一个构建失败”。 或者更糟糕的是“我做了一些配置,然后构建,然后做了一些更改,构建,更多更改,构建,更多更改,构建,现在它失败了,但我不记得我所做的所有更改以及更改顺序”。 而我们基本无法做到这样。(我觉得要做到还是可行的,不过会比较复杂,参考 archlinux 的包管理机制)

由于上述种种原因,通过添加跟踪机制,在一个包被移除(unselected)的时候删除其安装的文件,可执行程序,库,是一个非常难,而且不可考的事情,同时其非常复杂。

因此,Buildroot 的开发者们对此做出了自己的申明:

  • Buildroot 旨在让文件系统的生成(制作)变得容易(名为 Buidl root 也原于此),这就是我们想让 Buildroot 擅长的,建构根文件系统。
  • Buildroot 并不是想成为一个版本发行工具(版本生成器)。 Buildroot 的开发人员认为,这不是我们追求的目标,我们相信有其他更好的方案来作为版本发行工具,比如 Open Embedded, or openWRT 这类工具。
  • 我们更想将 buildroot 推向 “更方便制作跟文件系统工具” 的这条道路,这也是 Buildroot 从人群中脱颖而出的原因(当然还有一些其他原因)。
  • 我们相信,针对大多数嵌入式系统没,二进制包是不必要的,而且存在潜在的风险。 当一个二进制包被使用的时候, 当使用二进制包的时候,这通常意味着系统是可以部分升级的,这不同的二进制包版本会造成大量的组合,这都会需要在发布之前测试。 另一方面,一次性的升级整个文件系统 image ,这可以保证该系统是被测试验证通过的。

11.8. How to speed-up the build process?

由于 Buildroot 会涉及到整个系统的重建,这可能会很长,但我们有几个小技巧可以帮助你减少建构的时间。

  • 使用预先编译的 external toolchain 代替默认的 Buildroot 内置 toolchain。使用事先建构的 Linaro toolchain (ARM) 或者 Sourcery CodeBench toolchain (ARM, x86, x86-64, MIPS, etc.)。 你将会节省在每次完整编译的时候节省大量的时间,大约 20min. 注意:使用 external toolchain 并不会阻止你切换会 internal toolchain (有可能你想在开发完成之后还需要切换回 internal toolchain 进行建构)。
  • 使用 ccache 作为编译缓存 (参考: Section 8.14.3, “Using ccache in Buildroot”);
  • 了解你仅仅需要真正关心的几个包 (参考 Section 8.3, “Understanding how to rebuild packages”), 但有时候进行完整编译是必须的 (参考 Section 8.2, “Understanding when a full rebuild is necessary”);
  • 请确保你不是在一个 Linux 虚拟机上运行 Buildroot, 大部分虚拟i机技术会严重的降低 I/O 性能,而这对于构建源码是非常重要的。
  • 确保你建构中用到的文件都是本地文件,而不是 NFS 或者 NAS 上的文件,因为这回显著降低 build 速度。 如果本地的 download 目录(dl)中早已经存在编译过程中需要的源文件了,那么这也会对 build 的速度非常有帮助。
  • 购买一个新的硬件,HD 升级成 SSD, 扩大内存,升级 CPU 等。
  • 打开实验性质的并行编译,参考: Section 8.12, “Top-level parallel build”.

Chapter 12. Known issues

  • 如果选项 BR2_TARGET_LDFLAGS 中存在 $, Buildroot 也不会将之解析出来。 比如,接下来的选项将会失败 BR2_TARGET_LDFLAGS="-Wl,-rpath='$ORIGIN/../lib'"
  • SuperH 2 和 ARC 架构并不支持 libffi 软件包;
  • Sourcery CodeBench 中的 SuperH 4 编译器(2012.09) 编译 prboom 包将会失败;

Chapter 13. Legal notice and licensing

13.1. Complying with open source licenses

所有 Buildroot 的终端产品包含的开源软件(toolchain, root filesystem, kernel, bootloaders),都在各自的 licenses 下发布。

从众多的开源软件中选择合适的软件包,可以让您迅速的构建内容丰富的嵌入式系统,但在使用的过程中你也必须知道其软件包强加给你的条款( licenses)。 某些 license 要求您在产品文档中发布其 license 文档。还有一些要求您将软件的源代码重新分发给接收您的产品的人。

每个许可证的明确要求都记录在每个软件包中,您(或您的法办)有责任遵守这些要求。 为了您更加方便的查询,Buildroot 在你执行 make menuconfig, make xconfig or make gconfig 之后,可以从你的工程中收集一些你可能用得到的资料(物料),运行:

make legal-info

Buildroot 将会手机法务相关的资料并输出到你的 ${OUTPUT}/legal-info/ 目录中。 然后你可以找到以下文件:

  • README 文件总结了生成的资料(物料),同时也包含关于 Buildroot 无法生成的资料(物料)的警告。
  • buildroot.config:这是通常使用 make menuconfig 生成的 Buildroot 配置文件,它是重新建构时所必须的一个文件。
  • 所有目标平台和编译依赖的 host 的源码都被存放在 sources/host-sources/ 子目录内。 当然 <PKG>_REDISTRIBUTE = NO 配置过的包将不会被保存。 而每一个包应用到的 patch 也将会被保存,而且名为 series 的文件会按照应用的顺序记录各个补丁包。 补丁也服从对应包 license 中提到的提款。 注意:Buildroot 应用于 autotools-based 包的 Buildroot 应用于 autotools 的软件包的 Libtool 脚本的补丁,可在 Buildroot 源中的 support/libtool 下找到,由于技术限制,没有与包源一起保存。 您可能需要手动收集它们。
  • 有两个清单文件(一个用于主机,一个用于目标包),清单文件会列出配置的包、它们的版本、许可证和相关信息。 其中一些信息可能未在 Buildroot 中定义; 此类项目会被标记为 “unknown”。
  • 所有包的 lincense 文件都存在于 licenses/host-licenses/ 的相应目标内。 如果 Buildroot 中没有定义 license 文件则该不会生成该文件,并且会在 README 输出警告信息。

请注意,Buildroot 的 legal-info 的功能旨在生成所有包 License 中提到的和法律有关的文件。 Buildroot 并不会尝试生成你必须通过某种方式生成的文件。 当然,生成的资料会比需要严格遵守法律条文的资料多。 比如:对于类似 BSD 许可证下发布的源码,你并不需要以源码的形式重新发布。

更多的,在技术限制条件下,Buildroot 并不会生成你将要或者可能需要用到的资料,比如说 external toochain 的源码和 Buildroot 自己的源码等。 当你执行 make legal-info, Buildroot 会在 README 中提醒你,哪些可能资料将不会被保存。

最后,请记住 make legal-info 中的输出是基于每个包中的清单文件中的声明。 Buildroot 的开发者尽力保持这些声明性语句尽可能准确。 然而,这些声明是非常有可能不是精准和详尽的。 你(或者你的法务部门)在你的产品交付前,必须检查 make legal-info 输出的信息, 参考 Buildroot 发行版根目录中的 COPYING 文件中的免责条款。 (clauses 11 and 12)

13.2. Complying with the Buildroot license

Buildroot 是一个开源软件,在 GNU General Public License, version 2 或者更高版本下发布(除了下面列举到的补丁) 然而,作为一个构建系统,它通常不是终端产品的一部分:如果你是为你的设备开发跟文件系统,内核,bootloader 或者 toolchain,Buildroot 代码仅会出现在你的开发机器上,而不是设备存储中。

尽管如此,对于 Buildroot 开发人员的一般看法是,当发布包含 gpl 许可软件的产品时,应该将 Buildroot 源代码与其他包的源代码一起发布。 这是因为 GNU GPL 定义了对于 complete source code" 项目 " all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable ". Buildroot是脚本的一部分,该脚本用于控制可执行文件的编译和安装,因此它被认为是必须重新发布的材料的一部分。

请记住,这只是 Buildroot 开发者的观点,你应该考虑你们法务部门或者律师的任何意见和疑虑。

13.2.1. Patches to packages

Buildroot 同时还捆绑了补丁包,它们将应用于各种各样的包中。这些补丁并没有被 Buildroot 的 license 所覆盖。 相反,它们被所打补丁的软件(package)的 license 所覆盖。 当所述软件在多个许可下可用时,Buildroot补丁仅在公共访问许可下提供。

参考 Chapter 19, Patching a package 查看技术细节。

Chapter 14. Beyond Buildroot

14.1. Boot the generated images

14.1.1. NFS boot

如果要实现 NFD-boot,则需要使能 Filesystem images 中的 tar root filesystem 选项。

在完成编译之后,只需要运行以下命令则可以设置 NFS-root 目录:

sudo tar -xavf /path/to/output_dir/rootfs.tar -C /path/to/nfs_root_dir

记得将此路径加到 /etc/exports (NFS server export table) 文件中。

然后你可以在你的设备上执行 NFS 启动了。

14.1.2. Live CD

如果想要构建 Live CD 的 image ,需要在 Filesystem images 菜单中使能 iso image 选项。 注意:该选项仅仅在 x86 和 x86-64 架构上生效,而且如果你必须使用 Buildroot 来编译你的内核。

您可以使用 IsoLinux、Grub 或 Grub 2 作为引导加载程序构建 live CD image ,但只有 Isolinux 既支持 live CD 又支持 live USB(通过 Build hybrid image 选项来配置)。

你可以使用 QEMU 来测试你的 Live CD Image:

qemu-system-i386 -cdrom output/images/rootfs.iso9660

如果你配置的是 Hybrid ISO 你还可以将之作为 hard-driver image;

qemu-system-i386 -hda output/images/rootfs.iso9660

它可以方便的使用 dd 命令烧录到 USB 中;

dd if=output/images/rootfs.iso9660 of=/dev/sdb

14.2. Chroot

如果你想在通用 image 中 chroot,那么有以下几点你需要注意的:

  • 你应该将 image 的 tar root filesystem 设置为新的根目录;
  • 您选择的目标架构应该与您的主机兼容,或者您应该使用一些 qemu-* 二进制文件并在 binfmt 属性中正确设置它,以能够在目标主机上运行二进制文件;
  • Buildroot 目前没有提供 host-qemubinfmt 工具来修正构建和使之用于这种场景;

Part III. Developer guide

Chapter 15. How Buildroot works

如上所述,Buildroot 基本上是一组 Makefile,用于下载、配置和编译具有正确选项的软件。 它还包括各种软件包的补丁(主要是涉及交叉编译工具链的补丁,像 gccbinutilsuClibc)。

每个软件包基本上有一个 Makefile,而 Makefile 被分成许多不同的部分,保存在则以 .mk 扩展名命名的文件中。

  • toolchain/ 目录包含一些 Makefile 文件和交叉编译过程中关联的一些文件:比如 binutilsgccgdbkernel-headers 以及 uClibc
  • arch/ 目录包含 Buildroot 支持的所有处理器架构架构定义;
  • package/ 目录包含 Buildroot 支持,编译过程中涉及到的所有软件包和工具的 Makefile 文件和相关文件,而其中每一个 package 都拥有自己的一个目录;
  • linux/ 目录包含 Buildroot 支持的编译 Linux kernel 的 Makefile 和相关文件;
  • boot/ 目录包含 Buildroot 支持的编译 bootloader 过程中关联的 Makefile 和相关文件;
  • system/ 目录包含系统集成的支持文件,比如,目标文件系统的架构,或者初始化系统的架构;
  • fs/ 包含 Buildroot 支持的,再构建 rootfs images 时使用到的一些 Makefile 和相关文件;

package 下的每一个目录至少包含两个文件:

  • something.mk 是一个 Makefile 格式的文件,它常常被用于下载,配置,编译和安装某个包;
  • Config.in 是改包配置时的描述文件,其中可能会涉及到开启关闭某些功能,或者该包与其他包之间的依赖关系;

当配置完成之后,main Makefile 将会执行以下步骤:

  • output/ (如果没有 O= 指定的话)中创建所有的输出目录:staging, target, build ...
  • 创建一个 toolchain。如果 internal toolchain 被配置,这意味着将会生成一系列的交叉编译配套工具。 当一个 external toolchain 被配置的时候,则意味着会将交叉编译工具配置导入当前环境变量。
  • 生成 TARGETS 变量中列出的所有目标。 该变量的值由数个独立的 Makefile 文件组成。 更具配置文件,执行 make 过程将触发用户空间包(库、程序)、内核、引导加载程序的编译,以及根文件系统映像的生成。

Chapter 16. Coding style

总的来说,这些编码风格规则用于帮助您在 Buildroot 中添加新文件或重构现有文件。

如果你稍微修改一些现有的文件,一个重要的事情是,要确保整个文件的一致性,所以你可以:

  • 遵从该文件中使用到的,但可能已经被弃用的编码风格;
  • 或者,重构该文档,以使只符合现有规范;

16.1. Config.in file

Config.in 包含了几乎所有再 Buildroot 中可配置的条目;

一个完整的描述包括如下部分:

config BR2_PACKAGE_LIBFOO
        bool "libfoo"
        depends on BR2_PACKAGE_LIBBAZ
        select BR2_PACKAGE_LIBBAR
        help
          This is a comment that explains what libfoo is. The help text
          should be wrapped.

          http://foosoftware.org/libfoo/
  • bool, depends on, selecthelp 行的缩进为一个 Tab;
  • help 中的具体描述应该另起一行,并以一个 tab + 两个 space 开始;
  • help text 的每一行应该在 72 个字符内,但因为一个 tab 所占字符空间为 8,因此文本最大只有 62 个字符;

Config.in 是 Buildroot 工具的配置文件,基本遵从 Kconfig 的格式规范, 有关更多的 Kconfig 语言的细节,请参考: http://kernel.org/doc/Documentation/kbuild/kconfig-language.txt

16.2. The .mk file

  • 标题:文件以标题开头。 它包含模块名称,最好是小写字母,包含如下所示的分隔符之间。 另外标题后必须有一个空行:

    ################################################################################
    #
    # libfoo
    #
    ################################################################################
    
    
  • 定义: = 符号进行定义,该符号前后应该有一个空格;

    LIBFOO_VERSION = 1.0
    LIBFOO_CONF_OPTS += --without-python-support

    请不要让 = 相互对齐;

  • 缩进:仅支持 Tab 作为缩进;

    define LIBFOO_REMOVE_DOC
            $(RM) -fr $(TARGET_DIR)/usr/share/libfoo/doc \
                    $(TARGET_DIR)/usr/share/man/man3/libfoo*
    endef

    注意,定义在 define 块内的命令应该以一个 tab 作为起始符, 这样 make 才能将之理解成命令;

  • 可选依赖:

    • 参考的 multi-line 语法:

      正确格式:

      ifeq ($(BR2_PACKAGE_PYTHON),y)
      LIBFOO_CONF_OPTS += --with-python-support
      LIBFOO_DEPENDENCIES += python
      else
      LIBFOO_CONF_OPTS += --without-python-support
      endif

      错误格式:

      LIBFOO_CONF_OPTS += --with$(if $(BR2_PACKAGE_PYTHON),,out)-python-support
      LIBFOO_DEPENDENCIES += $(if $(BR2_PACKAGE_PYTHON),python,)
    • 请确配置选项和依赖放在一起;
  • 可选 hooks: 请确保 Hooks 声明和定义放在一个 if 块中;

    正确格式:

    ifneq ($(BR2_LIBFOO_INSTALL_DATA),y)
    define LIBFOO_REMOVE_DATA
            $(RM) -fr $(TARGET_DIR)/usr/share/libfoo/data
    endef
    LIBFOO_POST_INSTALL_TARGET_HOOKS += LIBFOO_REMOVE_DATA
    endif

    错误格式:

    define LIBFOO_REMOVE_DATA
            $(RM) -fr $(TARGET_DIR)/usr/share/libfoo/data
    endef
    
    ifneq ($(BR2_LIBFOO_INSTALL_DATA),y)
    LIBFOO_POST_INSTALL_TARGET_HOOKS += LIBFOO_REMOVE_DATA
    endif

16.3. The documentation

documentation 使用 asciidoc 格式。

关于 asciidoc 语法的更多信息请参考: http://www.methods.co.nz/asciidoc/userguide.html

16.4. Support scripts

support/utils/ 目录下的一些脚本是用 python 编写的, 格式应该服从 PEP8 Style Guide for Python Code

Chapter 17. Adding support for a particular board

Buildroot 包含了几个公开可用的硬件板级的基本配置,因此使用这些硬件的用户可以很容易地构建一个已知的工作系统。当然你也可以在 Buildroot 中添加对其他板的支持。

为此,您需要为你的硬件创建一个 Buildroot 配置,从而将 (内部)工具链、内核、引导加载程序、文件系统,busybox 进行编译,并构建一个基本的用户操作系统。 首先你不应该选择任何特定的包:配置应该尽可能少,并且应该只为目标平台构建一个可工作的基本 BusyBox 系统。 当然,您可以为您的内部项目使用更复杂的配置,但此时 Buildroot 项目将只集成基本的板配置。这是因为包的选择是高度依赖于具体的应用场景的。

当你有了一个大概的配置,可以执行 make savedefconfig 来保存该配置, 执行该命令将会在 Buildroot 源码目录库的根目录生成一个最小 defconfig 文件。 你可以将该文件复制到 configs/ 目录,并将之重命名为一个合适的名字,比如: <boardname>_defconfig. 如果配置稍微复杂一点,最好手动重新格式化它,并将它分成几个部分,在每个部分之前加上注释。 典型的分块顺序是 Architecture , Toolchain options (通常只是linux headers version), Firmware , Bootloader , Kernel ,和 Filesystem 。

对于不同的组件,总是有更新的修复版本或提交,而不是 “最终版本”。 比如,你可将 BR2_LINUX_KERNEL_CUSTOM_VERSION=yBR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE 设置为您测试的内核版本;

建议尽可能多地使用 Linux 和 bootloader 的源版本,并尽可能多地使用默认内核和引导加载程序配置。 如果它们应用到你的硬件上产生了错误,或者不存在相应的配置,我们鼓励你发送 fix commit 到相应的源项目(upstream projects)。

然而,与此同时,您可能希望保存内核或引导加载程序配置或特定于您的目标平台的补丁。 为此,你可以创建一个 board/<manufacturer> 目录和子目录 board/<manufacturer>/<boardname>。 然后,您可以将补丁和配置存放在这些目录中,并从主 Buildroot 配置中引用它们。 参考 Chapter 9, Project-specific customization 获取更多细节。

Chapter 18. Adding new packages to Buildroot

本章将介绍新包(用户程序或者应用)如何集成到 Buildroot 中。 另外,还会介绍如何集成现有的包,这是解决问题和调试 bug 所必须的。

当你需要添加一个新的 package 时,请确保在各个条件下都测试过了。 (参考 Section 18.24.3, “How to test your package”) 和检查其代码规范 (参考 Section 18.24.2, “How to check the coding style”).

18.1. Package directory

首先,在 package 目录 创建一个属于你的 package 的目录,比如 libfoo.

可能有些包被归类放到一个子目录下面,比如: x11r7, qt5 and gstreamer。 如果你的 package 属于这些类别,那么建议你在这些类目录下创建属于你 package 的目录。 额外创建一个新目录时不建议的。

18.2. Config files

为了是你的 package 能在配置工具中显示,你需要在创建的目录中创建一个 Config 文件,这里有两种格式:Config.in and Config.in.host

18.2.1. Config.in file

下面,我们以 libfoo 为例子在 libfoo 的子目录里面创建一个 Config 文件,其配置文件的格式如下所示:

config BR2_PACKAGE_LIBFOO
        bool "libfoo"
        help
          This is a comment that explains what libfoo is. The help text
          should be wrapped.

          http://foosoftware.org/libfoo/

这里的格式可以参考:16.1 中描述。

作为 Buildroot 下的约定,其属性应该服从以下顺顺序:

  1. bool 选项类型 string… 带双引号
  2. default 如果存在默认值情况下;
  3. depends on 如果该 package 依赖于特定目标情况下; Any dependencies on the target in form
  4. depends on 如果该 package 依赖于特定 toolchain 情况下;
  5. depends on 如果该 package 依赖于特定的某些 package 的情况下;
  6. select 如果存在任何的其他可选配置项;
  7. help 信息;

你可以添加一些其他的子选项到 if BR2_PACKAGE_LIBFOO…endif 的声明中,来对你的 papckage 进行更详细的配置。 你可以观察一下其他 package 是如何编写的。 关于 Config.in 文件的语法于 kernel 中 kconfig 的语法是一样的。 请参考 http://kernel.org/doc/Documentation/kbuild/kconfig-language.txt 获取有关该语法的更多详细的信息。

最后你需要将 libfoo/Config.in 添加到 package/Config.in 中(或者是你之前存放 libfoo 目录的类目录下)。 包含在该目录内的文件不应该包含除包明外的其他文件(bare 除外)。

source "package/libfoo/Config.in"

18.2.2. Config.in.host file

还有一些包是为了 build 给 host 使用的,针对这些 package 有两个选项:

  • 主机包包含一个或者多个依赖时,将 host-foo 增加到目标 package 的 xxxxx 变量中, 并且不需要创建 Config.in.host
  • host package 应该被显示的被用户配置。在这种情况下,需要为 host package 创建一个 Config.in.host

    config BR2_PACKAGE_HOST_FOO 
            help
              This is a comment that explains what foo for the host is.
    
              http://foosoftware.org/foo/

    Config.in 文件相同的编码风格和选项也是有效的。

    最后,你需要将你的新 libfoo/Config.in.host 配置加到 package/Config.in.host 中。 包含在该文件中的列表应该按照字母排序,并且不能包含除报名外的其他内容。

    source "package/foo/Config.in.host"

    这些 host package 将会出现在 Host utilities 目录中。

18.2.3. Choosing depends on or select

package 的 Config.in 文件还必须确保启用了依赖项。 通常 Buildroot 有以下规则:

  • 使用 select 的方式为库标注依赖,这些依赖通常都不是很明显, 比如: 库 libgtk2 使用 select BR2_PACKAGE_LIBGLIB2 来确保该依赖库会同样被选择, 因此 select 方式是采用后向语义来表达依赖关系的。
  • 当库需要明确的标识其依赖时,可以采用 depends on 类型依赖声明, 通常情况下,Buildroot 采用该种方式来表达目标架构(包括 MMU 支持和 toolchain 的选项等)的依赖关系, (参考 Section 18.2.4, “Dependencies on target and toolchain options”), 或者描述比较大的“事物”的依赖关系,比如 X.org 系统, depends on 类型的语法采用前向语义描述依赖关系。

注意.  目前关于 kconfig 的问题是 -- 这两个语义并没有建立内在联系。 因此你有可能遇到有些依赖没有选择上的问题,

下面这个例子说明了 selectdepends on 的用法:

config BR2_PACKAGE_RRDTOOL
        bool "rrdtool"
        depends on BR2_USE_WCHAR
        select BR2_PACKAGE_FREETYPE
        select BR2_PACKAGE_LIBART
        select BR2_PACKAGE_LIBPNG
        select BR2_PACKAGE_ZLIB
        help
          RRDtool is the OpenSource industry standard, high performance
          data logging and graphing system for time series data.

          http://oss.oetiker.ch/rrdtool/

comment "rrdtool needs a toolchain w/ wchar"
        depends on !BR2_USE_WCHAR

注意,这两种依赖类型,仅仅在描述同一个依赖的时候具有传递性。

这意味着在下面的例子中:

config BR2_PACKAGE_A
        bool "Package A"

config BR2_PACKAGE_B
        bool "Package B"
        depends on BR2_PACKAGE_A

config BR2_PACKAGE_C
        bool "Package C"
        depends on BR2_PACKAGE_B

config BR2_PACKAGE_D
        bool "Package D"
        select BR2_PACKAGE_B

config BR2_PACKAGE_E
        bool "Package E"
        select BR2_PACKAGE_D
  • 如果 Package B 被选择,那么 Package A 将会变得可见, 而 Package B 可见又依赖与 Pakcage A 被选择。
  • 选择 Package E 将会选择 Package D, 而这会导致 Package B 被选择, 但是这时 kconfig 并不会检查 Package A 是否被选择。 因此 Package A 最终也不会被选择。
  • 因此,在这种情况下就需要添加一个显示的依赖关系:
config BR2_PACKAGE_D
        bool "Package D"
        select BR2_PACKAGE_B
        depends on BR2_PACKAGE_A

config BR2_PACKAGE_E
        bool "Package E"
        select BR2_PACKAGE_D
        depends on BR2_PACKAGE_A

总的来说,对于库的依赖关系 select 应该是首选的。

注意,虽然这种表达方式确保了依赖都被启用,但必须在建构前。因此,该依赖关系还需要在 .mk 中表示。

更多关于格式的信息,请参考:the coding style.

18.2.4. Dependencies on target and toolchain options

许多包依赖于编译器的一些选项(比如:C library, C++ 支持,线程支持,RPC 支持, wchar 支持 或者 动态库支持)。 还有一些包仅可以在某些目标平台上建构(比如:处理器中是否存在 MMU 的支持)。

这些依赖关系必须在 Config.in 文件中有合适的 depends on 表达。 另外, 对于那些特定依赖 toolchain 的选项,在该选项还没有被启用的时候,应该有一段注解(comment)向用户展示,并显示的告知用户为什么该 package 不可用。 对目标体系结构或 MMU 支持的依赖,不应该在注释中显示出来:因为用户不太可能自由地选择另一个目标,所以显式地显示这些依赖没有什么意义。

comment 应该只在 config 选项本身在工具链选项依赖项满足才可见。 这意味着包的所有其他依赖(包括对目标架构和MMU支持的依赖)必须在comment定义中重复。 为了保持清晰的逻辑,这些非工具链选项的依赖于语句应该与工具链选项的依赖于语句分开。 如果在同一个文件中有一个配置选项(通常是主包),最好使用一个全局的 If…endif 构造,而不是在注释和其他配置选项上重复 depends on 语句。

Package Foo 依赖项的 comment 格式通常如下:

foo needs a toolchain w/ featA, featB, featC

比如:

mpd needs a toolchain w/ C++, threads, wchar

或者

crda needs a toolchain w/ threads

请注意,此文本有意保持简短,以便它适合 80 个字符的终端。

本节的其余部分列举了不同的目标和工具链选项、要依赖的相应配置符号以及要在注释中使用的文本。

  • 目标架构:

    • 依赖符号(Dependency symbol):BR2_powerpc, BR2_mips, … (参考 arch/Config.in)
    • 注释字符(Comment string): no comment to be added
  • MMU support

    • 依赖符号(Dependency symbol):BR2_USE_MMU
    • 注释字符(Comment string): no comment to be added
  • Gcc_sync* 用于原子操作的内置函数。 它们可用于 1 字节、2 字节、4 字节和 8 字节的变体。 由于不同的体系结构支持不同大小的原子操作,因此每个大小都有一个依赖符号:

    • 依赖符号(Dependency symbol):BR2_TOOLCHAIN_HAS_SYNC_1 设置 1 byte, BR2_TOOLCHAIN_HAS_SYNC_2 设置 2 bytes, BR2_TOOLCHAIN_HAS_SYNC_4 设置 4 bytes, BR2_TOOLCHAIN_HAS_SYNC_8 设置 8 bytes.
    • 注释字符(Comment string): no comment to be added
  • Gcc _atomic* 用于原子操作的内置函数。

    • 依赖符号(Dependency symbol):BR2_TOOLCHAIN_HAS_ATOMIC.
    • 注释字符(Comment string): no comment to be added
  • 内核头

    • 依赖符号(Dependency symbol):BR2_TOOLCHAIN_HEADERS_AT_LEAST_X_Y, (将 X_Y 替换成合适的版本号, 参考 toolchain/Config.in)
    • 注释字符(Comment string): headers >= X.Y and/or headers <= X.Y (replace X.Y with the proper version)
  • GCC version

    • 依赖符号(Dependency symbol):BR2_TOOLCHAIN_GCC_AT_LEAST_X_Y, (替换 X_Y 成合适的版本号, 参考 toolchain/Config.in)
    • 注释字符(Comment string) gcc >= X.Y and/or gcc <= X.Y (replace X.Y with the proper version)
  • Host GCC version

    • 依赖符号(Dependency symbol):BR2_HOST_GCC_AT_LEAST_X_Y, (替换X_Y 合适的版本号, see Config.in)
    • 注释字符(Comment string): no comment to be added
    • 请注意,具有最低主机 GCC 版本的通常不是包本身,而是它所依赖的主机包。
  • C library

    • 依赖符号(Dependency symbol):BR2_TOOLCHAIN_USES_GLIBC, BR2_TOOLCHAIN_USES_MUSL, BR2_TOOLCHAIN_USES_UCLIBC
    • 注释字符(Comment string):: for the C library, a slightly different comment text is used: foo needs a glibc toolchain, or foo needs a glibc toolchain w/ C++
  • C++ support

    • 依赖符号(Dependency symbol):BR2_INSTALL_LIBSTDCPP
    • 注释字符(Comment string): C++
  • D support

    • 依赖符号(Dependency symbol): BR2_TOOLCHAIN_HAS_DLANG
    • 注释字符(Comment string): Dlang
  • Fortran support

    • 依赖符号(Dependency symbol):BR2_TOOLCHAIN_HAS_FORTRAN
    • 注释字符(Comment string): fortran
  • thread support

    • 依赖符号(Dependency symbol):BR2_TOOLCHAIN_HAS_THREADS
    • 注释字符(Comment string): threads (unless BR2_TOOLCHAIN_HAS_THREADS_NPTL is also needed, in which case, specifying only NPTL is sufficient)
  • NPTL thread support

    • 依赖符号(Dependency symbol):BR2_TOOLCHAIN_HAS_THREADS_NPTL
    • 注释字符(Comment string): NPTL
  • RPC support

    • 依赖符号(Dependency symbol):BR2_TOOLCHAIN_HAS_NATIVE_RPC
    • 注释字符(Comment string): RPC
  • wchar support

    • 依赖符号(Dependency symbol):BR2_USE_WCHAR
    • 注释字符(Comment string): wchar
  • dynamic library

    • 依赖符号(Dependency symbol):!BR2_STATIC_LIBS
    • 注释字符(Comment string): dynamic library

18.2.5. Dependencies on a Linux kernel built by buildroot

一些包需要 Buildroot 编译 Linux Kernel. 这通常是一些内核模块(kernel modules)或者固件。 和描述 toolchain 选项的依赖关系一样,我们同样需要在相应的 Config.in 文件中描述其依赖关系。 通常使用的格式是:

foo needs a Linux kernel to be built

如果它及依赖于 Linux kernel, 又依赖于 toolchain, 那么可以使用如下 comment:

foo needs a toolchain w/ featA, featB, featC and a Linux kernel to be built

18.2.6. Dependencies on udev /dev management

如果一个包需要 udev /dev 管理,那么它应该添加依赖 BR2_PACKAGE_HAS_UDEV,并且需要添加以下 comment:

foo needs udev /dev management

如果它既依赖于 toolchain 的某些 option 又依赖于 udev /dev 管理,那么可以使用如下 comment:

foo needs udev /dev management and a toolchain w/ featA, featB, featC

18.2.7. Dependencies on features provided by virtual packages

一些特性可能被一个以上的 package 提供,比如说 openGL libraries:

参考 Section 18.11, “Infrastructure for virtual packages” 获取更多 package 的信息。

18.3. The .mk file

最后,最困难的部分,创建一个名为 libfoo.mk 的文件。 它描述了如何下载(配置/建构/安装 ...)目标 package,

这依赖于 package 的 type, 这个 .mk 文件使用的是另外一套语法来编写的:

  • 对于普通 package 的 Makefile (不是使用 autotools 或者 CMake 工具的): 它们的编译结构与基于 autotools 的包类似,但是需要开发多作一点工作。 它们指定了应该如何为包进行配置、编译和安装。 此编译结构必须用于所有不使用 autotools 作为其构建系统的包。 且此结构必须用在做有没有使用 autotools 建构的包上, 在将来,可能还会有为其他构建系统编写的其他模式的编译架构。 我们在 18.5.1reference 做详细介绍。
  • autotools-based 的 Makefiles (autoconf, automake, etc.): 我们为此类设备与定义了一些结构,自从 autotools 变成了一个非常通用的建构系统,结构也相对统一,因此所有依赖于 autotools 的包,都应该采用该中结构进行配置。 参考 tutorialreference 获取更加详细的信息。
  • cmake-based 的 Makefiles: 我们为此类软件包提供专用编译结构,因为 CMake 是一个越来越常用的构建系统,并且具有标准化的行为。 此基础结构必须用于依赖 CMake 的新包。 参考: tutorialreference 获取更详细的信息。
  • Python 模块的 Makefiles: Buildroot 有一个专用的 Python 模块编译结构,它们使用 distutils 或 setuptools 机制。我们通过教程和 参考来介绍它们 。 它们使用 distutilssetuptools 机制。 参考: tutorialreference 获取更详细的信息。
  • Lua 模块的 Makefiles: Buildroot 有一个专门的 Lua 模块编译结构,可通过 LuaRocks 网站获得。我们通过教程和 参考来介绍它们。 We have a dedicated infrastructure for Lua modules available through the LuaRocks web site. We cover them through a tutorialreference 获取详细信息。

更多 .mk 相关的格式信息请参考the writing rules

18.4. The .hash file

如果可能,您必须添加名为 libfoo.hash 的第三个文件,libfoo.hash 其中包含 libfoo 包下载文件的哈希值。 不添加 .hash 文件的唯一原因是由于包的下载方式而无法进行哈希检查。

当包有版本选择选项时,哈希文件可以存储在以版本命名的子目录中,例如 package/libfoo/1.2.3/libfoo.hash. 如果不同版本具有不同的许可条款,但它们存储在同一个文件中,这一点尤其重要。 此种情况之外,哈希文件应保留在包的目录中。

存储在该文件中的哈希值用于验证下载文件和许可证文件的完整性。

此文件的格式是每个要检查哈希的文件一行,每行包含以下三个字段,由两个空格分隔:

  • 哈希类型,以下之一:

    • md5, sha1, sha224, sha256, sha384, sha512, none
  • 文件的哈希值:

    • none, 一个或多个非空格字符,通常只是字符串 xxx
    • md5, 32 个十六进制字符串
    • sha1, 40 个十六进制字符串
    • sha224, 56 个十六进制字符串
    • sha256, 64 个十六进制字符串
    • sha384, 96 个十六进制字符串
    • sha512, 128 个十六进制字符串
  • 文件的名字:

    • 对于源的压缩文件:则是文件的名称(basename),不会包含路径方面的信息。
    • 对于 license 文件:路径则会出现在 FOO_LICENSE_FILES 变量中。

# 开头的行为注释行,在建构时将会被忽略,空行也将会被忽略。

一个文件可以有多个类型散列值,每个散列值在自己的行上。在这种情况下,所有哈希值都必须匹配。

注意  理想情况下,存储在此文件中的哈希应该与上游发布的哈希相匹配,例如在他们的网站上,或者在电子邮件公告中...... 如果上游提供了不止一种类型的哈希(例如 sha1 和 sha512 ),那么最好添加所有这些到 .hash 文件中。 如果上游不提供任何散列,或仅提供一个 md5 散列,则自己计算至少一个强散列(最好是 sha256, 注意不是md5),并在散列上方的注释行中提及这一点。

注意  许可证文件的哈希值用于在软件包版本冲突时检测许可证更改。 在 make legal-info 目标运行期间将检查该哈希值。 对于具有多个版本的包(如 Qt5),在该包的子目录 <packageversion> 中创建哈希文件, (可参考 Section 19.2, “How patches are applied”)。

none 散列类型为从存储库下载的源所保留(如 git clone. subversion checkout ... )

下面是一些编写 hash 文件的例子:

# Hashes from: http://www.foosoftware.org/download/libfoo-1.2.3.tar.bz2.{sha1,sha256}:
sha1  486fb55c3efa71148fe07895fd713ea3a5ae343a  libfoo-1.2.3.tar.bz2
sha256  efc8103cc3bcb06bda6a781532d12701eb081ad83e8f90004b39ab81b65d4369  libfoo-1.2.3.tar.bz2

# md5 from: http://www.foosoftware.org/download/libfoo-1.2.3.tar.bz2.md5, sha256 locally computed:
md5  2d608f3c318c6b7557d551a5a09314f03452f1a1  libfoo-data.bin
sha256  01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b  libfoo-data.bin

# Locally computed:
sha256  ff52101fb90bbfc3fe9475e425688c660f46216d7e751c4bbdb1dc85cdccacb9  libfoo-fix-blabla.patch

# No hash for 1234:
none  xxx  libfoo-1234.tar.gz

# Hash for license files:
sha256  a45a845012742796534f7e91fe623262ccfb99460a2bd04015bd28d66fba95b8  COPYING
sha256  01b1f9f2c8ee648a7a596a1abe8aa4ed7899b1c9e5551bda06da6e422b04aa55  doc/COPYING.LGPL

如果 .hash 文件存在, 并存在一个或者多个包的 hash 值,buildroot 将会在下载完包之后计算下载文件的 hash 值,并比对 .hash 文件中值。 如果一个或者多个 hash 不匹配,Buildroot 将会认为这个是一个错误,并删除该下载文件并警告。

如果 .hash 文件存在, 但是其中没有包含该下载文件的任何 hash 信息,Buildroot 会认为这是一个错误,并报出警告。 但是,下载文件会留在下载目录中,因为有可能 .hash 文件的问题,而下载文件是没问题的。

当前会检查从 http/ftp 服务器、Git 存储库、使用 scp 复制的文件和本地文件获取的文件的哈希值。 其他版本控制系统(例如 Subversion、CVS 等)不会检查哈希,因为当从此类版本控制系统获取源代码时, Buildroot 当前不会生成可 reproducible tarball。

.hash 文件中保存的 hash 值应该确保是稳定的文件生成的。 例如,Github 自动生成的补丁不能保证稳定,因此它们的哈希值会随着时间而改变。不应下载此类补丁,而应将其添加到本地包文件夹中。

如果 .hash 文件丢失,那么将不会检查下载文件的完整性。

18.5. Infrastructure for packages with specific build systems

那些特定的构建系统的包,不同 Buildroot 支持的标准( autotools 或者 CMake )里的包,这些包的构建同通常都需要手写 Makefile 或者 shell 脚本。

18.5.1. generic-package tutorial

01: ################################################################################
02: #
03: # libfoo
04: #
05: ################################################################################
06:
07: LIBFOO_VERSION = 1.0
08: LIBFOO_SOURCE = libfoo-$(LIBFOO_VERSION).tar.gz
09: LIBFOO_SITE = http://www.foosoftware.org/download
10: LIBFOO_LICENSE = GPL-3.0+
11: LIBFOO_LICENSE_FILES = COPYING
12: LIBFOO_INSTALL_STAGING = YES
13: LIBFOO_CONFIG_SCRIPTS = libfoo-config
14: LIBFOO_DEPENDENCIES = host-libaaa libbbb
15:
16: define LIBFOO_BUILD_CMDS
17:     $(MAKE) $(TARGET_CONFIGURE_OPTS) -C $(@D) all
18: endef
19:
20: define LIBFOO_INSTALL_STAGING_CMDS
21:     $(INSTALL) -D -m 0755 $(@D)/libfoo.a $(STAGING_DIR)/usr/lib/libfoo.a
22:     $(INSTALL) -D -m 0644 $(@D)/foo.h $(STAGING_DIR)/usr/include/foo.h
23:     $(INSTALL) -D -m 0755 $(@D)/libfoo.so* $(STAGING_DIR)/usr/lib
24: endef
25:
26: define LIBFOO_INSTALL_TARGET_CMDS
27:     $(INSTALL) -D -m 0755 $(@D)/libfoo.so* $(TARGET_DIR)/usr/lib
28:     $(INSTALL) -d -m 0755 $(TARGET_DIR)/etc/foo.d
29: endef
30:
31: define LIBFOO_USERS
32:     foo -1 libfoo -1 * - - - LibFoo daemon
33: endef
34:
35: define LIBFOO_DEVICES
36:     /dev/foo  c  666  0  0  42  0  -  -  -
37: endef
38:
39: define LIBFOO_PERMISSIONS
40:     /bin/foo  f  4755  foo  libfoo   -  -  -  -  -
41: endef
42:
43: $(eval $(generic-package))

Makefile 从第 7 到 11 行开始,包含以下元数据信息: 包的版本 ( LIBFOO_VERSION )、 包的 tarball 的名称 ( LIBFOO_SOURCE )(推荐使用 xz-ed tarball), 包的源下载地址 ( LIBFOO_SITE )、 包的 license ( LIBFOO_LICENSE ) 和带有 lencense 文本 ( LIBFOO_LICENSE_FILES ) 的文件。 LIBFOO_ 在这种情况下,所有变量必须以相同的前缀开头。此前缀始终是包名称的大写版本(请参阅下文以了解包名称的定义位置)。

在第 12 行,我们指定这个包要安装一些东西到暂存空间。这通常是库所需要的,因为它们必须在暂存空间中安装头文件和其他开发文件。 这将确保 LIBFOO_INSTALL_STAGING_CMDS 变量中列出的命令 将被执行。

在第 13 行,我们指定要对 LIBFOO_INSTALL_STAGING_CMDS 阶段安装某些 libfoo-config 文件。 这些 *-config 文件是位于 $(STAGING_DIR)/usr/bin 目录中的可执行 shell 脚本文件,由其他 3rd 方包执行以找出此特定包的位置和链接标志。

问题是所有这些 *-config 文件默认存在缺陷的、不适合交叉编译的主机系统链接标志。

比如: -I/usr/include instead of -I$(STAGING_DIR)/usr/include 或者:-L/usr/lib instead of -L$(STAGING_DIR)/usr/lib

因此这些脚本都会被执行一个 sed 操作以修正这些错误, 参数 LIBFOO_CONFIG_SCRIPTS 是需要修复的 shell 脚本的文件名列表。 所有这些名称都与 $(STAGING_DIR)/usr/bin 中文件相关,如果需要,可以给出多个名称。

另外,存在于 LIBFOO_CONFIG_SCRIPTS 中的文件将会从 $(TARGET_DIR)/usr/bin 中删除, 因为目标平台并不需要他们。

Example 18.1. Config script: divine package

Package divine 安装 shell 脚本$(STAGING_DIR)/usr/bin/divine-config.

因此该句式应该写作:

DIVINE_CONFIG_SCRIPTS = divine-config

Example 18.2. Config script: imagemagick package:

Package imagemagick 安装如下脚本:$(STAGING_DIR)/usr/bin/{Magick,Magick++,MagickCore,MagickWand,Wand}-config

因此他的修复变量应该如下:

IMAGEMAGICK_CONFIG_SCRIPTS = \
   Magick-config Magick++-config \
   MagickCore-config MagickWand-config Wand-config

在第 14 行,我们指定了这个包所依赖的依赖项列表。 这些依赖项按照小写包名列出,可以是目标 package(不带 host- 前缀)或主机包(带 host- 前缀)。 Buildroot 将确保在当前包开始其配置之前构建和安装所有这些包 。

Makefile 的其余部分,第 16..29 行,定义了在包配置、编译和安装的不同步骤中应该做什么。 LIBFOO_BUILD_CMDS 告诉 Buildroot 应该执行哪些步骤来构建包。 LIBFOO_INSTALL_STAGING_CMDS 告诉 Buildroot 应该执行哪些步骤来在暂存空间中安装包。 LIBFOO_INSTALL_TARGET_CMDS 告诉 Buildroot 应该执行哪些步骤来在目标空间中安装包。

所有这些步骤都依赖于 $(@D) 变量,该变量的值为解​​压缩包源代码的目录。

在第 31..33 行,我们定义了这个 package 使用的用户(例如,以非 root 用户身份运行守护进程)( LIBFOO_USERS )。

在第 35..37 行,我们定义了此 package 使用的设备节点 ( LIBFOO_DEVICES )。

在第 39..41 行,我们定义了要为此包安装的特定文件设置的权限( LIBFOO_PERMISSIONS )。

最后,在第 43 行,我们调用该 generic-package 函数,该函数根据之前定义的变量生成使包工作所需的所有 Makefile 代码。

18.5.2. generic-package reference

通用目标有两种变体。该 generic-package 宏用于交叉编译目标平台 package。 该 host-generic-package 宏用于编译主机 package,为主机本地编译。 可以在一个 .mk 文件中调用它们:一次创建规则以生成目标包,一次创建规则以生成主机包:

$(eval $(generic-package))
$(eval $(host-generic-package))

如果编译目标包需要在主机上安装一些工具,这可能很有用。 如果包名是 libfoo ,那么目标的包名也是 libfoo ,而主机的包名是 host-libfoo 。 如果其他包有依赖于该包,那么其他包的 DEPENDENCIES 变量值应该为 libfoo 或者 libfoo-host

在所有变量定义之后 ,对 generic-package 和 / 或 host-generic-package 宏的调用必须在文件的末尾。如果有的话,调用 to 必须在调用 to 之后 。 .mkhost-generic-package generic-package 调用 generic-package 和/或者 host-generic-package 宏必须在 .mk 的文件末尾。 如果两个都调用了,那么调用 host-generic-package 必须generic-package 之后。

对于目标包, generic-package 使用 .mk 文件名和其大写作为其变量名的前缀:如 LIBFOO_*, 而 host-generic-package 则在此基础上增加 HOST_ 作为其前缀:如 HOST_LIBFOO_*, 对于某些变量,如果 HOST_LIBFOO_* 不存在,那么也会以 LIBFOO_* 作为其前缀, 这是针对目标包和主机包拥有相同变量时来处理的。 详见下文:

以下变量是在 .mk 文件中的一组变量的集合,描述了该包的原信息(加入包名为 libfoo ):

  • LIBFOO_VERSION, 必须具备,描述 package 的版本。 请注意,如果 HOST_LIBFOO_VERSION 不存在,则假定与 LIBFOO_VERSION 一致. 它也可以是直接从其版本控制系统获取的包的 revision number 或 tag。例子:

    • 对于 release tarball 的版本: LIBFOO_VERSION = 0.1.2
    • git 的 sha1 commit id: LIBFOO_VERSION = cb9d6aa9429e838f0e54faa3d455bcbab5eef057
    • Git 的 tag: LIBFOO_VERSION = v0.1.2

      注意:  将分支名作为 FOO_VERSION 的值是不支持的,因为其不能也不能像人们期望的那样工作:

      1. 由于本地缓存,Buildroot 不会重新 fetch 远程更新,因此希望能够跟踪远程存储库的人会感到非常惊讶和失望;
      2. 因为两个构建永远不可能完美地同时进行,并且因为远程存储库可能随时在分支上获得新的提交,所以使用相同 Buildroot 树并构建相同配置的两个用户可能会获得不同的源,从而导致构建不可重现,并且人们会感到非常疑惑和伤心。
  • LIBFOO_SOURCE 可能包含 pakcage tarball 的名字,那么 tarball 将会从 LIBFOO_SITE 下载该 tarball。 如果 HOST_LIBFOO_SOURCE 没有指定,那么默认认为是 LIBFOO_SOURCE。 但是如果 LIBFOO_SOURCE 也没有被指定,则该值会假定为 libfoo-$(LIBFOO_VERSION).tar.gz, 比如:LIBFOO_SOURCE = foobar-$(LIBFOO_VERSION).tar.bz2
  • LIBFOO_PATCH 可能包含一个空格分隔的补丁文件名列表,Buildroot 将下载并应用到包源代码。 如果条目包含 ://,则 Buildroot 将假定它是一个完整的 URL 并从该位置下载补丁。 否则 Buildroot 将假定补丁应从 LIBFOO_SITE 处下载, 如果 HOST_LIBFOO_PATCH 未指定,则默认为 LIBFOO_PATCH。 请注意,包含在 Buildroot 本身中的补丁使用不同的机制: 所有包目录中的 *.patch 都将在文件被提取之后打上去, 不过 Buildroot 会先将 LIBFOO_PATCH 中的 patch 应用上去然后才将本地的 patch 打上去。
  • LIBFOO_SITE 提供包的位置,可以是 URL 或本地文件系统路径。 目前主要支持 HTTP、FTP 和 SCP 这几种用于检索 tarball 的 URL 类型,在这些情况下,不要包含尾部斜杠,Buildroot 会根据需要在目录和文件名之间添加斜杠。 Git、Subversion、Mercurial 和 Bazaar 是也是支持的 URL 类型,用于直接从源代码管理系统检索包。 这里 有一个帮助函数可以更轻松地从 GitHub 下载源 tarball。 也可以使用一个路径可用于指定 tarball 或包含包源代码的在本机的目录。参考 LIBFOO_SITE_METHOD 获取更多有关检索以及如何工作的更多详细信息。 请注意,SCP URL 的格式应为 scp://[user@]host:filepath,并且 filepath 为该文件想对于用户家目录的路径,因此您可能希望指定文件的绝对路径,那么请在路径钱加上斜杠表示,如 scp://[user@]host:/absolutepath. 如果 HOST_LIBFOO_SITE 未指定,则默认为 LIBFOO_SITE。 例子: LIBFOO_SITE=http://www.libfoosoftware.org/libfoo LIBFOO_SITE=http://svn.xiph.org/trunk/Tremor LIBFOO_SITE=/opt/software/libfoo.tar.gz LIBFOO_SITE=$(TOPDIR)/../src/libfoo.
  • LIBFOO_DL_OPTS 是一个传递给下载器的以空格分隔的附加选项列表。用于通过服务器端检查用户登录名和密码来检索文档,或使用代理的场景。 支持所有有效的下载方式 LIBFOO_SITE_METHOD; 选项中内容的有效性取决于下载方法(请参阅相应下载实用程序的手册页)。
  • LIBFOO_EXTRA_DOWNLOADS 是 Buildroot 应下载的附加文件的空格分隔列表。 如果条目包含, :// 则 Buildroot 将假定它是一个完整的 URL,并将下载此 URL 指向的文件。 否则,Buildroot 将假定要下载的文件位于 LIBFOO_SITE 中. 下载之后,Buildroot 不会对这些附加文件做任何事情。 下载的文件路径可从 $(LIBFOO_DL_DIR) 中获得。
  • LIBFOO_SITE_METHOD 用于指定获取 package 源代码的方法。 在很多情况下,Buildroot 会从 LIBFOO_SITE 中猜测起下载方法。设置 LIBFOO_SITE_METHOD 是非必要的。 当 HOST_LIBFOO_SITE_METHOD 没有指定,则其默认值为 LIBFOO_SITE_METHODLIBFOO_SITE_METHOD 的可能值有:

    • wget 从正常的 FTP/HTTP 服务器下载 tar 包。当 LIBFOO_SITE 设置以 http://, https:// 或者 ftp:// 开始时,会默认为该种下载方式。
    • scp 从 ssh 服务器下载 tar 包, 当 LIBFOO_SITEscp:// 开始时会默认为该中方式。
    • svn 获取 Subversion 仓库获取源代码, 当 LIBFOO_SITEsvn:// 开始则默认为该中方式, 当 LIBFOO_SITE 设置成 http:// 时,则必须设置 LIBFOO_SITE_METHOD=svn, Buildroot 才会以 svn 的方式从 http 地址获取源代码。 Buildroot 后续会将 checkout 中的文件以 tarball 的方式保持在 dl 目录中; 后续建构时也会是用 tarbal 而不是再 checkout 一次。
    • cvs 从 CVS 仓库中获取源码。当 LIBFOO_SITEcvs:// 开始时则默认为使用该中方式。 下载的源码将以如 svn 的方式缓存起来, Anonymous pserver 模式在 LIBFOO_SITE 中进行明确定义。 这两种 LIBFOO_SITE=cvs://libfoo.net:/cvsroot/libfooLIBFOO_SITE=cvs://:ext:libfoo.net:/cvsroot/libfoo 都是可接受的。 前者假设为 anonymous pserver 模式, LIBFOO_SITE 必须包含源 URL 以及远程存储库目录。模块即是包名。 LIBFOO_VERSION 是必须具备的字段,而且必须是 csv 中的 tag, branch 或者一个日期(比如:“2014-10-20”、“2014-10-20 13:45”、“2014-10-20 13:45+01”) 参考 man csv 获取更多详细信息。
    • git 从 Git 仓库中获取源码。 当 LIBFOO_SITEgit:// 开始时将默认使用该中方式。 下载后的源文件将会以 SVN 类似的方式缓存起来。
    • hg 从 Mercurial 仓库获取源文件, 当 LIBFOO_SITE 包含一个 Mercurial repository 地址时 必须 指定 LIBFOO_SITE_METHOD=hg , 下载后的源文件将会以 SVN 类似的方式缓存起来。
    • bzr 从 Bazaar 仓库获取源文件, 当 LIBFOO_SITEbzr:// 开始时将默认使用该中方式。 下载后的源文件将会以 SVN 类似的方式缓存起来。
    • file 从本地获取 tarball。 当 LIBFOO_SITE 设置为本地文件路径时使用该种方式, 对于不公开或版本控制的项目非常有用。
    • local 用于本地源代码目录。当 LIBFOO_SITE 指定包含包源代码的本地目录路径时,应该使用它。 Buildroot 将源目录的内容复制到包的构建目录中。请注意,对于 local 包,没有应用补丁。 如果您仍然需要修补源代码,请使用 LIBFOO_POST_RSYNC_HOOKS ,请参阅 Section 18.22.1, “Using the POST_RSYNC hook”.
  • LIBFOO_GIT_SUBMODULES 可以被设置成 YES 将 git 中的 submodules 打包成压缩包。 这只适应于下载方式为 git 的场景,(比如当 LIBFOO_SITE_METHOD=git 的时候)。 注意,当 git 中有绑定的库时,我们不建议使用该种方式,而更倾向于将这些库和 package 打包到一起。
  • LIBFOO_STRIP_COMPONENTS 是tar 中提取内容时需要去除的组件(目录)个数。 大多数软件包的 tarball 都有一个名为 "<pkg-name>-<pkg-version>", 的主要组件,因此 Buildroot 将 --strip-components=1 传递给 tar 以将其删除。 对于没有这个组件的非标准包,或者有多个前导组件要剥离,请使用要传递给 tar 的值设置给此变量。默认值:1。
  • LIBFOO_EXCLUDES 变量指明提取时不需要提取的文档,多个文档已空格分割开, 该值将会直接复制给 tar 的 --exclude 选项。默认为空。
  • LIBFOO_DEPENDENCIES 列出当前目标包编译所需的依赖项(列举包名称)。 保证在当前包的配置开始之前编译和安装这些依赖项。 但是,对这些依赖项配置的修改不会强制重建当前包。 与此方式类似,HOST_LIBFOO_DEPENDENCIES 列出当前主机包的依赖项。
  • LIBFOO_EXTRACT_DEPENDENCIES 列出要解压的当前目​​标包所需的依赖项(列举包名称)。 保证在当前包解压步骤开始前,编译和安装这些依赖项。 这仅由包基础结构(编译架构)在内部使用,通常不是由包直接调用。
  • LIBFOO_PATCH_DEPENDENCIES 列出给当前 package 打 patch 前所需的依赖项(列举包名称)。 保证在当前包打 patch 之前提取和修补(但不一定构建)这些依赖项。 以类似的方式, HOST_LIBFOO_PATCH_DEPENDENCIES 列出当前主机包的依赖项。 这很少使用;通常 LIBFOO_DEPENDENCIES 以足够应付绝大多数情况。
  • LIBFOO_PROVIDES 列举所有 libfoo 的所有 virtual packages 实现。 参考 Section 18.11, “Infrastructure for virtual packages” 获取更多详细信息。
  • LIBFOO_INSTALL_STAGING 可以被设置为YES 或者 NO (默认)。 如果设置为 YES,那么 LIBFOO_INSTALL_STAGING_CMDS 中的指令将会被执行,并安装相关资源到 staging 目录。
  • LIBFOO_INSTALL_TARGET 可以被设置成 YES (默认) 或者 NO。 如果设置成 YES, 那么 LIBFOO_INSTALL_TARGET_CMDS 中的指令将会被执行,并安装相关资源到 target 目录。
  • LIBFOO_INSTALL_IMAGES 可被设置为 YES 或者 NO (默认)。 如果设置成 YES,那么 LIBFOO_INSTALL_IMAGES_CMDS 中的命令将会被执行,并安装相关资源到 images 目录。
  • LIBFOO_CONFIG_SCRIPTS 列举 $(STAGING_DIR)/usr/bin 需要一些特殊操作使他们能更好编译的一些文件。 文件名以空格分隔开,列举在 LIBFOO_CONFIG_SCRIPTS 中的文件在处理之后都会从 $(TARGET_DIR)/usr/bin 中删除,因为他们是不需要存在目标平台上了。
  • LIBFOO_DEVICES 列举出需要 Buildroot 创建的静态设备列表中的文件。 这里的语法请参考 makedevs。 你可以在 Chapter 25, Makedev syntax documentation . 文档中找到相应的语法说明。 该变量是可选的。
  • LIBFOO_PERMISSIONS 列出在构建过程结束时要进行的权限更改。 该语法和 makedevs 类似。 你可以参考 Chapter 25, Makedev syntax documentation。获取更多语法信息。 该变量是可选的。
  • LIBFOO_USERS 列出要为此 package 创建的用户,如果它安装了您希望以特定用户身份运行的程序(例如,作为守护程序或作为 cron 作业)。 语法在本质上与 makedevs 类似, 该变量是可选的。在 Chapter 26, Makeusers syntax documentation 章节将会对该语法进行描述。 该选项是可选的。
  • LIBFOO_LICENSE 定义该 package 基于何种 license (or licenses) 发布。 此名称将出现在 make legal-info 导出的清单中. 如果 license 出现在 the SPDX License List 中, 请使用 SPDX 短标识符以保证清单文件的统一。否则,以精确和简洁的方式描述 license,要避免含糊不清的名称,例如 BSD 实际命名一系列许可证的名称。 该变量是可选的。如果未定义,清单文件中此包的 license 字段将出现 unknown 字样。此变量的预期格式必须符合以下规则:

    • 如果 package 的不同部分在不同的 license 下发布,则使用逗号分割开各个 license(例如:LIBFOO_LICENSE = GPL-2.0+, LGPL-2.1+ )。 如果需要清晰的表示哪个组件在哪个 license 下,则在括号之间用该组件注释许可证(例如: LIBFOO_LICENSE = GPL-2.0+ (programs), LGPL-2.1+ (libraries))。
    • 如果某些 license 以启用子选项为条件,请在条件许可证后附加逗号(例如: FOO_LICENSE += , GPL-2.0+(programs), 编译程序会删除逗号前的空格。
    • 如果 package 是双重许可,那么可以使用 or 关键字来标识(比如:LIBFOO_LICENSE = AFL-2.1 or GPL-2.0+);
  • LIBFOO_LICENSE_FILES 是包 tarball 中以空格分隔的文件列表,其中包含发布包所依据的许可证。 make legal-info 将复制目录中的所有这些文件至 legal-info 目录中。 有关更多信息, 请参阅 Chapter 13, Legal notice and licensing 。 该变量是可选的。如果没有定义,将会产生一个警告让你知道,并且 not saved 会出现在 license files 这个包的清单文件的字段中。
  • LIBFOO_ACTUAL_SOURCE_TARBALL 仅适用于其 LIBFOO_SITE / LIBFOO_SOURCE 对指向实际上不包含源代码而是二进制代码的存档的包 。 这是一种非常罕见的情况,仅适用于已经编译的外部工具链,尽管理论上它可能适用于其他包。 在这种情况下,一个单独的 tarball 通常可以与实际的源代码一起使用。设置 LIBFOO_ACTUAL_SOURCE_TARBALL 为实际源代码存档的名称, Buildroot 将下载它并在您运行 make legal-info 以收集合法相关材料时使用它。 请注意,此文件不会在常规构建期间下载,也不会通过 make source.
  • LIBFOO_ACTUAL_SOURCE_SITE 提供实际源 tarball 的位置。 默认值为 LIBFOO_SITE,因此如果二进制和源存档托管在同一目录中,则无需设置此变量。 如果 LIBFOO_ACTUAL_SOURCE_TARBALL 未设置,则不需要定义此变量。
  • LIBFOO_REDISTRIBUTE 可以被设置成 YES (默认) 或者 NO 来指示 package 源代码是否可以被允许发布,如果设置成 NO 则代表该 package 为非开源工程; Buildroot 在收集法务信息的时候将不会为该 package 保存源代码。
  • LIBFOO_FLAT_STACKSIZE 定义内置于 FLAT 二进制格式的应用程序的堆栈大小。NOMMU 架构处理器上的应用程序堆栈大小不能在运行时扩大。 FLAT 二进制格式的默认堆栈大小仅为 4k 字节。如果应用程序需要消耗更多堆栈,请在此处额外声明。
  • LIBFOO_BIN_ARCH_EXCLUDE 是一个空格分隔的路径列表(相对于目标目录),在检查 package 是否正确编译时,将不会检查此列表列出的项目, 你很少需要设置此变量,除非程序包在默认位置之外,而 /lib/firmware/usr/lib/firmware/lib/modules/usr/lib/modules/usr/share 目录会被自动排除。
  • LIBFOO_IGNORE_CVES 是一个以空格分隔的 CVE 列表,它告诉 Buildroot CVE 跟踪工具应该为此包忽略哪些 CVE。 这通常用于当 CVE 已经被 package 的补丁修复时,或者当 CVE 由于某种原因不影响 Buildroot package 时。 Makefile 中注释的 patch 必须始终在 CVE 条目之前。比如:
# 0001-fix-cve-2020-12345.patch
LIBFOO_IGNORE_CVES += CVE-2020-12345
# only when built with libbaz, which Buildroot doesn't support
LIBFOO_IGNORE_CVES += CVE-2020-54321
  • LIBFOO_CPE_ID_* 是一组定义其(package)为 CPE identifier 类型的变量。 其允许值为:

    • LIBFOO_CPE_ID_PREFIX 指定CPE标识符的前缀,即前三个字段。未定义时,默认值为 cpe:2.3:a。
    • LIBFOO_CPE_ID_VENDOR 指定 CPE 标识符的供应商部分。未定义时,默认值为 <pkgname>_project
    • LIBFOO_CPE_ID_PRODUCT 指定 CPE 标识符的产品部分。未定义时,默认值为<pkgname>
    • LIBFOO_CPE_ID_VERSION 指定 CPE 标识符的版本部分。未定义时,默认值为 $(LIBFOO_VERSION)
    • LIBFOO_CPE_ID_UPDATE 指定 CPE 标识符的更新部分。未定义时,默认值为 *

    如果定义了这些变量中的任何一个,则 Buildroot 假定 package 提供有效的 CPE 信息。在这种情况下,将产生定义 LIBFOO_CPE_ID

    对于 host package,如果它的 LIBFOO_CPE_ID_* 变量没有定义,它会从相应的 target package 中继承这些变量的值。

定义这写语法的推荐形式如下所示:

LIBFOO_VERSION = 2.32

现在,应该定义编译的过程中应该执行哪些的动作了。

  • LIBFOO_EXTRACT_CMDS 该变量列举了那些 actions 应当在解压的时候执行。 这通常不是必须的,因为 tarball 会由 Buildroot 自动处理, 但是,如果压缩包采取的不是标准的压缩格式(比如:zip, RAR,或者是形如 tarball 的非官方的格式), 那么就可以通过该命令来覆盖 Buildroot 的默认行为。
  • LIBFOO_CONFIGURE_CMDS 列举需要在编译前执行的配置行为。
  • LIBFOO_BUILD_CMDS 列举编译包时需要执行的一些操作。
  • HOST_LIBFOO_INSTALL_CMDS 列举当该 package 为 host package 时,在安装时需要执行的一些操作。 package 安装的文件必须安装到 $(HOST_DIR) 的相对目录, 所有的文件,包括开发用到的文件,比如说头文件,都应该安装,因为其他 package 可能依赖这些文件。
  • LIBFOO_INSTALL_TARGET_CMDS 列举当该 package 为 target package 时,在安装时需要执行的一些操作。 该 package 的包必须安装到 $(TARGET_DIR) 目录。 并且仅需要安装 执行程序 运行中涉及到的文件。 头文件,静态库和开发文档将会在最终确定文件系统的时候再次被删除。
  • LIBFOO_INSTALL_STAGING_CMDS 列举安装到 staging 目录阶段需要执行的动作。 该 package 的文件必须安装在 $(STAGING_DIR) 路径,所有开发中的文件都应该被安装,因为编译其他 package 的时候有可能用到。
  • LIBFOO_INSTALL_IMAGES_CMDS 列举将软件包安装到 image 目录中需要执行的一些操作。 当该 package 为 target package 时必须将文件安装到 $(BINARIES_DIR) 目录中。 只有那些不属于 TARGET_DIR 的二进制 image 但是在启动过程中必要的二进制 image 才能放在这里,比如像 kernel image, bootloader or root filesystem images。
  • LIBFOO_INSTALL_INIT_SYSVLIBFOO_INSTALL_INIT_OPENRCLIBFOO_INSTALL_INIT_SYSTEMD 列举安装启动程序(systemV-like init systems (busybox, sysvinit ...), openrc, systemd)的启动脚本时需要执行的动作。 只有在安装了相关的 init 系统时才会运行这些命令(即如果在配置中选择 systemd 作为 init 系统,则只会运行 LIBFOO_INSTALL_INIT_SYSTEMD)。 唯一的例外是当 OpenRC 被选为 init 系统时,如果 libfoo_install_init_openrc尚未设置,那么 libfoo_install_init_sysv 将被调用, 因为 openrc 支持 sysv init 脚本。 当使用 systemd 作为 init 系统时,buildroot 会在镜像构建的最后阶段使用 systemctl preset-all 命令自动开启所有服务。 您可以添加预设文件以防止特定单元(particular unit)被 buildroot 自动启用。
  • LIBFOO_HELP_CMDS 列举出打印包帮助信息的时候需要执行哪些动作,它包括 make help 的输出。 这些命令可以以任何格式打印任何信息。 不过,该变量很少使用,因为 package 很少会有克制化规则, 因此,如果你不清楚或者没必要打印帮助信息的情况下,请不要使用该变量。
  • LIBFOO_LINUX_CONFIG_FIXUPS 列出了构建和使用此包所需的 Linux 内核配置选项,甚至如果没有这些选项,包将从根本无法使用(编译)。 这应该是对 kconfig 调整选项的一组调用:KCONFIG_ENABLE_OPT, KCONFIG_DISABLE_OPT, 或者 KCONFIG_SET_OPT, 不过这通常很少使用到,因为很少有包需要特殊的内核选项。

定义这些变量的最佳方法如下:

define LIBFOO_CONFIGURE_CMDS
        action 1
        action 2
        action 3
endef

在 action 定义中,你可以使用如下变量:

  • $(LIBFOO_PKGDIR) 改变量存储指向保存 libfoo.mkConfig.in 文件的路径, 当需要安装 Buildroot 中的一些绑定的文件时该变量非常有用,比如运行时的配置文件,启动图片之类的..
  • $(@D), 该变量指向该 package 解压后源代码目录。
  • $(LIBFOO_DL_DIR):该变量只想所有 Buildroot 下载文件存储的路进(比如存储 libfoo.xxx.tar.gz 的路径)。
  • $(TARGET_CC), $(TARGET_LD), 等等。 用于获取交叉编译工具。
  • $(TARGET_CROSS) 获取交叉编译工具前缀。
  • 当然 $(HOST_DIR), $(STAGING_DIR)$(TARGET_DIR) 变量为相应包的安装目录。 这些变量指向全局 host , stagingtarget 目录. 除非使用 per-package 目录支持,在这种情况下它们指向当前包 host, stagingtarget 目录。 在这两种情况下,从包的角度来看,它没有任何区别:它应该只使用 HOST_DIR, STAGING_DIRTARGET_DIR。 有关 per-package directory 的更多信息请参考 Section 8.12, “Top-level parallel build”

最后,你还可以使用 hooks,参考 Section 18.22, “Hooks available in the various build steps” 获取更多信息。

18.6. Infrastructure for autotools-based packages

18.6.1. autotools-package tutorial

首先,我们来看一下如何编写一个 autotools-based 类型的 .mk 文件,比如:

01: ################################################################################
02: #
03: # libfoo
04: #
05: ################################################################################
06:
07: LIBFOO_VERSION = 1.0
08: LIBFOO_SOURCE = libfoo-$(LIBFOO_VERSION).tar.gz
09: LIBFOO_SITE = http://www.foosoftware.org/download
10: LIBFOO_INSTALL_STAGING = YES
11: LIBFOO_INSTALL_TARGET = NO
12: LIBFOO_CONF_OPTS = --disable-shared
13: LIBFOO_DEPENDENCIES = libglib2 host-pkgconf
14:
15: $(eval $(autotools-package))

在第 7 行,我们定义了包的v版本号。

在 8,9 行,我们定义了 tarball 的名字以及从哪个网址下载。 Buildroot 将会自动下载到本地。

在 10 行,告诉了 Buildroot 安装到 staging 目录。staging 目录位于 output/staging, 所有安装 staging 文件都安装在此目录(包括开发中的文件), 默认情况下,包不会安装到 staging 目录,因为通常仅仅需要将开发中依赖到的 libraries 安装到 staging 目录; 同样,默认情况下,当 staging 安装被时能的时候使用 make install 安装到该目录。

在 11 行,告诉了 Buildroot 不要安装 package 到 target 目录, 该目录包含将成为目标上运行的根文件系统的内容。 对于纯静态库,没有必要将它们安装在目标目录中,因为它们不会在运行时使用。 默认情况下,启用目标安装; 几乎不需要将此变量设置为 NO。 此外,默认情况下,使用 make install 命令将软件包安装在此位置。

在 12 行,我们告诉了 Buildroot 配置 package 时需要携带的配置选项,该选项在编译配置前将会传递给 ./configure

在 13 行,我们定义了该包的依赖,而这确保了这些依赖包将会在编译本包之前被编译,

最后在第 15 行,我们调用 autotools-package 来生成所有的 Makefile rules, 以用于该包的建构。

18.6.2. autotools-package reference

针对 autotools 类型的宏为 autotools-package, 它与 generic-package 宏类似, 并且你可以使用 host-autotools-package 来编译主机包(host package).

和 generic 的宏类似,autotools 指令也定义了一组 variable 来规范调用 autotools-package 时的行为。

首先,所有存在于 generic 编译架构中的元信息(matedata infomation)变量都存在于 autotools 的编译架构中: LIBFOO_VERSION, LIBFOO_SOURCE, LIBFOO_PATCH, LIBFOO_SITE, LIBFOO_SUBDIR, LIBFOO_DEPENDENCIES, LIBFOO_INSTALL_STAGING, LIBFOO_INSTALL_TARGET

但同时也为 autotools 编译架构定义了一组额外的变量, 其中大多数变量都仅限于特殊的场景,普通的包很少会用到他们。

  • LIBFOO_SUBDIR,该变量可能包含一个子目录名字,该目录包含一些配置脚本。在一些场景下,这是很有用的,比如,程序的配置脚本并不是从 tarball 解压出来之后的根目录中,而是在其他目录中。 编译 HOST 包的时候,如果 HOST_LIBFOO_SUBDIR 没有指定,则默认使用 LIBFOO_SUBDIR.
  • LIBFOO_CONF_ENV, 指定一些环境变量并传递到配置脚本中。默认为空。
  • LIBFOO_CONF_OPTS, 指定一些额外的配置选项传递给配置脚本,默认为空。
  • LIBFOO_MAKE, 指定一个替代 make 的命令,当在配置中指定一个并行的 make (使用 BR2_JLEVEL )时这通常都非常有用,但是经常因为这样或者那样的原因被禁用。 默认情况下被设置到 $(MAKE) 中。如果并行编译不支持,那么他应该设置为 LIBFOO_MAKE=$(MAKE1).
  • LIBFOO_MAKE_ENV, 指定一些额外的环境变量传递到构建过程中(build step)。在执行 make 之前就会先将这些变量设置上。 默认为空。
  • LIBFOO_MAKE_OPTS, 指定一些额外的选项并传递到构建过程中(build step)。这些选项是在执行 make 命令后被传递。默认为空。
  • LIBFOO_AUTORECONF, 标识该 package 是否应该重新配置(即: 是佛应该重新运行 autoconf, automake, libtool ... 来重新生成配置脚本和 Makefile.in 文件)。 可选的值有 YESNO。默认情况下该值为 NO
  • LIBFOO_AUTORECONF_ENV, 指定一些额外的环境变量并传递到 autoreconf 程序, 前提是 LIBFOO_AUTORECONF=YES 被设置上。默认为空。
  • LIBFOO_AUTORECONF_OPTS 指定一些额外的选项并传递到 autoreconf 程序,前提是 LIBFOO_AUTORECONF=YES 被设置上,默认为空。
  • LIBFOO_GETTEXTIZE, 告诉 package 是否因该被 gettextized (即: 如果 package 使用的 gettext version 不同于 Buildroot 提供的版本,那么此时需要运行 gettextize) 。 该变量仅在 LIBFOO_AUTORECONF=YES 设置上时生效。 有效值可为 YES 或者 NO。默认值为 NO.
  • LIBFOO_GETTEXTIZE_OPTS, 指定一些额外的选项传递到 gettextize 程序,如果 LIBFOO_GETTEXTIZE=YES。 例如,如果 .po 文件并不再通常的位置,默认情况下可能需要 -f 来进行指定,那么此时你可能需要用到该变量。
  • LIBFOO_LIBTOOL_PATCH 告诉 Buildroot 是否应该对交叉编译工具 libtool 打补丁,可选的值有 YESNO。默认情况下,该值为 YES
  • LIBFOO_INSTALL_STAGING_OPTS 包含用于将包安装到 staging 目录的 make 选项。 默认情况下,该值为 DESTDIR=$(STAGING_DIR) install, 对于大多数 autotools 包都是正确的,但是还是有可能会需要通过该指令进行修正。
  • LIBFOO_INSTALL_TARGET_OPTS 包含 install 过程中有可能使用到的 make 选项。默认情况下该值为 DESTDIR=$(TARGET_DIR) install。 对于大多数 autotools 包都是正确的,但是还是有可能会需要通过该指令进行修正。ui拒绝拒绝拒绝仅仅急哦哦

使用 autotools 架构,构建和安装包所需的所有步骤都已经定义,它们通常适用于大多数基于 autotools 的包。 但是,在特殊情况下,也可以自定义在任何特定步骤中的操作:

  • 通过添加各个步骤的后期钩子(hook)即可实现(可在 extract, patch, configure, build 和 install 之后添加 参考:Section 18.22, “Hooks available in the various build steps” 获取详细信息。
  • 通过重写想要的步骤。比如,如果你使用的是 autotools 架构的包,并且如果你在 .mk 中实现了 LIBFOO_CONFIGURE_CMDS 变量,那么在配置时会执行该变量中的规则(或者指令)。 但,使用这些变量要非常小心,只有在你非常清楚修改的结构(后果)的情况下操作,否则 Buildroot 可能出现意料之外的结果。

18.7. 基于 CMake-based 的包

18.7.1. cmake-package 入门手册

首先,我们来看一下如何编写一个 CMake 类型的 .mk 文件,如下所示:

01: ################################################################################
02: #
03: # libfoo
04: #
05: ################################################################################
06:
07: LIBFOO_VERSION = 1.0
08: LIBFOO_SOURCE = libfoo-$(LIBFOO_VERSION).tar.gz
09: LIBFOO_SITE = http://www.foosoftware.org/download
10: LIBFOO_INSTALL_STAGING = YES
11: LIBFOO_INSTALL_TARGET = NO
12: LIBFOO_CONF_OPTS = -DBUILD_DEMOS=ON
13: LIBFOO_DEPENDENCIES = libglib2 host-pkgconf
14:
15: $(eval $(cmake-package))

在第 7 行,我们定义了该包的版本号。

在第 8 或 9 行,我们定义了该包的名字和下载路径(本地或者网络中的)。buildroot 将会从该地址自动下载该 package。

在第 10 行,我们告诉了 Buildroot 需要安装的 staging 目录,默认路径在 output/staging/。 默认情况下只需要将开发过程中编译的依赖库安装到该目录,而不是全部的安装文件。并且默认情况下,当启用了安装到 staging 目录功能之后会调用 package 的 make install 将目标文件安装到该目录。

在第 11 行,我们告诉该 package 不要安装到 target 目录。该目录包含了那些运行在目标系统上的根文件系统。对于静态库,是不需要安装到此处的,因为他们并不会在运行时使用到。 默认情况下,target 的安装选项是默认启动的,而将该变量设置成 NO 几乎是很少用到。 同样默认情况下,安装时候执行命令为 make install.

在第 12 行,我们告诉了在执行 CMake 时需要携带的一些选项。

在第 13 行,我们定义了该 package 的一些依赖,而这些依赖将会在编译该 package 前编译。

最后在第 15 行,我们调用 cmake-package 宏,来生成编译过程中所用到的所有 makefile 的 rules。

18.7.2. cmake-package reference

Buildroot 中 CMake 编译架构使用的宏是 cmake-package, 它和 generic-package 宏类似。 其 host package 同样可用为 host-cmake-package 宏。

和通用编译架构一样,Buildroot 也为 CMake 定义了一组可在 cmake-package 前调用的宏。

首先,所有的在通用编译架构中可以使用的 matedata 信息都可以在 CMake 编译架构中使用到: LIBFOO_VERSION, LIBFOO_SOURCE, LIBFOO_PATCH, LIBFOO_SITE, LIBFOO_SUBDIR, LIBFOO_DEPENDENCIES, LIBFOO_INSTALL_STAGING, LIBFOO_INSTALL_TARGET.

还有一些特殊的专门为 CMake 定制的宏可在一些特殊的场合使用到(普通的一些 package 并不常用到他们)。

  • LIBFOO_SUBDIR 可能设置为一个子目录,而该目录中可能存在一些 CMakeLists.txt 文件。 这在某些场合是很有用的,比如说 CMakeLists.txt 文件并不在 tarball 解压的更目录中。 与之想对应的 HOS_LIBFOO_SUBDIR 则可用于指定 Host 的 CMakeLists.txt。 如果 HOS_LIBFOO_SUBDIR 不存在,则默认为 LIBFOO_SUBDIR
  • LIBFOO_CONF_ENV, 指定额外的环境变量传递到 CMake 编译中。默认为空。
  • LIBFOO_CONF_OPTS, 制定额外的一些配置传递到 CMake 中。 默认为空。一些通用的配置选项会在 cmake-package 中设置,因此正常情况下,并不需要额外去设置他们,除非你想重写他们。

    • CMAKE_BUILD_TYPEBR2_ENABLE_DEBUG 决定;
    • CMAKE_INSTALL_PREFIX;
    • BUILD_SHARED_LIBSBR2_STATIC_LIBS 决定;
    • BUILD_DOC, BUILD_DOCS 被禁止;
    • BUILD_EXAMPLE, BUILD_EXAMPLES 被禁止;
    • BUILD_TEST, BUILD_TESTS, BUILD_TESTING 被禁止.
  • LIBFOO_SUPPORTS_IN_SOURCE_BUILD = NO,该选项在 package 不能在源码树内建构,而需要另外新建一个目录建构时设置;
  • LIBFOO_MAKE, 指定可选的 make 指令。 在使用多线程编译( BR2_JLEVEL )时这个功能很有用,但是对于给定的 package 该功能最好禁用。 默认情况下,会设置成 $(MAKE)。如果并行构建并不适用于该 package,那么该变量应该设置为 LIBFOO_MAKE=$(MAKE1)
  • LIBFOO_MAKE_ENV,指定一些额外的环境变量传递到 build 过程。这些环境变量会在调用 make 前设置。默认为空。
  • LIBFOO_MAKE_OPTS, 指定一组额外的变量传递到 build 过程,这些环境变量将会在执行玩 make 之后设置。默认为空。
  • LIBFOO_INSTALL_OPTS 包含一组 make 选项,在 package 安装到 host 目录的时候使用。默认情况下,该值为 install, 对于大多数 CMake package 你都不需要修改。
  • LIBFOO_INSTALL_STAGING_OPTS 包含一组 make 选项,在安装文件到 staging 目录的时候使用, 默认情况下,该值为 DESTDIR=$(STAGING_DIR) install/fast, 对于大多数 CMake package 你都不需要修改。
  • LIBFOO_INSTALL_TARGET_OPTS 包含一组 make 选项,在安装文件到 target 目录的时候使用, 该变量的默认值为 DESTDIR=$(TARGET_DIR) install/fast。 对于大多数 CMake package 你都不需要修改。

对于 CMake 编译架构,需要编译安装的 package 的所有步骤都已经事先定义好,而且对于大多数 CMake-base 的 package 都是无需修改的。 当然,如果你一定需要客制化其中的任何步骤,这都是可行的。

  • 通过添加 post-operation hook (在 extract, patch, configure, build install 之后) 实现,请参考 Section 18.22, “Hooks available in the various build steps” 获取更多详细信息。
  • 通过重写某些步骤实现。比如,你在 package 的 .mk 文件中实现了 LIBFOO_CONFIGURE_CMDS 变量,该变量的过程被执行到的时候将会执行该变量中编写的规则。 而该功能应该非常谨慎的使用,除非你非常清楚你自己在做什么事情。

18.8. Infrastructure for Python packages

该编译框架采用 python 的标准(Python setuptools)来建构其系统,通常情况下将会识别 package 中的 setup.py 脚本。

18.8.1. python-package tutorial

首先,让我们先看一下,如何为 python package 编写一个 .mk 文件。下面是一个例子:

01: ################################################################################
02: #
03: # python-foo
04: #
05: ################################################################################
06:
07: PYTHON_FOO_VERSION = 1.0
08: PYTHON_FOO_SOURCE = python-foo-$(PYTHON_FOO_VERSION).tar.xz
09: PYTHON_FOO_SITE = http://www.foosoftware.org/download
10: PYTHON_FOO_LICENSE = BSD-3-Clause
11: PYTHON_FOO_LICENSE_FILES = LICENSE
12: PYTHON_FOO_ENV = SOME_VAR=1
13: PYTHON_FOO_DEPENDENCIES = libmad
14: PYTHON_FOO_SETUP_TYPE = distutils
15:
16: $(eval $(python-package))

在第 7 行,我们定义了该包的版本号。

在第 8 - 9 行,我们定义了该 package 的名字,以及起在本地或者网络中的地址。 Buildroot 将会根据此处提供的信息来获取改 package。

在第 10 - 11 行,我们给定了该 package 的 lisence 信息。第 10 行为 license 规范,而第 11 行则为该 license 文件。

在第 12 行,我们定制了一些客制化选项在 package 配置的时候传递给 Python setup.py 脚本。

在第 13 行,我们定义了该 package 的依赖,这样这些依赖将会在编译该 package 之前被编译。

在第 14 行,我们制订了 Python 的编译系统。在这个例子中我们使用的是 distutils,总共支持两种编译系统,一种是 distutils, 另外一种是 setuptools

在第 16 行,我们调用了 python-package 宏指令来生成该包编译过程中使用的所有 Makefile 的规则。

18.8.2. python-package reference

作为一个策略,Buildroot 中作为 Python module 的 package 仅支持命名为 python-<something>。 其他使用 python build system 但是不是作为 python 的 modules 的 package 可以自由的选择他们的名字,(比如说 buildroot 中提供的这两个包 scons and supervisor )。

Package 如果仅仅兼容 python 的某一个版本(Python 2 或者 Python 3),那么应该在显示的在 Config.in 中标识,( BR2_PACKAGE_PYTHON 代表为 Python 2, BR2_PACKAGE_PYTHON3 代表为 Python 3)。 如果都兼容,则不需要特殊提及,因为该条件在 “External python modules” 菜单中已经被提及。

编译 Python module 的宏为 python-package, 和 generic-package 类似。其还可以通过 host-python-package 宏来创建 host 端的 python module。

和通用编译框架类似,python 编译框架同样具备一组在调用 python-package 或者 host-python-package 时被引用的变量。

所有存在于 generic package infrastructure 中的元信息都可以用于 python 编译架构中,如: PYTHON_FOO_VERSION, PYTHON_FOO_SOURCE, PYTHON_FOO_PATCH, PYTHON_FOO_SITE, PYTHON_FOO_SUBDIR, PYTHON_FOO_DEPENDENCIES, PYTHON_FOO_LICENSE, PYTHON_FOO_LICENSE_FILES, PYTHON_FOO_INSTALL_STAGING, 等

注意:

  • 该类 package 并不需要设置将 python 或者 host-python 以来设置给 PYTHON_FOO_DEPENDENCIES, 因为 Buildroot 会自动将这些基础包加到依赖中。
  • 同样,对于基于 setuptools 的包,不需要将 host-setuptools 添加到 PYTHON_FOO_DEPENDENCIES,因为它是由 Python 基础编译架构根据需要自动添加的。

但是 Python 基础编译框架需要设置一个变量:

  • PYTHON_FOO_SETUP_TYPE, 该变量定义将用哪一个 Python Build system 进行编译。该变量支持两个值 distutilssetuptools。 如果你不知道应该用哪种编译方式,请查看源码中的 setuo.py 文件,还可以查看是否有从 distutils 或者 setuptools 中 import 一些东西。

根据包的需要,可以选择定义一些特定于 Python 编译架构的附加变量。 它们中的许多只在非常特定的情况下有用,因此典型的包只会使用其中的几个,或者根本不使用。

  • PYTHON_FOO_SUBDIR:有些 package 可能会将 setup.py 放到该工程的某个子目录,那么这个时候可以通过该变量来指定。 而对于 host 端的 package 如果没有指定 HOST_PYTHON_FOO_SUBDIR,那么则会默认使用该变量。
  • PYTHON_FOO_ENV:如果想要指定一些环境变量并在执行 setup.py 的时候使用,则可以使用该变量来指定。 注意, python 基础编译框架会自动将 PKG_PYTHON_DISTUTILS_ENV (distutils 类型 pacakge), HOST_PKG_PYTHON_DISTUTILS_ENV(distutils 类型 package), PKG_PYTHON_SETUPTOOLS_ENV ( setuptools 类型 packages) and HOST_PKG_PYTHON_SETUPTOOLS_ENV (setuptools 类型的 host packages) 传递到 setup.py 中。
  • PYTHON_FOO_BUILD_OPTS, to specify additional options to pass to the Python setup.py script during the build step. For target distutils packages, the PKG_PYTHON_DISTUTILS_BUILD_OPTS options are already passed automatically by the infrastructure.
  • PYTHON_FOO_INSTALL_TARGET_OPTS, PYTHON_FOO_INSTALL_STAGING_OPTSHOST_PYTHON_FOO_INSTALL_OPTSsetup.py 脚本指定了一些额外的选项。在安装的时候使用。 注意:该编译架构会自动的将定义在 PKG_PYTHON_DISTUTILS_INSTALL_TARGET_OPTS 或者 PKG_PYTHON_DISTUTILS_INSTALL_STAGING_OPTS (distutils 类型 packages), HOST_PKG_PYTHON_DISTUTILS_INSTALL_OPTS ( host 端 distutils 类型 packages), PKG_PYTHON_SETUPTOOLS_INSTALL_TARGET_OPTS 或者 PKG_PYTHON_SETUPTOOLS_INSTALL_STAGING_OPTS (setuptools 类型 packages) 和 HOST_PKG_PYTHON_SETUPTOOLS_INSTALL_OPTS (host 端 setuptools 类型 packages) 中的选项传递到 setup.py 中。
  • HOST_PYTHON_FOO_NEEDS_HOST_PYTHON: 定义 host 端 python 解释器的版本。该变量仅限于 host 端 pachage。支持两个值 python2python3。 这确保包在使用的时候被正确的 python 版本解释。 如果在某些步骤被覆盖了,那么在执行的时候应该显示的指定。

对于需要 Python 编译架构编译的 package 所有编译过程中使用的步骤都被预先定义,对于大多数 package 我们都不需要做太多的工作。 当然,特殊情况下,还是可被定制化:

  • 需要在执行某一个步骤之前增加 hook (如,在 extract, patch, configure, build or install 之后)。参考 Section 18.22, “Hooks available in the various build steps” 获取更多详细信息。
  • 需要重写一个或者多个步骤。比如,如果在 package 的 .mk 中定义了 PYTHON_FOO_BUILD_CMDS, 那么在执行编译步骤的时候将会使用该变量中定义的规则来编译。 然而,除非你非常清楚你的行动的目的,否则,请使用默认的编译流程。

18.8.3. Generating a python-package from a PyPI repository

如果你想在 Buildroot 中创建一个 Buildroot package 使之可以在 PyPI 上可用,有可能需要使用 utils/ 中的 scanpupi 工具来自动化这个过程,

你可以在 此处 找到 PyPI 包的列表。

scanpypi 需要安装 Python’s 的 setuptools 包到你的 host 主机上。

当你在 buildroot 的根目录时,你可以执行:

utils/scanpypi foo bar -o package

如果 foo 和 bar 能在 https://pypi.python.org 中找到, 这将在 package 目录中生成 python-foopython-bar

找到 external python modules 菜单,并将你的 package 添加到其中,确保这些条目服从字母排序。

请记住,您很可能需要手动检查包中包含的错误,因为有些东西是生成器无法猜测的(例如,是否依赖于任何 python 核心模块,如 BR2_PACKAGE_PYTHON_ZLIB)。 另外,请注意许可证和许可证文件的估计是可能出错的,必须检查。您还需要手动将包添加到 package/Config.in 文件中。

如果你的 buildroot package 不再官方的 Buildroot tree 中(可能在 br2-external tree 中),请使用 -o flag,如下所示:

utils/scanpypi foo bar -o other_package_dir

这将生成包 python-foopython-barother_package_directory 目录中,而不是 package 目录中。

执行选项 -h 将会列出所有支持选项:

utils/scanpypi -h

18.8.4. python-package CFFI backend

Python 的 C 外来函数接口 (CFFI) 提供了一种使用 C 语言编写的接口声明从 Python 调用已编译的 C 代码的方便可靠的方法。依赖此后端的 Python 包可以通过其文件字段中出现的cffi依赖项 来识别. install_requiressetup.py C Foreign Function Interface for Python (CFFI) provides a convenient and reliable way to call compiled C code from Python using interface declarations written in C. Python packages relying on this backend can be identified by the appearance of a cffi dependency in the install_requires field of their setup.py file.

这样的包应该:

  • 添加python-cffi为运行时依赖项,以便在目标上安装已编译的 C 库包装器。这是通过添加select BR2_PACKAGE_PYTHON_CFFI到包来实现的 Config.in。 add python-cffi as a runtime dependency in order to install the compiled C library wrapper on the target. This is achieved by adding select BR2_PACKAGE_PYTHON_CFFI to the package Config.in.
config BR2_PACKAGE_PYTHON_FOO
        bool "python-foo"
        select BR2_PACKAGE_PYTHON_CFFI # runtime
  • 添加host-python-cffi为构建时依赖项,以便交叉编译 C 包装器。这是通过添加host-python-cffi到PYTHON_FOO_DEPENDENCIES变量来实现的 。 add host-python-cffi as a build-time dependency in order to cross-compile the C wrapper. This is achieved by adding host-python-cffi to the PYTHON_FOO_DEPENDENCIES variable.
################################################################################
#
# python-foo
#
################################################################################

...

PYTHON_FOO_DEPENDENCIES = host-python-cffi

$(eval $(python-package))

18.9. Infrastructure for LuaRocks-based packages

18.9.1. luarocks-package tutorial

首先,让我们看看如何.mk为基于 LuaRocks 的包编写文件,举例: First, let’s see how to write a .mk file for a LuaRocks-based package, with an example :

01: ################################################################################
02: #
03: # lua-foo
04: #
05: ################################################################################
06:
07: LUA_FOO_VERSION = 1.0.2-1
08: LUA_FOO_NAME_UPSTREAM = foo
09: LUA_FOO_DEPENDENCIES = bar
10:
11: LUA_FOO_BUILD_OPTS += BAR_INCDIR=$(STAGING_DIR)/usr/include
12: LUA_FOO_BUILD_OPTS += BAR_LIBDIR=$(STAGING_DIR)/usr/lib
13: LUA_FOO_LICENSE = luaFoo license
14: LUA_FOO_LICENSE_FILES = $(LUA_FOO_SUBDIR)/COPYING
15:
16: $(eval $(luarocks-package))

On line 7, we declare the version of the package (the same as in the rockspec, which is the concatenation of the upstream version and the rockspec revision, separated by a hyphen - ).

On line 8, we declare that the package is called "foo" on LuaRocks. In Buildroot, we give Lua-related packages a name that starts with "lua", so the Buildroot name is different from the upstream name. LUA_FOO_NAME_UPSTREAM makes the link between the two names.

On line 9, we declare our dependencies against native libraries, so that they are built before the build process of our package starts.

On lines 11-12, we tell Buildroot to pass custom options to LuaRocks when it is building the package.

On lines 13-14, we specify the licensing terms for the package.

Finally, on line 16, we invoke the luarocks-package macro that generates all the Makefile rules that actually allows the package to be built.

Most of these details can be retrieved from the rock and rockspec. So, this file and the Config.in file can be generated by running the command luarocks buildroot foo lua-foo in the Buildroot directory. This command runs a specific Buildroot addon of luarocks that will automatically generate a Buildroot package. The result must still be manually inspected and possibly modified.

  • The package/Config.in file has to be updated manually to include the generated Config.in files.

18.9.2. luarocks-package reference

LuaRocks is a deployment and management system for Lua modules, and supports various build.type: builtin, make and cmake. In the context of Buildroot, the luarocks-package infrastructure only supports the builtin mode. LuaRocks packages that use the make or cmake build mechanisms should instead be packaged using the generic-package and cmake-package infrastructures in Buildroot, respectively.

The main macro of the LuaRocks package infrastructure is luarocks-package: like generic-package it works by defining a number of variables providing metadata information about the package, and then calling luarocks-package.

Just like the generic infrastructure, the LuaRocks infrastructure works by defining a number of variables before calling the luarocks-package macro.

First, all the package metadata information variables that exist in the generic infrastructure also exist in the LuaRocks infrastructure: LUA_FOO_VERSION, LUA_FOO_SOURCE, LUA_FOO_SITE, LUA_FOO_DEPENDENCIES, LUA_FOO_LICENSE, LUA_FOO_LICENSE_FILES.

Two of them are populated by the LuaRocks infrastructure (for the download step). If your package is not hosted on the LuaRocks mirror $(BR2_LUAROCKS_MIRROR), you can override them:

  • LUA_FOO_SITE, which defaults to $(BR2_LUAROCKS_MIRROR)
  • LUA_FOO_SOURCE, which defaults to $(lowercase LUA_FOO_NAME_UPSTREAM)-$(LUA_FOO_VERSION).src.rock

A few additional variables, specific to the LuaRocks infrastructure, are also defined. They can be overridden in specific cases.

  • LUA_FOO_NAME_UPSTREAM, which defaults to lua-foo, i.e. the Buildroot package name
  • LUA_FOO_ROCKSPEC, which defaults to $(lowercase LUA_FOO_NAME_UPSTREAM)-$(LUA_FOO_VERSION).rockspec
  • LUA_FOO_SUBDIR, which defaults to $(LUA_FOO_NAME_UPSTREAM)-$(LUA_FOO_VERSION_WITHOUT_ROCKSPEC_REVISION)
  • LUA_FOO_BUILD_OPTS contains additional build options for the luarocks build call.

18.10. Infrastructure for Perl/CPAN packages

18.10.1. perl-package tutorial

First, let’s see how to write a .mk file for a Perl/CPAN package, with an example :

01: ################################################################################
02: #
03: # perl-foo-bar
04: #
05: ################################################################################
06:
07: PERL_FOO_BAR_VERSION = 0.02
08: PERL_FOO_BAR_SOURCE = Foo-Bar-$(PERL_FOO_BAR_VERSION).tar.gz
09: PERL_FOO_BAR_SITE = $(BR2_CPAN_MIRROR)/authors/id/M/MO/MONGER
10: PERL_FOO_BAR_DEPENDENCIES = perl-strictures
11: PERL_FOO_BAR_LICENSE = Artistic or GPL-1.0+
12: PERL_FOO_BAR_LICENSE_FILES = LICENSE
13: PERL_FOO_BAR_DISTNAME = Foo-Bar
14:
15: $(eval $(perl-package))

On line 7, we declare the version of the package.

On line 8 and 9, we declare the name of the tarball and the location of the tarball on a CPAN server. Buildroot will automatically download the tarball from this location.

On line 10, we declare our dependencies, so that they are built before the build process of our package starts.

On line 11 and 12, we give licensing details about the package (its license on line 11, and the file containing the license text on line 12).

On line 13, the name of the distribution as needed by the script utils/scancpan (in order to regenerate/upgrade these package files).

Finally, on line 15, we invoke the perl-package macro that generates all the Makefile rules that actually allow the package to be built.

Most of these data can be retrieved from https://metacpan.org/. So, this file and the Config.in can be generated by running the script utils/scancpan Foo-Bar in the Buildroot directory (or in a br2-external tree). This script creates a Config.in file and foo-bar.mk file for the requested package, and also recursively for all dependencies specified by CPAN. You should still manually edit the result. In particular, the following things should be checked.

  • If the perl module links with a shared library that is provided by another (non-perl) package, this dependency is not added automatically. It has to be added manually to PERL_FOO_BAR_DEPENDENCIES.
  • The package/Config.in file has to be updated manually to include the generated Config.in files. As a hint, the scancpan script prints out the required source "…" statements, sorted alphabetically.

18.10.2. perl-package reference

As a policy, packages that provide Perl/CPAN modules should all be named perl-<something> in Buildroot.

This infrastructure handles various Perl build systems : ExtUtils-MakeMaker (EUMM), Module-Build (MB) and Module-Build-Tiny. Build.PL is preferred by default when a package provides a Makefile.PL and a Build.PL.

The main macro of the Perl/CPAN package infrastructure is perl-package. It is similar to the generic-package macro. The ability to have target and host packages is also available, with the host-perl-package macro.

Just like the generic infrastructure, the Perl/CPAN infrastructure works by defining a number of variables before calling the perl-package macro.

First, all the package metadata information variables that exist in the generic infrastructure also exist in the Perl/CPAN infrastructure: PERL_FOO_VERSION, PERL_FOO_SOURCE, PERL_FOO_PATCH, PERL_FOO_SITE, PERL_FOO_SUBDIR, PERL_FOO_DEPENDENCIES, PERL_FOO_INSTALL_TARGET.

Note that setting PERL_FOO_INSTALL_STAGING to YES has no effect unless a PERL_FOO_INSTALL_STAGING_CMDS variable is defined. The perl infrastructure doesn’t define these commands since Perl modules generally don’t need to be installed to the staging directory.

A few additional variables, specific to the Perl/CPAN infrastructure, can also be defined. Many of them are only useful in very specific cases, typical packages will therefore only use a few of them.

  • PERL_FOO_PREFER_INSTALLER/HOST_PERL_FOO_PREFER_INSTALLER, specifies the preferred installation method. Possible values are EUMM (for Makefile.PL based installation using ExtUtils-MakeMaker) and MB (for Build.PL based installation using Module-Build). This variable is only used when the package provides both installation methods.
  • PERL_FOO_CONF_ENV/HOST_PERL_FOO_CONF_ENV, to specify additional environment variables to pass to the perl Makefile.PL or perl Build.PL. By default, empty.
  • PERL_FOO_CONF_OPTS/HOST_PERL_FOO_CONF_OPTS, to specify additional configure options to pass to the perl Makefile.PL or perl Build.PL. By default, empty.
  • PERL_FOO_BUILD_OPTS/HOST_PERL_FOO_BUILD_OPTS, to specify additional options to pass to make pure_all or perl Build build in the build step. By default, empty.
  • PERL_FOO_INSTALL_TARGET_OPTS, to specify additional options to pass to make pure_install or perl Build install in the install step. By default, empty.
  • HOST_PERL_FOO_INSTALL_OPTS, to specify additional options to pass to make pure_install or perl Build install in the install step. By default, empty.

18.11. Infrastructure for virtual packages

In Buildroot, a virtual package is a package whose functionalities are provided by one or more packages, referred to as providers . The virtual package management is an extensible mechanism allowing the user to choose the provider used in the rootfs.

For example, OpenGL ES is an API for 2D and 3D graphics on embedded systems. The implementation of this API is different for the Allwinner Tech Sunxi and the Texas Instruments OMAP35xx platforms. So libgles will be a virtual package and sunxi-mali and ti-gfx will be the providers.

18.11.1. virtual-package tutorial

In the following example, we will explain how to add a new virtual package ( something-virtual ) and a provider for it ( some-provider ).

First, let’s create the virtual package.

18.11.2. Virtual package’s Config.in file

The Config.in file of virtual package something-virtual should contain:

01: config BR2_PACKAGE_HAS_SOMETHING_VIRTUAL
02:     bool
03:
04: config BR2_PACKAGE_PROVIDES_SOMETHING_VIRTUAL
05:     depends on BR2_PACKAGE_HAS_SOMETHING_VIRTUAL
06:     string

In this file, we declare two options, BR2_PACKAGE_HAS_SOMETHING_VIRTUAL and BR2_PACKAGE_PROVIDES_SOMETHING_VIRTUAL, whose values will be used by the providers.

18.11.3. Virtual package’s .mk file

The .mk for the virtual package should just evaluate the virtual-package macro:

01: ################################################################################
02: #
03: # something-virtual
04: #
05: ################################################################################
06:
07: $(eval $(virtual-package))

The ability to have target and host packages is also available, with the host-virtual-package macro.

18.11.4. Provider’s Config.in file

When adding a package as a provider, only the Config.in file requires some modifications.

The Config.in file of the package some-provider , which provides the functionalities of something-virtual , should contain:

01: config BR2_PACKAGE_SOME_PROVIDER
02:     bool "some-provider"
03:     select BR2_PACKAGE_HAS_SOMETHING_VIRTUAL
04:     help
05:       This is a comment that explains what some-provider is.
06:
07:       http://foosoftware.org/some-provider/
08:
09: if BR2_PACKAGE_SOME_PROVIDER
10: config BR2_PACKAGE_PROVIDES_SOMETHING_VIRTUAL
11:     default "some-provider"
12: endif

On line 3, we select BR2_PACKAGE_HAS_SOMETHING_VIRTUAL, and on line 11, we set the value of BR2_PACKAGE_PROVIDES_SOMETHING_VIRTUAL to the name of the provider, but only if it is selected.

18.11.5. Provider’s .mk file

The .mk file should also declare an additional variable SOME_PROVIDER_PROVIDES to contain the names of all the virtual packages it is an implementation of:

01: SOME_PROVIDER_PROVIDES = something-virtual

Of course, do not forget to add the proper build and runtime dependencies for this package!

18.11.6. Notes on depending on a virtual package

When adding a package that requires a certain FEATURE provided by a virtual package, you have to use depends on BR2_PACKAGE_HAS_FEATURE, like so:

config BR2_PACKAGE_HAS_FEATURE
    bool

config BR2_PACKAGE_FOO
    bool "foo"
    depends on BR2_PACKAGE_HAS_FEATURE

18.11.7. Notes on depending on a specific provider

If your package really requires a specific provider, then you’ll have to make your package depends on this provider; you can not select a provider.

Let’s take an example with two providers for a FEATURE:

config BR2_PACKAGE_HAS_FEATURE
    bool

config BR2_PACKAGE_FOO
    bool "foo"
    select BR2_PACKAGE_HAS_FEATURE

config BR2_PACKAGE_BAR
    bool "bar"
    select BR2_PACKAGE_HAS_FEATURE

And you are adding a package that needs FEATURE as provided by foo, but not as provided by bar.

If you were to use select BR2_PACKAGE_FOO, then the user would still be able to select BR2_PACKAGE_BAR in the menuconfig. This would create a configuration inconsistency, whereby two providers of the same FEATURE would be enabled at once, one explicitly set by the user, the other implicitly by your select.

Instead, you have to use depends on BR2_PACKAGE_FOO, which avoids any implicit configuration inconsistency.

18.12. Infrastructure for packages using kconfig for configuration files

A popular way for a software package to handle user-specified configuration is kconfig. Among others, it is used by the Linux kernel, Busybox, and Buildroot itself. The presence of a .config file and a menuconfig target are two well-known symptoms of kconfig being used.

Buildroot features an infrastructure for packages that use kconfig for their configuration. This infrastructure provides the necessary logic to expose the package’s menuconfig target as foo-menuconfig in Buildroot, and to handle the copying back and forth of the configuration file in a correct way.

The kconfig-package infrastructure is based on the generic-package infrastructure. All variables supported by generic-package are available in kconfig-package as well. See Section 18.5.2, “generic-package reference” for more details.

In order to use the kconfig-package infrastructure for a Buildroot package, the minimally required lines in the .mk file, in addition to the variables required by the generic-package infrastructure, are:

FOO_KCONFIG_FILE = reference-to-source-configuration-file

$(eval $(kconfig-package))

This snippet creates the following make targets:

  • foo-menuconfig, which calls the package’s menuconfig target
  • foo-update-config, which copies the configuration back to the source configuration file. It is not possible to use this target when fragment files are set.
  • foo-update-defconfig, which copies the configuration back to the source configuration file. The configuration file will only list the options that differ from the default values. It is not possible to use this target when fragment files are set.
  • foo-diff-config, which outputs the differences between the current configuration and the one defined in the Buildroot configuration for this kconfig package. The output is useful to identify the configuration changes that may have to be propagated to configuration fragments for example.

and ensures that the source configuration file is copied to the build directory at the right moment.

There are two options to specify a configuration file to use, either FOO_KCONFIG_FILE (as in the example, above) or FOO_KCONFIG_DEFCONFIG. It is mandatory to provide either, but not both:

  • FOO_KCONFIG_FILE specifies the path to a defconfig or full-config file to be used to configure the package.
  • FOO_KCONFIG_DEFCONFIG specifies the defconfig make rule to call to configure the package.

In addition to these minimally required lines, several optional variables can be set to suit the needs of the package under consideration:

  • FOO_KCONFIG_EDITORS: a space-separated list of kconfig editors to support, for example menuconfig xconfig . By default, menuconfig .
  • FOO_KCONFIG_FRAGMENT_FILES: a space-separated list of configuration fragment files that are merged to the main configuration file. Fragment files are typically used when there is a desire to stay in sync with an upstream (def)config file, with some minor modifications.
  • FOO_KCONFIG_OPTS: extra options to pass when calling the kconfig editors. This may need to include $(FOO_MAKE_OPTS) , for example. By default, empty.
  • FOO_KCONFIG_FIXUP_CMDS: a list of shell commands needed to fixup the configuration file after copying it or running a kconfig editor. Such commands may be needed to ensure a configuration consistent with other configuration of Buildroot, for example. By default, empty.
  • FOO_KCONFIG_DOTCONFIG: path (with filename) of the .config file, relative to the package source tree. The default, .config, should be well suited for all packages that use the standard kconfig infrastructure as inherited from the Linux kernel; some packages use a derivative of kconfig that use a different location.
  • FOO_KCONFIG_DEPENDENCIES: the list of packages (most probably, host packages) that need to be built before this package’s kconfig is interpreted. Seldom used. By default, empty.

18.13. Infrastructure for rebar-based packages

18.13.1. rebar-package tutorial

First, let’s see how to write a .mk file for a rebar-based package, with an example :

01: ################################################################################
02: #
03: # erlang-foobar
04: #
05: ################################################################################
06:
07: ERLANG_FOOBAR_VERSION = 1.0
08: ERLANG_FOOBAR_SOURCE = erlang-foobar-$(ERLANG_FOOBAR_VERSION).tar.xz
09: ERLANG_FOOBAR_SITE = http://www.foosoftware.org/download
10: ERLANG_FOOBAR_DEPENDENCIES = host-libaaa libbbb
11:
12: $(eval $(rebar-package))

On line 7, we declare the version of the package.

On line 8 and 9, we declare the name of the tarball (xz-ed tarball recommended) and the location of the tarball on the Web. Buildroot will automatically download the tarball from this location.

On line 10, we declare our dependencies, so that they are built before the build process of our package starts.

Finally, on line 12, we invoke the rebar-package macro that generates all the Makefile rules that actually allows the package to be built.

18.13.2. rebar-package reference

The main macro of the rebar package infrastructure is rebar-package. It is similar to the generic-package macro. The ability to have host packages is also available, with the host-rebar-package macro.

Just like the generic infrastructure, the rebar infrastructure works by defining a number of variables before calling the rebar-package macro.

First, all the package metadata information variables that exist in the generic infrastructure also exist in the rebar infrastructure: ERLANG_FOOBAR_VERSION, ERLANG_FOOBAR_SOURCE, ERLANG_FOOBAR_PATCH, ERLANG_FOOBAR_SITE, ERLANG_FOOBAR_SUBDIR, ERLANG_FOOBAR_DEPENDENCIES, ERLANG_FOOBAR_INSTALL_STAGING, ERLANG_FOOBAR_INSTALL_TARGET, ERLANG_FOOBAR_LICENSE and ERLANG_FOOBAR_LICENSE_FILES.

A few additional variables, specific to the rebar infrastructure, can also be defined. Many of them are only useful in very specific cases, typical packages will therefore only use a few of them.

  • ERLANG_FOOBAR_USE_AUTOCONF, to specify that the package uses autoconf at the configuration step. When a package sets this variable to YES, the autotools infrastructure is used.

    Note. You can also use some of the variables from the autotools infrastructure: ERLANG_FOOBAR_CONF_ENV, ERLANG_FOOBAR_CONF_OPTS, ERLANG_FOOBAR_AUTORECONF, ERLANG_FOOBAR_AUTORECONF_ENV and ERLANG_FOOBAR_AUTORECONF_OPTS.

  • ERLANG_FOOBAR_USE_BUNDLED_REBAR, to specify that the package has a bundled version of rebar and that it shall be used. Valid values are YES or NO (the default).

    Note. If the package bundles a rebar utility, but can use the generic one that Buildroot provides, just say NO (i.e., do not specify this variable). Only set if it is mandatory to use the rebar utility bundled in this package.

  • ERLANG_FOOBAR_REBAR_ENV, to specify additional environment variables to pass to the rebar utility.
  • ERLANG_FOOBAR_KEEP_DEPENDENCIES, to keep the dependencies described in the rebar.config file. Valid values are YES or NO (the default). Unless this variable is set to YES, the rebar infrastructure removes such dependencies in a post-patch hook to ensure rebar does not download nor compile them.

With the rebar infrastructure, all the steps required to build and install the packages are already defined, and they generally work well for most rebar-based packages. However, when required, it is still possible to customize what is done in any particular step:

  • By adding a post-operation hook (after extract, patch, configure, build or install). See Section 18.22, “Hooks available in the various build steps” for details.
  • By overriding one of the steps. For example, even if the rebar infrastructure is used, if the package .mk file defines its own ERLANG_FOOBAR_BUILD_CMDS variable, it will be used instead of the default rebar one. However, using this method should be restricted to very specific cases. Do not use it in the general case.

18.14. Infrastructure for Waf-based packages

18.14.1. waf-package tutorial

First, let’s see how to write a .mk file for a Waf-based package, with an example :

01: ################################################################################
02: #
03: # libfoo
04: #
05: ################################################################################
06:
07: LIBFOO_VERSION = 1.0
08: LIBFOO_SOURCE = libfoo-$(LIBFOO_VERSION).tar.gz
09: LIBFOO_SITE = http://www.foosoftware.org/download
10: LIBFOO_CONF_OPTS = --enable-bar --disable-baz
11: LIBFOO_DEPENDENCIES = bar
12:
13: $(eval $(waf-package))

On line 7, we declare the version of the package.

On line 8 and 9, we declare the name of the tarball (xz-ed tarball recommended) and the location of the tarball on the Web. Buildroot will automatically download the tarball from this location.

On line 10, we tell Buildroot what options to enable for libfoo.

On line 11, we tell Buildroot the dependencies of libfoo.

Finally, on line line 13, we invoke the waf-package macro that generates all the Makefile rules that actually allows the package to be built.

18.14.2. waf-package reference

The main macro of the Waf package infrastructure is waf-package. It is similar to the generic-package macro.

Just like the generic infrastructure, the Waf infrastructure works by defining a number of variables before calling the waf-package macro.

First, all the package metadata information variables that exist in the generic infrastructure also exist in the Waf infrastructure: LIBFOO_VERSION, LIBFOO_SOURCE, LIBFOO_PATCH, LIBFOO_SITE, LIBFOO_SUBDIR, LIBFOO_DEPENDENCIES, LIBFOO_INSTALL_STAGING, LIBFOO_INSTALL_TARGET.

An additional variable, specific to the Waf infrastructure, can also be defined.

  • LIBFOO_SUBDIR may contain the name of a subdirectory inside the package that contains the main wscript file. This is useful, if for example, the main wscript file is not at the root of the tree extracted by the tarball. If HOST_LIBFOO_SUBDIR is not specified, it defaults to LIBFOO_SUBDIR.
  • LIBFOO_NEEDS_EXTERNAL_WAF can be set to YES or NO to tell Buildroot to use the bundled waf executable. If set to NO, the default, then Buildroot will use the waf executable provided in the package source tree; if set to YES, then Buildroot will download, install waf as a host tool and use it to build the package.
  • LIBFOO_WAF_OPTS, to specify additional options to pass to the waf script at every step of the package build process: configure, build and installation. By default, empty.
  • LIBFOO_CONF_OPTS, to specify additional options to pass to the waf script for the configuration step. By default, empty.
  • LIBFOO_BUILD_OPTS, to specify additional options to pass to the waf script during the build step. By default, empty.
  • LIBFOO_INSTALL_STAGING_OPTS, to specify additional options to pass to the waf script during the staging installation step. By default, empty.
  • LIBFOO_INSTALL_TARGET_OPTS, to specify additional options to pass to the waf script during the target installation step. By default, empty.

18.15. Infrastructure for Meson-based packages

18.15.1. meson-package tutorial

Meson is an open source build system meant to be both extremely fast, and, even more importantly, as user friendly as possible. It uses Ninja as a companion tool to perform the actual build operations.

Let’s see how to write a .mk file for a Meson-based package, with an example:

01: ################################################################################
02: #
03: # foo
04: #
05: ################################################################################
06:
07: FOO_VERSION = 1.0
08: FOO_SOURCE = foo-$(FOO_VERSION).tar.gz
09: FOO_SITE = http://www.foosoftware.org/download
10: FOO_LICENSE = GPL-3.0+
11: FOO_LICENSE_FILES = COPYING
12: FOO_INSTALL_STAGING = YES
13:
14: FOO_DEPENDENCIES = host-pkgconf bar
15:
16: ifeq ($(BR2_PACKAGE_BAZ),y)
17: FOO_CONF_OPTS += -Dbaz=true
18: FOO_DEPENDENCIES += baz
19: else
20: FOO_CONF_OPTS += -Dbaz=false
21: endif
22:
23: $(eval $(meson-package))

The Makefile starts with the definition of the standard variables for package declaration (lines 7 to 11).

On line line 23, we invoke the meson-package macro that generates all the Makefile rules that actually allows the package to be built.

In the example, host-pkgconf and bar are declared as dependencies in FOO_DEPENDENCIES at line 14 because the Meson build file of foo uses pkg-config to determine the compilation flags and libraries of package bar.

Note that it is not necessary to add host-meson in the FOO_DEPENDENCIES variable of a package, since this basic dependency is automatically added as needed by the Meson package infrastructure.

If the "baz" package is selected, then support for the "baz" feature in "foo" is activated by adding -Dbaz=true to FOO_CONF_OPTS at line 17, as specified in the meson_options.txt file in "foo" source tree. The "baz" package is also added to FOO_DEPENDENCIES. Note that the support for baz is explicitly disabled at line 20, if the package is not selected.

To sum it up, to add a new meson-based package, the Makefile example can be copied verbatim then edited to replace all occurences of FOO with the uppercase name of the new package and update the values of the standard variables.

18.15.2. meson-package reference

The main macro of the Meson package infrastructure is meson-package. It is similar to the generic-package macro. The ability to have target and host packages is also available, with the host-meson-package macro.

Just like the generic infrastructure, the Meson infrastructure works by defining a number of variables before calling the meson-package macro.

First, all the package metadata information variables that exist in the generic infrastructure also exist in the Meson infrastructure: FOO_VERSION, FOO_SOURCE, FOO_PATCH, FOO_SITE, FOO_SUBDIR, FOO_DEPENDENCIES, FOO_INSTALL_STAGING, FOO_INSTALL_TARGET.

A few additional variables, specific to the Meson infrastructure, can also be defined. Many of them are only useful in very specific cases, typical packages will therefore only use a few of them.

  • FOO_SUBDIR may contain the name of a subdirectory inside the package that contains the main meson.build file. This is useful, if for example, the main meson.build file is not at the root of the tree extracted by the tarball. If HOST_FOO_SUBDIR is not specified, it defaults to FOO_SUBDIR.
  • FOO_CONF_ENV, to specify additional environment variables to pass to meson for the configuration step. By default, empty.
  • FOO_CONF_OPTS, to specify additional options to pass to meson for the configuration step. By default, empty.
  • FOO_CFLAGS, to specify compiler arguments added to the package specific cross-compile.conf file c_args property. By default, the value of TARGET_CFLAGS.
  • FOO_CXXFLAGS, to specify compiler arguments added to the package specific cross-compile.conf file cpp_args property. By default, the value of TARGET_CXXFLAGS.
  • FOO_LDFLAGS, to specify compiler arguments added to the package specific cross-compile.conf file c_link_args and cpp_link_args properties. By default, the value of TARGET_LDFLAGS.
  • FOO_MESON_EXTRA_BINARIES, to specify a space-separated list of programs to add to the [binaries] section of the meson cross-compilation.conf configuration file. The format is program-name='/path/to/program', with no space around the = sign, and with the path of the program between single quotes. By default, empty. Note that Buildroot already sets the correct values for c, cpp, ar, strip, and pkgconfig.
  • FOO_MESON_EXTRA_PROPERTIES, to specify a space-separated list of properties to add to the [properties] section of the meson cross-compilation.conf configuration file. The format is property-name=<value> with no space around the = sign, and with single quotes around string values. By default, empty. Note that Buildroot already sets values for needs_exe_wrapper, c_args, c_link_args, cpp_args, cpp_link_args, sys_root, and pkg_config_libdir.
  • FOO_NINJA_ENV, to specify additional environment variables to pass to ninja, meson companion tool in charge of the build operations. By default, empty.
  • FOO_NINJA_OPTS, to specify a space-separated list of targets to build. By default, empty, to build the default target(s).

18.16. Integration of Cargo-based packages

Cargo is the package manager for the Rust programming language. It allows the user to build programs or libraries written in Rust, but it also downloads and manages their dependencies, to ensure repeatable builds. Cargo packages are called "crates".

18.16.1. Cargo-based package’s Config.in file

The Config.in file of Cargo-based package foo should contain:

01: config BR2_PACKAGE_FOO
02:     bool "foo"
03:     depends on BR2_PACKAGE_HOST_RUSTC_TARGET_ARCH_SUPPORTS
04:     select BR2_PACKAGE_HOST_RUSTC
05:     help
06:       This is a comment that explains what foo is.
07:
08:       http://foosoftware.org/foo/

18.16.2. Cargo-based package’s .mk file

Buildroot does not (yet) S 04: select BR2_PACKAGE_HOST_RUSTC 05: help 06: This is a comment that explains what foo is. 07: 08: http://foosoftware.org/foo/

18.16.2. Cargo-based package’s .mk file

Buildroot does not (yet) provide a dedicated package infrastructure for Cargo-based packages. So, we will explain how to write a .mk file for such a package. Let’s start with an example:

01: ################################################################################
02: #
03: # foo
04: #
05: ################################################################################
06:
07: FOO_VERSION = 1.0
08: FOO_SOURCE = foo-$(FOO_VERSION).tar.gz
09: FOO_SITE = http://www.foosoftware.org/download
10: FOO_LICENSE = GPL-3.0+
11: FOO_LICENSE_FILES = COPYING
12:
13: FOO_DEPENDENCIES = host-rustc
14:
15: FOO_CARGO_ENV = CARGO_HOME=$(HOST_DIR)/share/cargo
16:
17: FOO_BIN_DIR = target/$(RUSTC_TARGET_NAME)/$(FOO_CARGO_MODE)
18:
19: FOO_CARGO_OPTS = \
20:     $(if $(BR2_ENABLE_DEBUG),,--release) \
21:     --target=$(RUSTC_TARGET_NAME) \
22:     --manifest-path=$(@D)/Cargo.toml
23:
24: define FOO_BUILD_CMDS
25:     $(TARGET_MAKE_ENV) $(FOO_CARGO_ENV) \
26:             cargo build $(FOO_CARGO_OPTS)
27: endef
28:
29: define FOO_INSTALL_TARGET_CMDS
30:     $(INSTALL) -D -m 0755 $(@D)/$(FOO_BIN_DIR)/foo \
31:             $(TARGET_DIR)/usr/bin/foo
32: endef
33:
34: $(eval $(generic-package))

The Makefile starts with the definition of the standard variables for package declaration (lines 7 to 11).

As seen in line 34, it is based on the generic-package infrastructure. So, it defines the variables required by this particular infrastructure, where Cargo is invoked:

  • FOO_BUILD_CMDS: Cargo is invoked to perform the build. The options required to configure the cross-compilation of the package are passed via FOO_CONF_OPTS.
  • FOO_INSTALL_TARGET_CMDS: The binary executable generated is installed on the target.

In order to have Cargo available for the build, FOO_DEPENDENCIES needs to contain host-cargo.

To sum it up, to add a new Cargo-based package, the Makefile example can be copied verbatim then edited to replace all occurences of FOO with the uppercase name of the new package and update the values of the standard variables.

18.16.3. About Dependencies Management

A crate can depend on other libraries from crates.io or git repositories, listed in its Cargo.toml file. Before starting a build, Cargo usually downloads automatically them. This step can also be performed independently, via the cargo fetch command.

Cargo maintains a local cache of the registry index and of git checkouts of the crates, whose location is given by $CARGO_HOME. As seen in the package Makefile example at line 15, this environment variable is set to $(HOST_DIR)/share/cargo.

This dependency download mechanism is not convenient when performing an offline build, as Cargo will fail to fetch the dependencies. In that case, it is advised to generate a tarball of the dependencies using the cargo vendor and add it to FOO_EXTRA_DOWNLOADS.

18.17. Infrastructure for Go packages

This infrastructure applies to Go packages that use the standard build system and use bundled dependencies.

18.17.1. golang-package tutorial

First, let’s see how to write a .mk file for a go package, with an example :

01: ################################################################################
02: #
03: # foo
04: #
05: ################################################################################
06:
07: FOO_VERSION = 1.0
08: FOO_SITE = $(call github,bar,foo,$(FOO_VERSION))
09: FOO_LICENSE = BSD-3-Clause
10: FOO_LICENSE_FILES = LICENSE
11:
12: $(eval $(golang-package))

On line 7, we declare the version of the package.

On line 8, we declare the upstream location of the package, here fetched from Github, since a large number of Go packages are hosted on Github.

On line 9 and 10, we give licensing details about the package.

Finally, on line 12, we invoke the golang-package macro that generates all the Makefile rules that actually allow the package to be built.

18.17.2. golang-package reference

In their Config.in file, packages using the golang-package infrastructure should depend on BR2_PACKAGE_HOST_GO_TARGET_ARCH_SUPPORTS because Buildroot will automatically add a dependency on host-go to such packages. If you need CGO support in your package, you must add a dependency on BR2_PACKAGE_HOST_GO_TARGET_CGO_LINKING_SUPPORTS.

The main macro of the Go package infrastructure is golang-package. It is similar to the generic-package macro. The ability to build host packages is also available, with the host-golang-package macro. Host packages built by host-golang-package macro should depend on BR2_PACKAGE_HOST_GO_HOST_ARCH_SUPPORTS.

Just like the generic infrastructure, the Go infrastructure works by defining a number of variables before calling the golang-package.

All the package metadata information variables that exist in the generic package infrastructure also exist in the Go infrastructure: FOO_VERSION, FOO_SOURCE, FOO_PATCH, FOO_SITE, FOO_SUBDIR, FOO_DEPENDENCIES, FOO_LICENSE, FOO_LICENSE_FILES, FOO_INSTALL_STAGING, etc.

Note that it is not necessary to add host-go in the FOO_DEPENDENCIES variable of a package, since this basic dependency is automatically added as needed by the Go package infrastructure.

A few additional variables, specific to the Go infrastructure, can optionally be defined, depending on the package’s needs. Many of them are only useful in very specific cases, typical packages will therefore only use a few of them, or none.

  • The package must specify its Go module name in the FOO_GOMOD variable. If not specified, it defaults to URL-domain/1st-part-of-URL/2nd-part-of-URL, e.g FOO_GOMOD will take the value github.com/bar/foo for a package that specifies FOO_SITE = $(call github,bar,foo,$(FOO_VERSION)). The Go package infrastructure will automatically generate a minimal go.mod file in the package source tree if it doesn’t exist.
  • FOO_LDFLAGS and FOO_TAGS can be used to pass respectively the LDFLAGS or the TAGS to the go build command.
  • FOO_BUILD_TARGETS can be used to pass the list of targets that should be built. If FOO_BUILD_TARGETS is not specified, it defaults to .. We then have two cases:

    • FOO_BUILD_TARGETS is .. In this case, we assume only one binary will be produced, and that by default we name it after the package name. If that is not appropriate, the name of the produced binary can be overridden using FOO_BIN_NAME.
    • FOO_BUILD_TARGETS is not .. In this case, we iterate over the values to build each target, and for each produced a binary that is the non-directory component of the target. For example if FOO_BUILD_TARGETS = cmd/docker cmd/dockerd the binaries produced are docker and dockerd.
  • FOO_INSTALL_BINS can be used to pass the list of binaries that should be installed in /usr/bin on the target. If FOO_INSTALL_BINS is not specified, it defaults to the lower-case name of package.

With the Go infrastructure, all the steps required to build and install the packages are already defined, and they generally work well for most Go-based packages. However, when required, it is still possible to customize what is done in any particular step:

  • By adding a post-operation hook (after extract, patch, configure, build or install). See Section 18.22, “Hooks available in the various build steps” for details.
  • By overriding one of the steps. For example, even if the Go infrastructure is used, if the package .mk file defines its own FOO_BUILD_CMDS variable, it will be used instead of the default Go one. However, using this method should be restricted to very specific cases. Do not use it in the general case.

18.18. Infrastructure for QMake-based packages

18.18.1. qmake-package tutorial

First, let’s see how to write a .mk file for a QMake-based package, with an example :

01: ################################################################################
02: #
03: # libfoo
04: #
05: ################################################################################
06:
07: LIBFOO_VERSION = 1.0
08: LIBFOO_SOURCE = libfoo-$(LIBFOO_VERSION).tar.gz
09: LIBFOO_SITE = http://www.foosoftware.org/download
10: LIBFOO_CONF_OPTS = QT_CONFIG+=bar QT_CONFIG-=baz
11: LIBFOO_DEPENDENCIES = bar
12:
13: $(eval $(qmake-package))

On line 7, we declare the version of the package.

On line 8 and 9, we declare the name of the tarball (xz-ed tarball recommended) and the location of the tarball on the Web. Buildroot will automatically download the tarball from this location.

On line 10, we tell Buildroot what options to enable for libfoo.

On line 11, we tell Buildroot the dependencies of libfoo.

Finally, on line line 13, we invoke the qmake-package macro that generates all the Makefile rules that actually allows the package to be built.

18.18.2. qmake-package reference

The main macro of the QMake package infrastructure is qmake-package. It is similar to the generic-package macro.

Just like the generic infrastructure, the QMake infrastructure works by defining a number of variables before calling the qmake-package macro.

First, all the package metadata information variables that exist in the generic infrastructure also exist in the QMake infrastructure: LIBFOO_VERSION, LIBFOO_SOURCE, LIBFOO_PATCH, LIBFOO_SITE, LIBFOO_SUBDIR, LIBFOO_DEPENDENCIES, LIBFOO_INSTALL_STAGING, LIBFOO_INSTALL_TARGET.

An additional variable, specific to the QMake infrastructure, can also be defined.

  • LIBFOO_CONF_ENV, to specify additional environment variables to pass to the qmake script for the configuration step. By default, empty.
  • LIBFOO_CONF_OPTS, to specify additional options to pass to the qmake script for the configuration step. By default, empty.
  • LIBFOO_MAKE_ENV, to specify additional environment variables to the make command during the build and install steps. By default, empty.
  • LIBFOO_MAKE_OPTS, to specify additional targets to pass to the make command during the build step. By default, empty.
  • LIBFOO_INSTALL_STAGING_OPTS, to specify additional targets to pass to the make command during the staging installation step. By default, install.
  • LIBFOO_INSTALL_TARGET_OPTS, to specify additional targets to pass to the make command during the target installation step. By default, install.
  • LIBFOO_SYNC_HEADERS, to run syncqt.pl before qmake. Some packages need this to have a properly populated include directory before running the build.

18.19. Infrastructure for packages building kernel modules

Buildroot offers a helper infrastructure to make it easy to write packages that build and install Linux kernel modules. Some packages only contain a kernel module, other packages contain programs and libraries in addition to kernel modules. Buildroot’s helper infrastructure supports either case.

18.19.1. kernel-module tutorial

Let’s start with an example on how to prepare a simple package that only builds a kernel module, and no other component:

01: ################################################################################
02: #
03: # foo
04: #
05: ################################################################################
06:
07: FOO_VERSION = 1.2.3
08: FOO_SOURCE = foo-$(FOO_VERSION).tar.xz
09: FOO_SITE = http://www.foosoftware.org/download
10: FOO_LICENSE = GPL-2.0
11: FOO_LICENSE_FILES = COPYING
12:
13: $(eval $(kernel-module))
14: $(eval $(generic-package))

Lines 7-11 define the usual meta-data to specify the version, archive name, remote URI where to find the package source, licensing information.

On line 13, we invoke the kernel-module helper infrastructure, that generates all the appropriate Makefile rules and variables to build that kernel module.

Finally, on line 14, we invoke the generic-package infrastructure.

The dependency on linux is automatically added, so it is not needed to specify it in FOO_DEPENDENCIES.

What you may have noticed is that, unlike other package infrastructures, we explicitly invoke a second infrastructure. This allows a package to build a kernel module, but also, if needed, use any one of other package infrastructures to build normal userland components (libraries, executables…). Using the kernel-module infrastructure on its own is not sufficient; another package infrastructure must be used.

Let’s look at a more complex example:

01: ################################################################################
02: #
03: # foo
04: #
05: ################################################################################
06:
07: FOO_VERSION = 1.2.3
08: FOO_SOURCE = foo-$(FOO_VERSION).tar.xz
09: FOO_SITE = http://www.foosoftware.org/download
10: FOO_LICENSE = GPL-2.0
11: FOO_LICENSE_FILES = COPYING
12:
13: FOO_MODULE_SUBDIRS = driver/base
14: FOO_MODULE_MAKE_OPTS = KVERSION=$(LINUX_VERSION_PROBED)
15:
16: ifeq ($(BR2_PACKAGE_LIBBAR),y)
17: FOO_DEPENDENCIES = libbar
18: FOO_CONF_OPTS = --enable-bar
19: FOO_MODULE_SUBDIRS += driver/bar
20: else
21: FOO_CONF_OPTS = --disable-bar
22: endif
23:
24: $(eval $(kernel-module))
26: $(eval $(autotools-package))

Here, we see that we have an autotools-based package, that also builds the kernel module located in sub-directory driver/base and, if libbar is enabled, the kernel module located in sub-directory driver/bar, and defines the variable KVERSION to be passed to the Linux buildsystem when building the module(s).

18.19.2. kernel-module reference

The main macro for the kernel module infrastructure is kernel-module. Unlike other package infrastructures, it is not stand-alone, and requires any of the other *-package macros be called after it.

The kernel-module macro defines post-build and post-target-install hooks to build the kernel modules. If the package’s .mk needs access to the built kernel modules, it should do so in a post-build hook, registered after the call to kernel-module. Similarly, if the package’s .mk needs access to the kernel module after it has been installed, it should do so in a post-install hook, registered after the call to kernel-module. Here’s an example:

$(eval $(kernel-module))

define FOO_DO_STUFF_WITH_KERNEL_MODULE
    # Do something with it...
endef
FOO_POST_BUILD_HOOKS += FOO_DO_STUFF_WITH_KERNEL_MODULE

$(eval $(generic-package))

Finally, unlike the other package infrastructures, there is no host-kernel-module variant to build a host kernel module.

The following additional variables can optionally be defined to further configure the build of the kernel module:

  • FOO_MODULE_SUBDIRS may be set to one or more sub-directories (relative to the package source top-directory) where the kernel module sources are. If empty or not set, the sources for the kernel module(s) are considered to be located at the top of the package source tree.
  • FOO_MODULE_MAKE_OPTS may be set to contain extra variable definitions to pass to the Linux buildsystem.

You may also reference (but you may not set!) those variables:

  • LINUX_DIR contains the path to where the Linux kernel has been extracted and built.
  • LINUX_VERSION contains the version string as configured by the user.
  • LINUX_VERSION_PROBED contains the real version string of the kernel, retrieved with running make -C $(LINUX_DIR) kernelrelease
  • KERNEL_ARCH contains the name of the current architecture, like arm, mips

18.20. Infrastructure for asciidoc documents

The Buildroot manual, which you are currently reading, is entirely written using the AsciiDoc mark-up syntax. The manual is then rendered to many formats:

  • html
  • split-html
  • pdf
  • epub
  • text

Although Buildroot only contains one document written in AsciiDoc, there is, as for packages, an infrastructure for rendering documents using the AsciiDoc syntax.

Also as for packages, the AsciiDoc infrastructure is available from a br2-external tree. This allows documentation for a br2-external tree to match the Buildroot documentation, as it will be rendered to the same formats and use the same layout and theme.

18.20.1. asciidoc-document tutorial

Whereas package infrastructures are suffixed with -package, the document infrastructures are suffixed with -document. So, the AsciiDoc infrastructure is named asciidoc-document.

Here is an example to render a simple AsciiDoc document.

01: ################################################################################
02: #
03: # foo-document
04: #
05: ################################################################################
06:
07: FOO_SOURCES = $(sort $(wildcard $(pkgdir)/*))
08: $(eval $(call asciidoc-document))

On line 7, the Makefile declares what the sources of the document are. Currently, it is expected that the document’s sources are only local; Buildroot will not attempt to download anything to render a document. Thus, you must indicate where the sources are. Usually, the string above is sufficient for a document with no sub-directory structure.

On line 8, we call the asciidoc-document function, which generates all the Makefile code necessary to render the document.

18.20.2. asciidoc-document reference

The list of variables that can be set in a .mk file to give metadata information is (assuming the document name is foo) :

  • FOO_SOURCES, mandatory, defines the source files for the document.
  • FOO_RESOURCES, optional, may contain a space-separated list of paths to one or more directories containing so-called resources (like CSS or images). By default, empty.
  • FOO_DEPENDENCIES, optional, the list of packages (most probably, host-packages) that must be built before building this document.

There are also additional hooks (see Section 18.22, “Hooks available in the various build steps” for general information on hooks), that a document may set to define extra actions to be done at various steps:

  • FOO_POST_RSYNC_HOOKS to run additional commands after the sources have been copied by Buildroot. This can for example be used to generate part of the manual with information extracted from the tree. As an example, Buildroot uses this hook to generate the tables in the appendices.
  • FOO_CHECK_DEPENDENCIES_HOOKS to run additional tests on required components to generate the document. In AsciiDoc, it is possible to call filters, that is, programs that will parse an AsciiDoc block and render it appropriately (e.g. ditaa or aafigure).
  • FOO_CHECK_DEPENDENCIES_<FMT>_HOOKS, to run additional tests for the specified format <FMT> (see the list of rendered formats, above).

Here is a complete example that uses all variables and all hooks:

01: ################################################################################
02: #
03: # foo-document
04: #
05: ################################################################################
06:
07: FOO_SOURCES = $(sort $(wildcard $(pkgdir)/*))
08: FOO_RESOURCES = $(sort $(wildcard $(pkgdir)/ressources))
09:
10: define FOO_GEN_EXTRA_DOC
11:     /path/to/generate-script --outdir=$(@D)
12: endef
13: FOO_POST_RSYNC_HOOKS += FOO_GEN_EXTRA_DOC
14:
15: define FOO_CHECK_MY_PROG
16:     if ! which my-prog >/dev/null 2>&1; then \
17:         echo "You need my-prog to generate the foo document"; \
18:         exit 1; \
19:     fi
20: endef
21: FOO_CHECK_DEPENDENCIES_HOOKS += FOO_CHECK_MY_PROG
22:
23: define FOO_CHECK_MY_OTHER_PROG
24:     if ! which my-other-prog >/dev/null 2>&1; then \
25:         echo "You need my-other-prog to generate the foo document as PDF"; \
26:         exit 1; \
27:     fi
28: endef
29: FOO_CHECK_DEPENDENCIES_PDF_HOOKS += FOO_CHECK_MY_OTHER_PROG
30:
31: $(eval $(call asciidoc-document))

18.21. Infrastructure specific to the Linux kernel package

The Linux kernel package can use some specific infrastructures based on package hooks for building Linux kernel tools or/and building Linux kernel extensions.

18.21.1. linux-kernel-tools

Buildroot offers a helper infrastructure to build some userspace tools for the target available within the Linux kernel sources. Since their source code is part of the kernel source code, a special package, linux-tools, exists and re-uses the sources of the Linux kernel that runs on the target.

Let’s look at an example of a Linux tool. For a new Linux tool named foo, create a new menu entry in the existing package/linux-tools/Config.in. This file will contain the option descriptions related to each kernel tool that will be used and displayed in the configuration tool. It would basically look like:

01: config BR2_PACKAGE_LINUX_TOOLS_FOO
02:     bool "foo"
03:     select BR2_PACKAGE_LINUX_TOOLS
04:     help
05:       This is a comment that explains what foo kernel tool is.
06:
07:       http://foosoftware.org/foo/

The name of the option starts with the prefix BR2_PACKAGE_LINUX_TOOLS_, followed by the uppercase name of the tool (like is done for packages).

Note. Unlike other packages, the linux-tools package options appear in the linux kernel menu, under the Linux Kernel Tools sub-menu, not under the Target packages main menu.

Then for each linux tool, add a new .mk.in file named package/linux-tools/linux-tool-foo.mk.in. It would basically look like:

01: ################################################################################
02: #
03: # foo
04: #
05: ################################################################################
06:
07: LINUX_TOOLS += foo
08:
09: FOO_DEPENDENCIES = libbbb
10:
11: define FOO_BUILD_CMDS
12:     $(TARGET_MAKE_ENV) $(MAKE) -C $(LINUX_DIR)/tools foo
13: endef
14:
15: define FOO_INSTALL_STAGING_CMDS
16:     $(TARGET_MAKE_ENV) $(MAKE) -C $(LINUX_DIR)/tools \
17:             DESTDIR=$(STAGING_DIR) \
18:             foo_install
19: endef
20:
21: define FOO_INSTALL_TARGET_CMDS
22:     $(TARGET_MAKE_ENV) $(MAKE) -C $(LINUX_DIR)/tools \
23:             DESTDIR=$(TARGET_DIR) \
24:             foo_install
25: endef

On line 7, we register the Linux tool foo to the list of available Linux tools.

On line 9, we specify the list of dependencies this tool relies on. These dependencies are added to the Linux package dependencies list only when the foo tool is selected.

The rest of the Makefile, lines 11-25 defines what should be done at the different steps of the Linux tool build process like for a generic package . They will actually be used only when the foo tool is selected. The only supported commands are _BUILD_CMDS, _INSTALL_STAGING_CMDS and _INSTALL_TARGET_CMDS.

Note. One must not call $(eval $(generic-package)) or any other package infrastructure! Linux tools are not packages by themselves, they are part of the linux-tools package.

18.21.2. linux-kernel-extensions

Some packages provide new features that require the Linux kernel tree to be modified. This can be in the form of patches to be applied on the kernel tree, or in the form of new files to be added to the tree. The Buildroot’s Linux kernel extensions infrastructure provides a simple solution to automatically do this, just after the kernel sources are extracted and before the kernel patches are applied. Examples of extensions packaged using this mechanism are the real-time extensions Xenomai and RTAI, as well as the set of out-of-tree LCD screens drivers fbtft.

Let’s look at an example on how to add a new Linux extension foo.

First, create the package foo that provides the extension: this package is a standard package; see the previous chapters on how to create such a package. This package is in charge of downloading the sources archive, checking the hash, defining the licence informations and building user space tools if any.

Then create the Linux extension proper: create a new menu entry in the existing linux/Config.ext.in. This file contains the option descriptions related to each kernel extension that will be used and displayed in the configuration tool. It would basically look like:

01: config BR2_LINUX_KERNEL_EXT_FOO
02:     bool "foo"
03:     help
04:       This is a comment that explains what foo kernel extension is.
05:
06:       http://foosoftware.org/foo/

Then for each linux extension, add a new .mk file named linux/linux-ext-foo.mk. It should basically contain:

01: ################################################################################
02: #
03: # foo
04: #
05: ################################################################################
06:
07: LINUX_EXTENSIONS += foo
08:
09: define FOO_PREPARE_KERNEL
10:     $(FOO_DIR)/prepare-kernel-tree.sh --linux-dir=$(@D)
11: endef

On line 7, we add the Linux extension foo to the list of available Linux extensions.

On line 9-11, we define what should be done by the extension to modify the Linux kernel tree; this is specific to the linux extension and can use the variables defined by the foo package, like: $(FOO_DIR) or $(FOO_VERSION)… as well as all the Linux variables, like: $(LINUX_VERSION) or $(LINUX_VERSION_PROBED), $(KERNEL_ARCH)… See the definition of those kernel variables.

18.22. Hooks available in the various build steps

The generic infrastructure (and as a result also the derived autotools and cmake infrastructures) allow packages to specify hooks. These define further actions to perform after existing steps. Most hooks aren’t really useful for generic packages, since the .mk file already has full control over the actions performed in each step of the package construction.

The following hook points are available:

  • LIBFOO_PRE_DOWNLOAD_HOOKS
  • LIBFOO_POST_DOWNLOAD_HOOKS
  • LIBFOO_PRE_EXTRACT_HOOKS
  • LIBFOO_POST_EXTRACT_HOOKS
  • LIBFOO_PRE_RSYNC_HOOKS
  • LIBFOO_POST_RSYNC_HOOKS
  • LIBFOO_PRE_PATCH_HOOKS
  • LIBFOO_POST_PATCH_HOOKS
  • LIBFOO_PRE_CONFIGURE_HOOKS
  • LIBFOO_POST_CONFIGURE_HOOKS
  • LIBFOO_PRE_BUILD_HOOKS
  • LIBFOO_POST_BUILD_HOOKS
  • LIBFOO_PRE_INSTALL_HOOKS (for host packages only)
  • LIBFOO_POST_INSTALL_HOOKS (for host packages only)
  • LIBFOO_PRE_INSTALL_STAGING_HOOKS (for target packages only)
  • LIBFOO_POST_INSTALL_STAGING_HOOKS (for target packages only)
  • LIBFOO_PRE_INSTALL_TARGET_HOOKS (for target packages only)
  • LIBFOO_POST_INSTALL_TARGET_HOOKS (for target packages only)
  • LIBFOO_PRE_INSTALL_IMAGES_HOOKS
  • LIBFOO_POST_INSTALL_IMAGES_HOOKS
  • LIBFOO_PRE_LEGAL_INFO_HOOKS
  • LIBFOO_POST_LEGAL_INFO_HOOKS

These variables are lists of variable names containing actions to be performed at this hook point. This allows several hooks to be registered at a given hook point. Here is an example:

define LIBFOO_POST_PATCH_FIXUP
        action1
        action2
endef

LIBFOO_POST_PATCH_HOOKS += LIBFOO_POST_PATCH_FIXUP

18.22.1. Using the POST_RSYNC hook

The POST_RSYNC hook is run only for packages that use a local source, either through the local site method or the OVERRIDE_SRCDIR mechanism. In this case, package sources are copied using rsync from the local location into the buildroot build directory. The rsync command does not copy all files from the source directory, though. Files belonging to a version control system, like the directories .git, .hg, etc. are not copied. For most packages this is sufficient, but a given package can perform additional actions using the POST_RSYNC hook.

In principle, the hook can contain any command you want. One specific use case, though, is the intentional copying of the version control directory using rsync. The rsync command you use in the hook can, among others, use the following variables:

  • $(SRCDIR): the path to the overridden source directory
  • $(@D): the path to the build directory

18.22.2. Target-finalize hook

Packages may also register hooks in LIBFOO_TARGET_FINALIZE_HOOKS. These hooks are run after all packages are built, but before the filesystem images are generated. They are seldom used, and your package probably do not need them.

18.23. Gettext integration and interaction with packages

Many packages that support internationalization use the gettext library. Dependencies for this library are fairly complicated and therefore, deserve some explanation.

The glibc C library integrates a full-blown implementation of gettext , supporting translation. Native Language Support is therefore built-in in glibc .

On the other hand, the uClibc and musl C libraries only provide a stub implementation of the gettext functionality, which allows to compile libraries and programs using gettext functions, but without providing the translation capabilities of a full-blown gettext implementation. With such C libraries, if real Native Language Support is necessary, it can be provided by the libintl library of the gettext package.

Due to this, and in order to make sure that Native Language Support is properly handled, packages in Buildroot that can use NLS support should:

  1. Ensure NLS support is enabled when BR2_SYSTEM_ENABLE_NLS=y. This is done automatically for autotools packages and therefore should only be done for packages using other package infrastructures.
  2. Add $(TARGET_NLS_DEPENDENCIES) to the package <pkg>_DEPENDENCIES variable. This addition should be done unconditionally: the value of this variable is automatically adjusted by the core infrastructure to contain the relevant list of packages. If NLS support is disabled, this variable is empty. If NLS support is enabled, this variable contains host-gettext so that tools needed to compile translation files are available on the host. In addition, if uClibc or musl are used, this variable also contains gettext in order to get the full-blown gettext implementation.
  3. If needed, add $(TARGET_NLS_LIBS) to the linker flags, so that the package gets linked with libintl. This is generally not needed with autotools packages as they usually detect automatically that they should link with libintl. However, packages using other build systems, or problematic autotools-based packages may need this. $(TARGET_NLS_LIBS) should be added unconditionally to the linker flags, as the core automatically makes it empty or defined to -lintl depending on the configuration.

No changes should be made to the Config.in file to support NLS.

Finally, certain packages need some gettext utilities on the target, such as the gettext program itself, which allows to retrieve translated strings, from the command line. In such a case, the package should:

  • use select BR2_PACKAGE_GETTEXT in their Config.in file, indicating in a comment above that it’s a runtime dependency only.
  • not add any gettext dependency in the DEPENDENCIES variable of their .mk file.

18.24. Tips and tricks

18.24.1. Package name, config entry name and makefile variable relationship

In Buildroot, there is some relationship between:

  • the package name , which is the package directory name (and the name of the *.mk file);
  • the config entry name that is declared in the Config.in file;
  • the makefile variable prefix.

It is mandatory to maintain consistency between these elements, using the following rules:

  • the package directory and the *.mk name are the package name itself (e.g.: package/foo-bar_boo/foo-bar_boo.mk);
  • the make target name is the package name itself (e.g.: foo-bar_boo);
  • the config entry is the upper case package name with . and - characters substituted with _, prefixed with BR2_PACKAGE_ (e.g.: BR2_PACKAGE_FOO_BAR_BOO);
  • the *.mk file variable prefix is the upper case package name with . and - characters substituted with _ (e.g.: FOO_BAR_BOO_VERSION).

18.24.2. How to check the coding style

Buildroot provides a script in utils/check-package that checks new or changed files for coding style. It is not a complete language validator, but it catches many common mistakes. It is meant to run in the actual files you created or modified, before creating the patch for submission.

This script can be used for packages, filesystem makefiles, Config.in files, etc. It does not check the files defining the package infrastructures and some other files containing similar common code.

To use it, run the check-package script, by telling which files you created or changed:

$ ./utils/check-package package/new-package/*

If you have the utils directory in your path you can also run:

$ cd package/new-package/
$ check-package *

The tool can also be used for packages in a br2-external:

$ check-package -b /path/to/br2-ext-tree/package/my-package/*

18.24.3. How to test your package

Once you have added your new package, it is important that you test it under various conditions: does it build for all architectures? Does it build with the different C libraries? Does it need threads, NPTL? And so on…

Buildroot runs autobuilders which continuously test random configurations. However, these only build the master branch of the git tree, and your new fancy package is not yet there.

Buildroot provides a script in utils/test-pkg that uses the same base configurations as used by the autobuilders so you can test your package in the same conditions.

First, create a config snippet that contains all the necessary options needed to enable your package, but without any architecture or toolchain option. For example, let’s create a config snippet that just enables libcurl, without any TLS backend:

$ cat libcurl.config
BR2_PACKAGE_LIBCURL=y

If your package needs more configuration options, you can add them to the config snippet. For example, here’s how you would test libcurl with openssl as a TLS backend and the curl program:

$ cat libcurl.config
BR2_PACKAGE_LIBCURL=y
BR2_PACKAGE_LIBCURL_CURL=y
BR2_PACKAGE_OPENSSL=y

Then run the test-pkg script, by telling it what config snippet to use and what package to test:

$ ./utils/test-pkg -c libcurl.config -p libcurl

By default, test-pkg will build your package against a subset of the toolchains used by the autobuilders, which has been selected by the Buildroot developers as being the most useful and representative subset. If you want to test all toolchains, pass the -a option. Note that in any case, internal toolchains are excluded as they take too long to build.

The output lists all toolchains that are tested and the corresponding result (excerpt, results are fake):

$ ./utils/test-pkg -c libcurl.config -p libcurl
                armv5-ctng-linux-gnueabi [ 1/11]: OK
              armv7-ctng-linux-gnueabihf [ 2/11]: OK
                        br-aarch64-glibc [ 3/11]: SKIPPED
                           br-arcle-hs38 [ 4/11]: SKIPPED
                            br-arm-basic [ 5/11]: FAILED
                  br-arm-cortex-a9-glibc [ 6/11]: OK
                   br-arm-cortex-a9-musl [ 7/11]: FAILED
                   br-arm-cortex-m4-full [ 8/11]: OK
                             br-arm-full [ 9/11]: OK
                    br-arm-full-nothread [10/11]: FAILED
                      br-arm-full-static [11/11]: OK
11 builds, 2 skipped, 2 build failed, 1 legal-info failed

The results mean:

  • OK: the build was successful.
  • SKIPPED: one or more configuration options listed in the config snippet were not present in the final configuration. This is due to options having dependencies not satisfied by the toolchain, such as for example a package that depends on BR2_USE_MMU with a noMMU toolchain. The missing options are reported in missing.config in the output build directory (~/br-test-pkg/TOOLCHAIN_NAME/ by default).
  • FAILED: the build failed. Inspect the logfile file in the output build directory to see what went wrong:

    • the actual build failed,
    • the legal-info failed,
    • one of the preliminary steps (downloading the config file, applying the configuration, running dirclean for the package) failed.

When there are failures, you can just re-run the script with the same options (after you fixed your package); the script will attempt to re-build the package specified with -p for all toolchains, without the need to re-build all the dependencies of that package.

The test-pkg script accepts a few options, for which you can get some help by running:

$ ./utils/test-pkg -h

18.24.4. How to add a package from GitHub

Packages on GitHub often don’t have a download area with release tarballs. However, it is possible to download tarballs directly from the repository on GitHub. As GitHub is known to have changed download mechanisms in the past, the github helper function should be used as shown below.

# Use a tag or a full commit ID
FOO_VERSION = 1.0
FOO_SITE = $(call github,<user>,<package>,v$(FOO_VERSION))

Notes

  • The FOO_VERSION can either be a tag or a commit ID.
  • The tarball name generated by github matches the default one from Buildroot (e.g.: foo-f6fb6654af62045239caed5950bc6c7971965e60.tar.gz), so it is not necessary to specify it in the .mk file.
  • When using a commit ID as version, you should use the full 40 hex characters.
  • When the tag contains a prefix such as v in v1.0, then the VERSION variable should contain just 1.0, and the v should be added directly in the SITE variable, as illustrated above. This ensures that the VERSION variable value can be used to match against release-monitoring.org results.

If the package you wish to add does have a release section on GitHub, the maintainer may have uploaded a release tarball, or the release may just point to the automatically generated tarball from the git tag. If there is a release tarball uploaded by the maintainer, we prefer to use that since it may be slightly different (e.g. it contains a configure script so we don’t need to do AUTORECONF).

You can see on the release page if it’s an uploaded tarball or a git tag:

github_hash_mongrel2.png
  • If it looks like the image above then it was uploaded by the maintainer and you should use that link (in that example: mongrel2-v1.9.2.tar.bz2 ) to specify FOO_SITE, and not use the github helper.
  • On the other hand, if there’s is only the "Source code" link, then it’s an automatically generated tarball and you should use the github helper function.

18.24.5. How to add a package from Gitlab

In a similar way to the github macro described in Section 18.24.4, “How to add a package from GitHub”, Buildroot also provides the gitlab macro to download from Gitlab repositories. It can be used to download auto-generated tarballs produced by Gitlab, either for specific tags or commits:

# Use a tag or a full commit ID
FOO_VERSION = 1.0
FOO_SITE = $(call gitlab,<user>,<package>,v$(FOO_VERSION))

By default, it will use a .tar.gz tarball, but Gitlab also provides .tar.bz2 tarballs, so by adding a <pkg>_SOURCE variable, this .tar.bz2 tarball can be used:

# Use a tag or a full commit ID
FOO_VERSION = 1.0
FOO_SITE = $(call gitlab,<user>,<package>,v$(FOO_VERSION))
FOO_SOURCE = foo-$(FOO_VERSION).tar.bz2

If there is a specific tarball uploaded by the upstream developers in https://gitlab.com/<project>/releases/, do not use this macro, but rather use directly the link to the tarball.

18.25. Conclusion

As you can see, adding a software package to Buildroot is simply a matter of writing a Makefile using an existing example and modifying it according to the compilation process required by the package.

If you package software that might be useful for other people, don’t forget to send a patch to the Buildroot mailing list (see Section 22.5, “Submitting patches”)!

Chapter 19. Patching a package

While integrating a new package or updating an existing one, it may be necessary to patch the source of the software to get it cross-built within Buildroot.

Buildroot offers an infrastructure to automatically handle this during the builds. It supports three ways of applying patch sets: downloaded patches, patches supplied within buildroot and patches located in a user-defined global patch directory.

19.1. Providing patches

19.1.1. Downloaded

If it is necessary to apply a patch that is available for download, then add it to the <packagename>_PATCH variable. If an entry contains ://, then Buildroot will assume it is a full URL and download the patch from this location. Otherwise, Buildroot will assume that the patch should be downloaded from <packagename>_SITE. It can be a single patch, or a tarball containing a patch series.

Like for all downloads, a hash should be added to the <packagename>.hash file.

This method is typically used for packages from Debian.

19.1.2. Within Buildroot

Most patches are provided within Buildroot, in the package directory; these typically aim to fix cross-compilation, libc support, or other such issues.

These patch files should be named <number>-<description>.patch.

Notes

  • The patch files coming with Buildroot should not contain any package version reference in their filename.
  • The field <number> in the patch file name refers to the apply order , and shall start at 1; It is preferred to pad the number with zeros up to 4 digits, like git-format-patch does. E.g.: 0001-foobar-the-buz.patch
  • Previously, it was mandatory for patches to be prefixed with the name of the package, like <package>-<number>-<description>.patch, but that is no longer the case. Existing packages will be fixed as time passes. Do not prefix patches with the package name.
  • Previously, a series file, as used by quilt, could also be added in the package directory. In that case, the series file defines the patch application order. This is deprecated, and will be removed in the future. Do not use a series file.

19.1.3. Global patch directory

The BR2_GLOBAL_PATCH_DIR configuration file option can be used to specify a space separated list of one or more directories containing global package patches. See Section 9.8, “Adding project-specific patches” for details.

19.2. How patches are applied

  1. Run the <packagename>_PRE_PATCH_HOOKS commands if defined;
  2. Cleanup the build directory, removing any existing *.rej files;
  3. If <packagename>_PATCH is defined, then patches from these tarballs are applied;
  4. If there are some *.patch files in the package’s Buildroot directory or in a package subdirectory named <packageversion>, then:

    • If a series file exists in the package directory, then patches are applied according to the series file;
    • Otherwise, patch files matching *.patch are applied in alphabetical order. So, to ensure they are applied in the right order, it is highly recommended to name the patch files like this: <number>-<description>.patch, where <number> refers to the apply order .
  5. If BR2_GLOBAL_PATCH_DIR is defined, the directories will be enumerated in the order they are specified. The patches are applied as described in the previous step.
  6. Run the <packagename>_POST_PATCH_HOOKS commands if defined.

If something goes wrong in the steps 3 or 4 , then the build fails.

19.3. Format and licensing of the package patches

Patches are released under the same license as the software they apply to (see Section 13.2, “Complying with the Buildroot license”).

A message explaining what the patch does, and why it is needed, should be added in the header commentary of the patch.

You should add a Signed-off-by statement in the header of the each patch to help with keeping track of the changes and to certify that the patch is released under the same license as the software that is modified.

If the software is under version control, it is recommended to use the upstream SCM software to generate the patch set.

Otherwise, concatenate the header with the output of the diff -purN package-version.orig/ package-version/ command.

If you update an existing patch (e.g. when bumping the package version), make sure the existing From header and Signed-off-by tags are not removed, but do update the rest of the patch comment when appropriate.

At the end, the patch should look like:

configure.ac: add C++ support test

Signed-off-by: John Doe <john.doe@noname.org>

--- configure.ac.orig
+++ configure.ac
@@ -40,2 +40,12 @@

AC_PROG_MAKE_SET
+
+AC_CACHE_CHECK([whether the C++ compiler works],
+               [rw_cv_prog_cxx_works],
+               [AC_LANG_PUSH([C++])
+                AC_LINK_IFELSE([AC_LANG_PROGRAM([], [])],
+                               [rw_cv_prog_cxx_works=yes],
+                               [rw_cv_prog_cxx_works=no])
+                AC_LANG_POP([C++])])
+
+AM_CONDITIONAL([CXX_WORKS], [test "x$rw_cv_prog_cxx_works" = "xyes"])

19.4. Integrating patches found on the Web

When integrating a patch of which you are not the author, you have to add a few things in the header of the patch itself.

Depending on whether the patch has been obtained from the project repository itself, or from somewhere on the web, add one of the following tags:

Backported from: <some commit id>

or

Fetch from: <some url>

It is also sensible to add a few words about any changes to the patch that may have been necessary.

Chapter 20. Download infrastructure

TODO

Chapter 21. Debugging Buildroot

It is possible to instrument the steps Buildroot does when building packages. Define the variable BR2_INSTRUMENTATION_SCRIPTS to contain the path of one or more scripts (or other executables), in a space-separated list, you want called before and after each step. The scripts are called in sequence, with three parameters:

  • start or end to denote the start (resp. the end) of a step;
  • the name of the step about to be started, or which just ended;
  • the name of the package.

For example :

make BR2_INSTRUMENTATION_SCRIPTS="/path/to/my/script1 /path/to/my/script2"

The list of steps is:

  • extract
  • patch
  • configure
  • build
  • install-host, when a host-package is installed in $(HOST_DIR)
  • install-target, when a target-package is installed in $(TARGET_DIR)
  • install-staging, when a target-package is installed in $(STAGING_DIR)
  • install-image, when a target-package installs files in $(BINARIES_DIR)

The script has access to the following variables:

  • BR2_CONFIG: the path to the Buildroot .config file
  • HOST_DIR, STAGING_DIR, TARGET_DIR: see Section 18.5.2, “generic-package reference”
  • BUILD_DIR: the directory where packages are extracted and built
  • BINARIES_DIR: the place where all binary files (aka images) are stored
  • BASE_DIR: the base output directory

Chapter 22. Contributing to Buildroot

There are many ways in which you can contribute to Buildroot: analyzing and fixing bugs, analyzing and fixing package build failures detected by the autobuilders, testing and reviewing patches sent by other developers, working on the items in our TODO list and sending your own improvements to Buildroot or its manual. The following sections give a little more detail on each of these items.

If you are interested in contributing to Buildroot, the first thing you should do is to subscribe to the Buildroot mailing list. This list is the main way of interacting with other Buildroot developers and to send contributions to. If you aren’t subscribed yet, then refer to Chapter 5, Community resources for the subscription link.

If you are going to touch the code, it is highly recommended to use a git repository of Buildroot, rather than starting from an extracted source code tarball. Git is the easiest way to develop from and directly send your patches to the mailing list. Refer to Chapter 3, Getting Buildroot for more information on obtaining a Buildroot git tree.

22.1. Reproducing, analyzing and fixing bugs

A first way of contributing is to have a look at the open bug reports in the Buildroot bug tracker. As we strive to keep the bug count as small as possible, all help in reproducing, analyzing and fixing reported bugs is more than welcome. Don’t hesitate to add a comment to bug reports reporting your findings, even if you don’t yet see the full picture.

22.2. Analyzing and fixing autobuild failures

The Buildroot autobuilders are a set of build machines that continuously run Buildroot builds based on random configurations. This is done for all architectures supported by Buildroot, with various toolchains, and with a random selection of packages. With the large commit activity on Buildroot, these autobuilders are a great help in detecting problems very early after commit.

All build results are available at http://autobuild.buildroot.org, statistics are at http://autobuild.buildroot.org/stats.php. Every day, an overview of all failed packages is sent to the mailing list.

Detecting problems is great, but obviously these problems have to be fixed as well. Your contribution is very welcome here! There are basically two things that can be done:

  • Analyzing the problems. The daily summary mails do not contain details about the actual failures: in order to see what’s going on you have to open the build log and check the last output. Having someone doing this for all packages in the mail is very useful for other developers, as they can make a quick initial analysis based on this output alone.
  • Fixing a problem. When fixing autobuild failures, you should follow these steps:

    1. Check if you can reproduce the problem by building with the same configuration. You can do this manually, or use the br-reproduce-build script that will automatically clone a Buildroot git repository, checkout the correct revision, download and set the right configuration, and start the build.
    2. Analyze the problem and create a fix.
    3. Verify that the problem is really fixed by starting from a clean Buildroot tree and only applying your fix.
    4. Send the fix to the Buildroot mailing list (see Section 22.5, “Submitting patches”). In case you created a patch against the package sources, you should also send the patch upstream so that the problem will be fixed in a later release, and the patch in Buildroot can be removed. In the commit message of a patch fixing an autobuild failure, add a reference to the build result directory, as follows:
Fixes: http://autobuild.buildroot.org/results/51000a9d4656afe9e0ea6f07b9f8ed374c2e4069

22.3. Reviewing and testing patches

With the amount of patches sent to the mailing list each day, the maintainer has a very hard job to judge which patches are ready to apply and which ones aren’t. Contributors can greatly help here by reviewing and testing these patches.

In the review process, do not hesitate to respond to patch submissions for remarks, suggestions or anything that will help everyone to understand the patches and make them better. Please use internet style replies in plain text emails when responding to patch submissions.

To indicate approval of a patch, there are three formal tags that keep track of this approval. To add your tag to a patch, reply to it with the approval tag below the original author’s Signed-off-by line. These tags will be picked up automatically by patchwork (see Section 22.3.1, “Applying Patches from Patchwork”) and will be part of the commit log when the patch is accepted.

Tested-by
Indicates that the patch has been tested successfully. You are encouraged to specify what kind of testing you performed (compile-test on architecture X and Y, runtime test on target A, …). This additional information helps other testers and the maintainer.
Reviewed-by
Indicates that you code-reviewed the patch and did your best in spotting problems, but you are not sufficiently familiar with the area touched to provide an Acked-by tag. This means that there may be remaining problems in the patch that would be spotted by someone with more experience in that area. Should such problems be detected, your Reviewed-by tag remains appropriate and you cannot be blamed.
Acked-by
Indicates that you code-reviewed the patch and you are familiar enough with the area touched to feel that the patch can be committed as-is (no additional changes required). In case it later turns out that something is wrong with the patch, your Acked-by could be considered inappropriate. The difference between Acked-by and Reviewed-by is thus mainly that you are prepared to take the blame on Acked patches, but not on Reviewed ones.

If you reviewed a patch and have comments on it, you should simply reply to the patch stating these comments, without providing a Reviewed-by or Acked-by tag. These tags should only be provided if you judge the patch to be good as it is.

It is important to note that neither Reviewed-by nor Acked-by imply that testing has been performed. To indicate that you both reviewed and tested the patch, provide two separate tags (Reviewed/Acked-by and Tested-by).

Note also that any developer can provide Tested/Reviewed/Acked-by tags, without exception, and we encourage everyone to do this. Buildroot does not have a defined group of core developers, it just so happens that some developers are more active than others. The maintainer will value tags according to the track record of their submitter. Tags provided by a regular contributor will naturally be trusted more than tags provided by a newcomer. As you provide tags more regularly, your trustworthiness (in the eyes of the maintainer) will go up, but any tag provided is valuable.

Buildroot’s Patchwork website can be used to pull in patches for testing purposes. Please see Section 22.3.1, “Applying Patches from Patchwork” for more information on using Buildroot’s Patchwork website to apply patches.

22.3.1. Applying Patches from Patchwork

The main use of Buildroot’s Patchwork website for a developer is for pulling in patches into their local git repository for testing purposes.

When browsing patches in the patchwork management interface, an mbox link is provided at the top of the page. Copy this link address and run the following commands:

$ git checkout -b <test-branch-name>
$ wget -O - <mbox-url> | git am

Another option for applying patches is to create a bundle. A bundle is a set of patches that you can group together using the patchwork interface. Once the bundle is created and the bundle is made public, you can copy the mbox link for the bundle and apply the bundle using the above commands.

22.4. Work on items from the TODO list

If you want to contribute to Buildroot but don’t know where to start, and you don’t like any of the above topics, you can always work on items from the Buildroot TODO list. Don’t hesitate to discuss an item first on the mailing list or on IRC. Do edit the wiki to indicate when you start working on an item, so we avoid duplicate efforts.

22.5. Submitting patches

Note

Please, do not attach patches to bugs, send them to the mailing list instead .

If you made some changes to Buildroot and you would like to contribute them to the Buildroot project, proceed as follows.

22.5.1. The formatting of a patch

We expect patches to be formatted in a specific way. This is necessary to make it easy to review patches, to be able to apply them easily to the git repository, to make it easy to find back in the history how and why things have changed, and to make it possible to use git bisect to locate the origin of a problem.

First of all, it is essential that the patch has a good commit message. The commit message should start with a separate line with a brief summary of the change, prefixed by the area touched by the patch. A few examples of good commit titles:

  • package/linuxptp: bump version to 2.0
  • configs/imx23evk: bump Linux version to 4.19
  • package/pkg-generic: postpone evaluation of dependency conditions
  • boot/uboot: needs host-{flex,bison}
  • support/testing: add python-ubjson tests

The description that follows the prefix should start with a lower case letter (i.e "bump", "needs", "postpone", "add" in the above examples).

Second, the body of the commit message should describe why this change is needed, and if necessary also give details about how it was done. When writing the commit message, think of how the reviewers will read it, but also think about how you will read it when you look at this change again a few years down the line.

Third, the patch itself should do only one change, but do it completely. Two unrelated or weakly related changes should usually be done in two separate patches. This usually means that a patch affects only a single package. If several changes are related, it is often still possible to split them up in small patches and apply them in a specific order. Small patches make it easier to review, and often make it easier to understand afterwards why a change was done. However, each patch must be complete. It is not allowed that the build is broken when only the first but not the second patch is applied. This is necessary to be able to use git bisect afterwards.

Of course, while you’re doing your development, you’re probably going back and forth between packages, and certainly not committing things immediately in a way that is clean enough for submission. So most developers rewrite the history of commits to produce a clean set of commits that is appropriate for submission. To do this, you need to use interactive rebasing . You can learn about it in the Pro Git book. Sometimes, it is even easier to discard you history with git reset --soft origin/master and select individual changes with git add -i or git add -p.

Finally, the patch should be signed off. This is done by adding Signed-off-by: Your Real Name <your@email.address> at the end of the commit message. git commit -s does that for you, if configured properly. The Signed-off-by tag means that you publish the patch under the Buildroot license (i.e. GPL-2.0+, except for package patches, which have the upstream license), and that you are allowed to do so. See the Developer Certificate of Origin for details.

When adding new packages, you should submit every package in a separate patch. This patch should have the update to package/Config.in, the package Config.in file, the .mk file, the .hash file, any init script, and all package patches. If the package has many sub-options, these are sometimes better added as separate follow-up patches. The summary line should be something like <packagename>: new package. The body of the commit message can be empty for simple packages, or it can contain the description of the package (like the Config.in help text). If anything special has to be done to build the package, this should also be explained explicitly in the commit message body.

When you bump a package to a new version, you should also submit a separate patch for each package. Don’t forget to update the .hash file, or add it if it doesn’t exist yet. Also don’t forget to check if the _LICENSE and _LICENSE_FILES are still valid. The summary line should be something like <packagename>: bump to version <new version>. If the new version only contains security updates compared to the existing one, the summary should be <packagename>: security bump to version <new version> and the commit message body should show the CVE numbers that are fixed. If some package patches can be removed in the new version, it should be explained explicitly why they can be removed, preferably with the upstream commit ID. Also any other required changes should be explained explicitly, like configure options that no longer exist or are no longer needed.

If you are interested in getting notified of build failures and of further changes in the packages you added or modified, please add yourself to the DEVELOPERS file. This should be done in the same patch creating or modifying the package. See the DEVELOPERS file for more information.

Buildroot provides a handy tool to check for common coding style mistakes on files you created or modified, called check-package (see Section 18.24.2, “How to check the coding style” for more information).

22.5.2. Preparing a patch series

Starting from the changes committed in your local git view, rebase your development branch on top of the upstream tree before generating a patch set. To do so, run:

$ git fetch --all --tags
$ git rebase origin/master

Now, you are ready to generate then submit your patch set.

To generate it, run:

$ git format-patch -M -n -s -o outgoing origin/master

This will generate patch files in the outgoing subdirectory, automatically adding the Signed-off-by line.

Once patch files are generated, you can review/edit the commit message before submitting them, using your favorite text editor.

Buildroot provides a handy tool to know to whom your patches should be sent, called get-developers (see Chapter 23, DEVELOPERS file and get-developers for more information). This tool reads your patches and outputs the appropriate git send-email command to use:

$ ./utils/get-developers outgoing/*

Use the output of get-developers to send your patches:

$ git send-email --to buildroot@buildroot.org --cc bob --cc alice outgoing/*

Alternatively, get-developers -e can be used directly with the --cc-cmd argument to git send-email to automatically CC the affected developers:

$ git send-email --to buildroot@buildroot.org \
      --cc-cmd './utils/get-developers -e' origin/master

git can be configured to automatically do this out of the box with:

$ git config sendemail.to buildroot@buildroot.org
$ git config sendemail.ccCmd "$(pwd)/utils/get-developers -e"

And then just do:

$ git send-email origin/master

Note that git should be configured to use your mail account. To configure git, see man git-send-email or google it.

If you do not use git send-email, make sure posted patches are not line-wrapped , otherwise they cannot easily be applied. In such a case, fix your e-mail client, or better yet, learn to use git send-email.

22.5.3. Cover letter

If you want to present the whole patch set in a separate mail, add --cover-letter to the git format-patch command (see man git-format-patch for further information). This will generate a template for an introduction e-mail to your patch series.

A cover letter may be useful to introduce the changes you propose in the following cases:

  • large number of commits in the series;
  • deep impact of the changes in the rest of the project;
  • RFC [4] ;
  • whenever you feel it will help presenting your work, your choices, the review process, etc.

22.5.4. Patches for maintenance branches

When fixing bugs on a maintenance branch, bugs should be fixed on the master branch first. The commit log for such a patch may then contain a post-commit note specifying what branches are affected:

package/foo: fix stuff

Signed-off-by: Your Real Name <your@email.address>
---
Backport to: 2020.02.x, 2020.05.x
(2020.08.x not affected as the version was bumped)

Those changes will then be backported by a maintainer to the affected branches.

However, some bugs may apply only to a specific release, for example because it is using an older version of a package. In that case, patches should be based off the maintenance branch, and the patch subject prefix must include the maintenance branch name (for example "[PATCH 2020.02.x]"). This can be done with the git format-patch flag --subject-prefix:

$ git format-patch --subject-prefix "PATCH 2020.02.x" \
    -M -s -o outgoing origin/2020.02.x

Then send the patches with git send-email, as described above.

22.5.5. Patch revision changelog

When improvements are requested, the new revision of each commit should include a changelog of the modifications between each submission. Note that when your patch series is introduced by a cover letter, an overall changelog may be added to the cover letter in addition to the changelog in the individual commits. The best thing to rework a patch series is by interactive rebasing: git rebase -i origin/master. Consult the git manual for more information.

When added to the individual commits, this changelog is added when editing the commit message. Below the Signed-off-by section, add --- and your changelog.

Although the changelog will be visible for the reviewers in the mail thread, as well as in patchwork, git will automatically ignores lines below --- when the patch will be merged. This is the intended behavior: the changelog is not meant to be preserved forever in the git history of the project.

Hereafter the recommended layout:

Patch title: short explanation, max 72 chars

A paragraph that explains the problem, and how it manifests itself. If
the problem is complex, it is OK to add more paragraphs. All paragraphs
should be wrapped at 72 characters.

A paragraph that explains the root cause of the problem. Again, more
than one paragraph is OK.

Finally, one or more paragraphs that explain how the problem is solved.
Don't hesitate to explain complex solutions in detail.

Signed-off-by: John DOE <john.doe@example.net>

---
Changes v2 -> v3:
  - foo bar  (suggested by Jane)
  - bar buz

Changes v1 -> v2:
  - alpha bravo  (suggested by John)
  - charly delta

Any patch revision should include the version number. The version number is simply composed of the letter v followed by an integer greater or equal to two (i.e. "PATCH v2", "PATCH v3" …).

This can be easily handled with git format-patch by using the option --subject-prefix:

$ git format-patch --subject-prefix "PATCH v4" \
    -M -s -o outgoing origin/master

Since git version 1.8.1, you can also use -v <n> (where <n> is the version number):

$ git format-patch -v4 -M -s -o outgoing origin/master

When you provide a new version of a patch, please mark the old one as superseded in patchwork. You need to create an account on patchwork to be able to modify the status of your patches. Note that you can only change the status of patches you submitted yourself, which means the email address you register in patchwork should match the one you use for sending patches to the mailing list.

You can also add the --in-reply-to <message-id> option when submitting a patch to the mailing list. The id of the mail to reply to can be found under the "Message Id" tag on patchwork. The advantage of in-reply-to is that patchwork will automatically mark the previous version of the patch as superseded.

22.6. Reporting issues/bugs or getting help

Before reporting any issue, please check in the mailing list archive whether someone has already reported and/or fixed a similar problem.

However you choose to report bugs or get help, either by opening a bug in the bug tracker or by sending a mail to the mailing list, there are a number of details to provide in order to help people reproduce and find a solution to the issue.

Try to think as if you were trying to help someone else; in that case, what would you need?

Here is a short list of details to provide in such case:

  • host machine (OS/release)
  • version of Buildroot
  • target for which the build fails
  • package(s) for which the build fails
  • the command that fails and its output
  • any information you think that may be relevant

Additionally, you should add the .config file (or if you know how, a defconfig; see Section 9.3, “Storing the Buildroot configuration”).

If some of these details are too large, do not hesitate to use a pastebin service. Note that not all available pastebin services will preserve Unix-style line terminators when downloading raw pastes. Following pastebin services are known to work correctly: - https://gist.github.com/ - http://code.bulix.org/

22.7. Using the run-tests framework

Buildroot includes a run-time testing framework called run-tests built upon Python scripting and QEMU runtime execution. There are two types of test cases within the framework, one for build time tests and another for run-time tests that have a QEMU dependency. The goals of the framework are the following:

  • build a well defined configuration
  • optionally, verify some properties of the build output
  • if it is a run-time test:

    • boot it under QEMU
    • run some test condition to verify that a given feature is working

The run-tests tool has a series of options documented in the tool’s help -h description. Some common options include setting the download folder, the output folder, keeping build output, and for multiple test cases, you can set the JLEVEL for each.

Here is an example walk through of running a test case.

  • For a first step, let us see what all the test case options are. The test cases can be listed by executing support/testing/run-tests -l. These tests can all be run individually during test development from the console. Both one at a time and selectively as a group of a subset of tests.
$ support/testing/run-tests -l
List of tests
test_run (tests.utils.test_check_package.TestCheckPackage)
Test the various ways the script can be called in a simple top to ... ok
test_run (tests.toolchain.test_external.TestExternalToolchainBuildrootMusl) ... ok
test_run (tests.toolchain.test_external.TestExternalToolchainBuildrootuClibc) ... ok
test_run (tests.toolchain.test_external.TestExternalToolchainCCache) ... ok
test_run (tests.toolchain.test_external.TestExternalToolchainCtngMusl) ... ok
test_run (tests.toolchain.test_external.TestExternalToolchainLinaroArm) ... ok
test_run (tests.toolchain.test_external.TestExternalToolchainSourceryArmv4) ... ok
test_run (tests.toolchain.test_external.TestExternalToolchainSourceryArmv5) ... ok
test_run (tests.toolchain.test_external.TestExternalToolchainSourceryArmv7) ... ok
[snip]
test_run (tests.init.test_systemd.TestInitSystemSystemdRoFull) ... ok
test_run (tests.init.test_systemd.TestInitSystemSystemdRoIfupdown) ... ok
test_run (tests.init.test_systemd.TestInitSystemSystemdRoNetworkd) ... ok
test_run (tests.init.test_systemd.TestInitSystemSystemdRwFull) ... ok
test_run (tests.init.test_systemd.TestInitSystemSystemdRwIfupdown) ... ok
test_run (tests.init.test_systemd.TestInitSystemSystemdRwNetworkd) ... ok
test_run (tests.init.test_busybox.TestInitSystemBusyboxRo) ... ok
test_run (tests.init.test_busybox.TestInitSystemBusyboxRoNet) ... ok
test_run (tests.init.test_busybox.TestInitSystemBusyboxRw) ... ok
test_run (tests.init.test_busybox.TestInitSystemBusyboxRwNet) ... ok

Ran 157 tests in 0.021s

OK

Those runtime tests are regularly executed by Buildroot Gitlab CI infrastructure, see .gitlab.yml and https://gitlab.com/buildroot.org/buildroot/-/jobs.

22.7.1. Creating a test case

The best way to get familiar with how to create a test case is to look at a few of the basic file system support/testing/tests/fs/ and init support/testing/tests/init/ test scripts. Those tests give good examples of a basic build and build with run type of tests. There are other more advanced cases that use things like nested br2-external folders to provide skeletons and additional packages.

The test cases by default use a br-arm-full-* uClibc-ng toolchain and the prebuild kernel for a armv5/7 cpu. It is recommended to use the default defconfig test configuration except when Glibc/musl or a newer kernel are necessary. By using the default it saves build time and the test would automatically inherit a kernel/std library upgrade when the default is updated.

The basic test case definition involves

  • Creation of a new test file
  • Defining a unique test class
  • Determining if the default defconfig plus test options can be used
  • Implementing a def test_run(self): function to optionally startup the emulator and provide test case conditions.

After creating the test script, add yourself to the DEVELOPERS file to be the maintainer of that test case.

22.7.2. Debugging a test case

Within the Buildroot repository, the testing framework is organized at the top level in support/testing/ by folders of conf, infra and tests. All the test cases live under the test folder and are organized in various folders representing the catagory of test.

Lets walk through an example.

  • Using the Busybox Init system test case with a read/write rootfs tests.init.test_busybox.TestInitSystemBusyboxRw
  • A minimal set of command line arguments when debugging a test case would include -d which points to your dl folder, -o to an output folder, and -k to keep any output on both pass/fail. With those options, the test will retain logging and build artifacts providing status of the build and execution of the test case.
$ support/testing/run-tests -d dl -o output_folder -k tests.init.test_busybox.TestInitSystemBusyboxRw
15:03:26 TestInitSystemBusyboxRw                  Starting
15:03:28 TestInitSystemBusyboxRw                  Building
15:08:18 TestInitSystemBusyboxRw                  Building done
15:08:27 TestInitSystemBusyboxRw                  Cleaning up
.
Ran 1 test in 301.140s

OK
  • For the case of a successful build, the output_folder would contain a <test name> folder with the Buildroot build, build log and run-time log. If the build failed, the console output would show the stage at which it failed (setup / build / run). Depending on the failure stage, the build/run logs and/or Buildroot build artifacts can be inspected and instrumented. If the QEMU instance needs to be launched for additional testing, the first few lines of the run-time log capture it and it would allow some incremental testing without re-running support/testing/run-tests.
  • You can also make modifications to the current sources inside the output_folder (e.g. for debug purposes) and rerun the standard Buildroot make targets (in order to regenerate the complete image with the new modifications) and then rerun the test. Modifying the sources directly can speed up debugging compared to adding patch files, wiping the output directoy, and starting the test again.
$ ls output_folder/
TestInitSystemBusyboxRw/
TestInitSystemBusyboxRw-build.log
TestInitSystemBusyboxRw-run.log
  • The source file used to implement this example test is found under support/testing/tests/init/test_busybox.py. This file outlines the minimal defconfig that creates the build, QEMU configuration to launch the built images and the test case assertions.

To test an existing or new test case within Gitlab CI, there is a method of invoking a specific test by creating a Buildroot fork in Gitlab under your account. This can be handy when adding/changing a run-time test or fixing a bug on a use case tested by a run-time test case.

In the examples below, the <name> component of the branch name is a unique string you choose to identify this specific job being created.

  • to trigger all run-test test case jobs:
 $ git push gitlab HEAD:<name>-runtime-tests
  • to trigger one test case job, a specific branch naming string is used that includes the full test case name.
 $ git push gitlab HEAD:<name>-<test case name>


[4] RFC: (Request for comments) change proposal

Chapter 23. DEVELOPERS file and get-developers

The main Buildroot directory contains a file named DEVELOPERS that lists the developers involved with various areas of Buildroot. Thanks to this file, the get-developers tool allows to:

  • Calculate the list of developers to whom patches should be sent, by parsing the patches and matching the modified files with the relevant developers. See Section 22.5, “Submitting patches” for details.
  • Find which developers are taking care of a given architecture or package, so that they can be notified when a build failure occurs on this architecture or package. This is done in interaction with Buildroot’s autobuild infrastructure.

We ask developers adding new packages, new boards, or generally new functionality in Buildroot, to register themselves in the DEVELOPERS file. As an example, we expect a developer contributing a new package to include in his patch the appropriate modification to the DEVELOPERS file.

The DEVELOPERS file format is documented in detail inside the file itself.

The get-developers tool, located in utils/ allows to use the DEVELOPERS file for various tasks:

  • When passing one or several patches as command line argument, get-developers will return the appropriate git send-email command. If the -e option is passed, only the email addresses are printed in a format suitable for git send-email --cc-cmd.
  • When using the -a <arch> command line option, get-developers will return the list of developers in charge of the given architecture.
  • When using the -p <package> command line option, get-developers will return the list of developers in charge of the given package.
  • When using the -c command line option, get-developers will look at all files under version control in the Buildroot repository, and list the ones that are not handled by any developer. The purpose of this option is to help completing the DEVELOPERS file.
  • When using without any arguments, it validates the integrity of the DEVELOPERS file and will note WARNINGS for items that don’t match.

Chapter 24. Release Engineering

24.1. Releases

The Buildroot project makes quarterly releases with monthly bugfix releases. The first release of each year is a long term support release, LTS.

  • Quarterly releases: 2020.02, 2020.05, 2020.08, and 2020.11
  • Bugfix releases: 2020.02.1, 2020.02.2, …
  • LTS releases: 2020.02, 2021.02, …

Releases are supported until the first bugfix release of the next release, e.g., 2020.05.x is EOL when 2020.08.1 is released.

LTS releases are supported until the first bugfix release of the next LTS, e.g., 2020.02.x is supported until 2021.02.1 is released.

24.2. Development

Each release cycle consist of two months of development on the master branch and one month stabilization before the release is made. During this phase no new features are added to master, only bugfixes.

The stabilization phase starts with tagging -rc1, and every week until the release, another release candidate is tagged.

To handle new features and version bumps during the stabilization phase, a next branch may be created for these features. Once the current release has been made, the next branch is merged into master and the development cycle for the next release continues there.

Part IV. Appendix

Chapter 25. Makedev syntax documentation

The makedev syntax is used in several places in Buildroot to define changes to be made for permissions, or which device files to create and how to create them, in order to avoid calls to mknod.

This syntax is derived from the makedev utility, and more complete documentation can be found in the package/makedevs/README file.

It takes the form of a space separated list of fields, one file per line; the fields are:

name

type

mode

uid

gid

major

minor

start

inc

count

There are a few non-trivial blocks:

  • name is the path to the file you want to create/modify
  • type is the type of the file, being one of:

    • f: a regular file
    • d: a directory
    • r: a directory recursively
    • c: a character device file
    • b: a block device file
    • p: a named pipe
  • mode are the usual permissions settings (only numerical values are allowed)
  • uid and gid are the UID and GID to set on this file; can be either numerical values or actual names
  • major and minor are here for device files, set to - for other files
  • start, inc and count are for when you want to create a batch of files, and can be reduced to a loop, beginning at start, incrementing its counter by inc until it reaches count

Let’s say you want to change the permissions of a given file; using this syntax, you will need to write:

/usr/bin/foo f 755 0 0 - - - - -
/usr/bin/bar f 755 root root - - - - -
/data/buz f 644 buz-user buz-group - - - - -

Alternatively, if you want to change owner/permission of a directory recursively, you can write (to set UID to foo, GID to bar and access rights to rwxr-x--- for the directory /usr/share/myapp and all files and directories below it):

/usr/share/myapp r 750 foo bar - - - - -

On the other hand, if you want to create the device file /dev/hda and the corresponding 15 files for the partitions, you will need for /dev/hda:

/dev/hda b 640 root root 3 0 0 0 -

and then for device files corresponding to the partitions of /dev/hda, /dev/hdaX, X ranging from 1 to 15:

/dev/hda b 640 root root 3 1 1 1 15

Extended attributes are supported if BR2_ROOTFS_DEVICE_TABLE_SUPPORTS_EXTENDED_ATTRIBUTES is enabled. This is done by adding a line starting with |xattr after the line describing the file. Right now, only capability is supported as extended attribute.

|xattr

capability

  • |xattr is a "flag" that indicate an extended attribute
  • capability is a capability to add to the previous file

If you want to add the capability cap_sys_admin to the binary foo, you will write :

/usr/bin/foo f 755 root root - - - - -
|xattr cap_sys_admin+eip

You can add several capabilities to a file by using several |xattr lines. If you want to add the capability cap_sys_admin and cap_net_admin to the binary foo, you will write :

/usr/bin/foo f 755 root root - - - - -
|xattr cap_sys_admin+eip
|xattr cap_net_admin+eip

Chapter 26. Makeusers syntax documentation

The syntax to create users is inspired by the makedev syntax, above, but is specific to Buildroot.

The syntax for adding a user is a space-separated list of fields, one user per line; the fields are:

username

uid

group

gid

password

home

shell

groups

comment

Where:

  • username is the desired user name (aka login name) for the user. It can not be root, and must be unique. If set to -, then just a group will be created.
  • uid is the desired UID for the user. It must be unique, and not 0. If set to -1, then a unique UID will be computed by Buildroot in the range [1000…1999]
  • group is the desired name for the user’s main group. It can not be root. If the group does not exist, it will be created.
  • gid is the desired GID for the user’s main group. It must be unique, and not 0. If set to -1, and the group does not already exist, then a unique GID will be computed by Buildroot in the range [1000..1999]
  • password is the crypt(3)-encoded password. If prefixed with !, then login is disabled. If prefixed with =, then it is interpreted as clear-text, and will be crypt-encoded (using MD5). If prefixed with !=, then the password will be crypt-encoded (using MD5) and login will be disabled. If set to *, then login is not allowed. If set to -, then no password value will be set.
  • home is the desired home directory for the user. If set to - , no home directory will be created, and the user’s home will be /. Explicitly setting home to / is not allowed.
  • shell is the desired shell for the user. If set to -, then /bin/false is set as the user’s shell.
  • groups is the comma-separated list of additional groups the user should be part of. If set to -, then the user will be a member of no additional group. Missing groups will be created with an arbitrary gid.
  • comment (aka GECOS field) is an almost-free-form text.

There are a few restrictions on the content of each field:

  • except for comment, all fields are mandatory.
  • except for comment, fields may not contain spaces.
  • no field may contain a colon (:).

If home is not -, then the home directory, and all files below, will belong to the user and its main group.

Examples:

foo -1 bar -1 !=blabla /home/foo /bin/sh alpha,bravo Foo user

This will create this user:

  • username (aka login name) is: foo
  • uid is computed by Buildroot
  • main group is: bar
  • main group gid is computed by Buildroot
  • clear-text password is: blabla, will be crypt(3)-encoded, and login is disabled.
  • home is: /home/foo
  • shell is: /bin/sh
  • foo is also a member of groups: alpha and bravo
  • comment is: Foo user
test 8000 wheel -1 = - /bin/sh - Test user

This will create this user:

  • username (aka login name) is: test
  • uid is : 8000
  • main group is: wheel
  • main group gid is computed by Buildroot, and will use the value defined in the rootfs skeleton
  • password is empty (aka no password).
  • home is / but will not belong to test
  • shell is: /bin/sh
  • test is not a member of any additional groups
  • comment is: Test user

Chapter 27. Migrating from older Buildroot versions

Some versions have introduced backward incompatibilities. This section explains those incompatibilities, and for each explains what to do to complete the migration.

27.1. Migrating to 2016.11

Before Buildroot 2016.11, it was possible to use only one br2-external tree at once. With Buildroot 2016.11 came the possibility to use more than one simultaneously (for details, see Section 9.2, “Keeping customizations outside of Buildroot”).

This however means that older br2-external trees are not usable as-is. A minor change has to be made: adding a name to your br2-external tree.

This can be done very easily in just a few steps:

  • First, create a new file named external.desc, at the root of your br2-external tree, with a single line defining the name of your br2-external tree:

    $ echo 'name: NAME_OF_YOUR_TREE' >external.desc

    Note. Be careful when choosing a name: It has to be unique and be made with only ASCII characters from the set [A-Za-z0-9_].

  • Then, change every occurence of BR2_EXTERNAL in your br2-external tree with the new variable:

    $ find . -type f | xargs sed -i 's/BR2_EXTERNAL/BR2_EXTERNAL_NAME_OF_YOUR_TREE_PATH/g'

Now, your br2-external tree can be used with Buildroot 2016.11 onward.

Note: This change makes your br2-external tree incompatible with Buildroot before 2016.11.

27.2. Migrating to 2017.08

Before Buildroot 2017.08, host packages were installed in $(HOST_DIR)/usr (with e.g. the autotools' --prefix=$(HOST_DIR)/usr

posted @ 2021-07-27 00:20  Mojies  阅读(362)  评论(0编辑  收藏  举报