20 使用 devtool 命令行工具

devtool 提供构建、测试和打包软件的多种功能,与 bitbake 命令一起 提供,也是 Extensible Software Development Kit (eSDK) 的重要部分。

20 使用 devtool add 添加应用

devtool add 根据已有源码生成新配方,使用许多 devtool 命令共用的 工作区层结构。它既能将源码提取到工作区或 独立本地 Git 仓库,也能直接使用无需提取的已有代码。

不同场景采用不同参数组合。下图展示常见流程:

../_images/devtool-add-flow.png
  1. 生成新配方: 图上方展示三种基于已有源码生成配方的场景。

    团队开发中,其他开发者往往负责不同源码区域。要在 Yocto Project 开发 中使用这些代码,只需具备源码访问权限、配方以及可控的工作区域。

    三种场景如下:

    • 左侧: 源码尚不在本地,需要提取,并且无需放在工作区外的指定位置。 所有内容均位于默认工作区:

      $ devtool add recipe fetchuri
      

      devtool 将上游源码提取为 sources 下的本地 Git 仓库,并在 工作区创建名为 recipe 的配方和对应追加文件。省略 recipe 时,会尝试 自动判断名称。

    • 中间: 源码也尚不在本地,但需要提取到默认工作区之外。

      备注

      必要时,devtool 会在提取过程中创建本地 Git 仓库。

      第一个位置参数 srctree 指定工作区外的目标位置,必须为空目录:

      $ devtool add recipe srctree fetchuri
      

      源码从 fetchuri 获取,提取到 srctree,成为本地 Git 仓库。 工作区内则创建名为 recipe 的配方及追加文件。

    • 右侧: srctree 已在工作区外准备好。

      指定新配方名称和已有源码树位置:

      $ devtool add recipe srctree
      

      命令检查源码,在工作区创建名为 recipe 的配方。源码已经存在,因此 不会移动,只有新配方进入工作区。另外还创建追加文件目录及初始 *.bbappend。

  2. 编辑配方: devtool edit-recipe 用 $EDITOR 指定的编辑器打开文件:

    $ devtool edit-recipe recipe
    

    保存的修改会在后续构建时生效。

  3. 构建配方或重建镜像: 下一步取决于如何使用新代码。

    如果最终需要把构建输出部署到目标硬件,运行:

    $ devtool build recipe
    

    如果希望工作区配方软件包直接进入镜像,以便部署测试,运行:

    $ devtool build-image image
    
  4. 部署构建输出: 构建后通常需要在目标硬件验证是否符合预期。

    备注

    假定已有预构建镜像运行在 QEMU 或真实硬件上,镜像安装了 SSH。真实 硬件还需能够与开发机器双向网络通信。

    用 devtool deploy-target 部署:

    $ devtool deploy-target recipe target
    

    target 是正在运行 SSH 服务器的目标机器。

    devtool build-image 构建的镜像也可部署到硬件,但 devtool 没有提供 专门的镜像烧写命令。

  5. 完成配方工作: devtool finish 将本地 Git 提交转换为补丁,把新 配方移到长期保存的层,并重置工作区状态,恢复正常配方构建:

    $ devtool finish recipe layer
    

    备注

    需要生成补丁的修改必须先提交到源码树的 Git 仓库。

    最终配方移到指定层后,标准层和上游源码的使用状态会恢复,之后从这些 位置构建,而非工作区。

    备注

    如果决定放弃当前工作,可用 devtool reset 恢复状态,源码树仍保留。

20 使用 devtool modify 修改已有组件源码

devtool modify 用于已有本地配方的组件,可从上游提取代码、指定配方, 并跟踪和收集其他开发者提供的相关补丁。

不同场景的参数组合不同,常见流程如下:

../_images/devtool-modify-flow.png
  1. 准备修改代码: 图中三种场景均假定:

    • 配方位于本地工作区之外的层。

    • 源码位于尚未提取的上游,或已经提取到本地。

    典型情况是其他开发者已创建层和配方,源码可从上游或本地获得。

    • 左侧: 源码尚不在本地,需要从上游提取到默认工作区,配方仍位于 外部 meta-layername 层。

      指定配方即可默认提取源码:

      $ devtool modify recipe
      

      devtool 根据配方 SRC_URI 定位源码及其他开发者的本地补丁。 未提供 srctree 时,提取到工作区默认位置的本地 Git 仓库,并创建 追加文件,原配方位置不变。

      SRC_URI 中以 file:// 引用但不是 *.patch/ 或 *.diff 的本地文件,会复制到新源码树的 oe-local-files。可以在那里方便 地修改或添加文件,下次构建时同源码修改一起生效。

    • 中间: 源码尚不在本地,需要提取为工作区外的本地 Git 仓库;配方 仍在外部层。

      指定配方及提取位置:

      $ devtool modify recipe srctree
      

      备注

      srctree 不能是 URL。

      命令仍按 SRC_URI 找到源码和补丁,将非补丁文件复制到新树的 oe-local-files,源码默认提取到 srctree。

      工作区只创建追加文件,配方保留原位置,源码放在指定位置。

    • 右侧: srctree 已作为 Git 仓库存在于工作区外,配方也在本地 其他层中。

      用 "-n" 表示无需提取,srctree 指向已有源码:

      $ devtool modify -n recipe srctree
      

      若存在 oe-local-files 且包含非补丁文件,会使用它们。若不存在, 随后运行 devtool finish 会删除原配方旁的非补丁文件,因为工具 会认为你已经删除了它们。

      命令完成后,工作区仅有追加文件,配方和源码均保持原位置。

  2. 编辑源码: 使用任意编辑器修改并保存源文件。

  3. 构建配方或重建镜像: 若要将输出部署到目标,运行:

    $ devtool build recipe
    

    若希望工作区软件包进入镜像以便直接部署测试,运行:

    $ devtool build-image image
    
  4. 部署构建输出: 构建后在硬件验证结果。

    备注

    假定已有镜像运行在 QEMU 或真实硬件上,安装了 SSH;真实硬件还需与 开发机器双向网络连通。

    部署命令:

    $ devtool deploy-target recipe target
    

    target 是运行 SSH 服务器的目标机器。

    也可用其他方法部署 devtool build-image 生成的镜像,devtool 本身 没有镜像烧写命令。

  5. 完成配方工作: devtool finish 将本地提交转换成补丁,更新配方 引用,或按目标层创建 .bbappend,并恢复正常构建:

    $ devtool finish recipe layer
    

    备注

    运行 finish 前,需将要转为补丁的修改暂存并提交到本地 Git 仓库。

    无需移动原配方:工具会更新原层配方,或在 layer 指定的另一层创建追加 文件。oe-local-files 中的工作也会保存回配方旁的原文件。

    最后恢复标准层和上游源码状态,使后续构建不再依赖工作区。

    备注

    决定不继续时,可用 devtool reset 恢复;源码树保留。

20 用 devtool ide-sdk 配置 IDE 并准备 SDK

devtool ide-sdk 可为一个或多个配方的源码开发生成 IDE 配置。不同语言和 构建系统需要不同的交叉开发及远程调试工具,例如:

  • C/C++ 项目通常使用 CMake 或 Meson。

  • Python 项目使用 setuptools 或其后继方案。

  • Rust 项目使用 Cargo。

IDE 插件及设置通常也依赖构建系统。为隐藏这些细节,该命令完成两件事:

  • 生成指定配方交叉开发及远程调试所需的 SDK。

  • 生成 IDE 和插件配置,使其直接使用 SDK 提供的交叉工具链及调试工具。

对支持的构建系统,生成配置结合了 devtool modify 工作流程 (在 SDK 工作流中使用 devtool)和 SDK/eSDK 环境设置脚本流程 (运行可扩展 SDK 环境初始化脚本)的优点:

  • 源码位于 devtool modify 或 devtool add 创建的工作区,仍可使用 devtool build、devtool build-image、devtool deploy-target 和 bitbake,也可随时再次运行 devtool ide-sdk 更新 SDK 和 IDE 配置。

  • 目标是原生支持多语言、多 IDE,即让 IDE 直接调用 cmake、meson 等工具。通常比 devtool build 快,也能利用 VSCode 对 CMake、GDB 等的良好集成。

    多语言和多 IDE 支持复杂且持续变化,因此 IDE 支持采用插件实现,可由 可选层提供。

以上是默认的 "modified" 模式,它使用 devtool modify 工作区以及 BitBake 的配方专用 系统根目录。

某些配方或场景不适合这种完整集成,因此还有 "shared" 模式。使用 --mode=shared 时,直接从 BitBake 环境准备 SDK,提供 运行可扩展 SDK 环境初始化脚本 中相同的环境设置脚本,并配置 IDE 使用 共享 系统根目录 和 SDK 工具。它本质上是 直接在 Yocto 构建中配置可扩展 SDK 环境 所述可扩展 SDK 设置流程的包装。

该命令可以替代 SDK 安装器,提供标准 SDK 和 eSDK 的全部功能,同时更加灵活。 例如,很容易修改 build/conf/local.conf 中的 MACHINE, 更新层元数据后重新生成 SDK。

两种模式的示例如下:

  1. Modified 模式:

    先进行少量设置,例如在 build/conf/local.conf 添加:

    # Build the companion debug file system
    IMAGE_GEN_DEBUGFS = "1"
    # Optimize build time: with devtool ide-sdk the dbg tar is not needed
    IMAGE_FSTYPES_DEBUGFS = ""
    # Without copying the binaries into roofs-dbg, GDB does not find all source files.
    IMAGE_CLASSES += "image-combined-dbg"
    
    # SSH is mandatory, no password simplifies the usage
    EXTRA_IMAGE_FEATURES += "\
       ssh-server-openssh \
       allow-empty-password \
       allow-root-login \
       empty-root-password \
    "
    
    # Remote debugging needs gdbserver on the target device
    IMAGE_INSTALL:append = " gdbserver"
    
    # Add the recipes which should be modified to the image
    # Otherwise some dependencies might be missing.
    IMAGE_INSTALL:append = " my-recipe"
    

    假定 BitBake 环境已就绪,且通过 devtool modify my-recipe,或更推荐 的 devtool modify my-recipe --debug-build 创建工作区,可运行:

    $ devtool ide-sdk my-recipe core-image-minimal --target root@192.168.7.2
    

    命令需要镜像配方,本例为 core-image-minimal,用于生成 SDK。目标 设备也应安装该固件镜像。可以指定多个软件包配方:

    $ devtool ide-sdk my-recipe-1 my-recipe-2 core-image-minimal --target root@192.168.7.2
    

    工具尝试为所有配方生成 IDE 配置。具体行为取决于配方使用的构建工具, 基本原则是让 IDE 的调用方式与 BitBake 完全一致。

    例如,继承 cmake 的配方会生成 CMake preset,VSCode 的 CMake Tools 插件支持它,从而获得与 BitBake 相同的构建结果。

    交叉 SDK 需要与 IDE 无缝集成的远程调试。工具会生成部署产物到目标的 辅助脚本,以及调试器和 IDE 配置。

    备注

    目标必须运行 devtool ide-sdk 构建的镜像,确保主机符号与目标 二进制匹配。

    默认 IDE 为 VSCode,使用提示如下:

    • VSCode 可编辑配方或应用源码。通常先在配方目录启动一个实例,运行 Yocto Project BitBake 插件。

      警告

      Python、BitBake 等插件需合理配置,否则可能尝试索引整个 BitBake 构建目录,长时间占用资源,甚至耗尽内存;也可能无法正常工作。

      若能找到 code 且尚无 .vscode,oe-init-build-env 会创建 初始 .vscode/settings.json。最好在启动 VSCode 前先运行一次。 也可以把构建目录放在层之外,例如 oe-init-build-env ../build。

      BitBake 插件可通过少量点击创建工作区并运行 devtool ide-sdk,也 可以在终端执行命令。

    • 开发配方源码时,在其工作区另开 VSCode 实例,例如:

      code build/workspace/sources/my-recipe
      

      此实例使用适合应用开发的插件。工具会生成所需 extensions.json、 settings.json、tasks.json 和 launch.json。

      首次打开源码目录时会提示安装插件,接受后即可照常编辑和调试。也可 在第一个 VSCode 实例中点击配方工作区,启动相应实例。

    • 使用 CMake 时按 Ctrl + Shift + p,输入 cmake,可选择 preset、 编译或运行 CTest。

      若配方继承 cmake-qemu 而非 cmake, 可透明地通过 QEMU 用户模式在主机运行交叉编译单元测试。

    • 使用 Meson 时按 Ctrl + Shift + p,输入 meson,可编译或运行 单元测试。

      Meson 默认支持 QEMU 用户模式。只要代码适合在主机执行,通常无需额外 步骤即可从 IDE 运行交叉编译测试。

    • 部署时按 Ctrl + Shift + p,输入 task,选择 install && deploy-target。

    • 远程调试时,点击左侧带 bug icon 的播放按钮,进入调试视图。 在绿色播放按钮旁下拉列表选择生成的配置,再点击播放。

      启动调试会自动部署。如不需要,在 tasks.json 中为 "label": "gdbserver start... 的任务移除 "dependsOn": ["install && deploy-target...]。

      VSCode 支持多种 GDB 配置,但许多在交叉开发、架构支持或目标性能上 有限制,因此工具采用通用的主机 GDB、目标 gdbserver 方式:

      • tasks.json 引用脚本,通过 SSH 复制二进制到目标。

      • 相应脚本通过 SSH 启动目标 gdbserver。

        修改被调试程序参数需编辑 oe-scripts/gdbserver_* 脚本。 launch.json 的 args 字段对此无效。

      • VSCode 按 远程调试或使用本地调试服务器 所述连接 gdbserver。

    也支持 --ide=none,生成 gdbinit 等通用配置和辅助脚本,用于启动 目标 gdbserver 及主机 GDB。

    以下示例使用 meta-selftest 中继承 cmake-qemu 的 cmake-example:

    # Create the SDK
    devtool modify cmake-example --debug-build
    devtool ide-sdk cmake-example core-image-minimal -c --ide=none
    
    # Install the firmware on a target device or start QEMU
    runqemu
    
    # From exploring the workspace of cmake-example
    cd build/workspace/sources/cmake-example
    
    # Find cmake-native and save the path into a variable
    # Note: using just cmake instead of $CMAKE_NATIVE would work in many cases
    CMAKE_NATIVE="$(jq -r '.configurePresets[0] | "\(.cmakeExecutable)"' CMakeUserPresets.json)"
    
    # List available CMake presets
    "$CMAKE_NATIVE" --list-presets
    Available configure presets:
    
      "cmake-example-cortexa57" - cmake-example: cortexa57
    
    # Re-compile the already compiled sources
    "$CMAKE_NATIVE" --build --preset cmake-example-cortexa57
    ninja: no work to do.
    # Do a clean re-build
    "$CMAKE_NATIVE" --build --preset cmake-example-cortexa57 --target clean
    [1/1] Cleaning all built files...
    Cleaning... 8 files.
    "$CMAKE_NATIVE" --build --preset cmake-example-cortexa57 --target all
    [7/7] Linking CXX executable cmake-example
    
    # Run the cross-compiled unit tests with QEMU user-mode
    "$CMAKE_NATIVE" --build --preset cmake-example-cortexa57 --target test
    [0/1] Running tests...
    Test project .../build/tmp/work/cortexa57-poky-linux/cmake-example/1.0/cmake-example-1.0
        Start 1: test-cmake-example
    1/1 Test #1: test-cmake-example ...............   Passed    0.03 sec
    
    100% tests passed, 0 tests failed out of 1
    
    Total Test time (real) =   0.03 sec
    
    # Using CTest directly is possible as well
    CTEST_NATIVE="$(dirname "$CMAKE_NATIVE")/ctest"
    
    # List available CMake presets
    "$CTEST_NATIVE" --list-presets
    Available test presets:
    
      "cmake-example-cortexa57" - cmake-example: cortexa57
    
    # Run the cross-compiled unit tests with QEMU user-mode
    "$CTEST_NATIVE" --preset "cmake-example-cortexa57"
    Test project ...build/tmp/work/cortexa57-poky-linux/cmake-example/1.0/cmake-example-1.0
        Start 1: test-cmake-example
    1/1 Test #1: test-cmake-example ...............   Passed    0.03 sec
    
    100% tests passed, 0 tests failed out of 1
    
    Total Test time (real) =   0.03 sec
    
    # Deploying the new build to the target device (default is QEUM at 192.168.7.2)
    oe-scripts/install_and_deploy_cmake-example-cortexa57
    
    # Start a remote debugging session with gdbserver on the target and GDB on the host
    oe-scripts/gdbserver_1234_usr-bin-cmake-example_m
    oe-scripts/gdb_1234_usr-bin-cmake-example
    break main
    run
    step
    stepi
    continue
    quit
    
    # Stop gdbserver on the target device
    oe-scripts/gdbserver_1234_usr-bin-cmake-example_m stop
    
  2. 共享系统根目录模式:

    创建包含 my-recipe 全部开发依赖、使用共享 系统根目录 的 SDK:

    $ devtool ide-sdk --mode=shared my-recipe
    

    在 VSCode 中,交叉工具链以 CMake kit 提供,定义位于 ~/.local/share/CMakeTools/cmake-tools-kits.json。以下创建 CMake 项目并启动 VSCode,演示工具链选择:

    mkdir kit-test
    echo "project(foo VERSION 1.0)" > kit-test/CMakeLists.txt
    code kit-test
    

    工作区有 CMake 项目后,可启用交叉编译:

    • 按 Ctrl + Shift + P,输入 CMake: Scan for Kits

    • 按 Ctrl + Shift + P,输入 CMake: Select a Kit

    随后应能使用多数 CMake 和 IDE 功能。

    也支持其他 IDE。不过,devtool ide-sdk --mode=shared --ide=none my-recipe 目前只是 直接在 Yocto 构建中配置可扩展 SDK 环境 所述流程的简单包装。

20 使用 devtool upgrade 创建支持新版软件的配方

devtool upgrade 将已有配方升级到更近的上游版本。软件不断演进,可用此 流程保持构建配方与上游同步。

备注

这只是升级方法之一。完整介绍见 升级配方。

命令允许指定源码修订和版本方案,将代码提取到工作区内外,并支持 Fetchers 能处理的所有 源码形式。工作区结构见 工作区层结构。

常见流程如下:

../_images/devtool-upgrade-flow.png
  1. 开始升级: 典型场景满足:

    • 配方位于本地工作区之外的层。

    • 新版源码与原 SRC_URI 指向的位置一致,例如文件名带新版号的 归档包,或上游 Git 仓库中的另一修订。

    常见情况是第三方软件已更新,而配方位于自己的层,需要升级:

    $ devtool upgrade -V version recipe
    

    默认提取到 工作区层结构 的 sources。 如需其他位置,指定 srctree:

    $ devtool upgrade -V version recipe srctree
    

    备注

    "-V" 指定新版本;省略时升级到最新版本。

    如果 SRC_URI 指向 Git,必须通过 "-S" 指定源码修订。

    命令根据 SRC_URI 找到源码和本地补丁,在工作区准备源码、新版 配方及追加文件。

    file:// 引用中除 *.patch/、*.diff 外的非补丁文件,复制到 新源码树的 oe-local-files。在此修改或添加的文件,会在下次构建时 与源码变更一起生效。

  2. 解决升级冲突: 如果原配方补丁与新版源码冲突,应编辑源码,按普通 git rebase 冲突解决流程处理。继续之前,必须解决所有冲突。

  3. 构建配方或重建镜像: 如需部署构建输出,运行:

    $ devtool build recipe
    

    如需将工作区软件包直接放入镜像,运行:

    $ devtool build-image image
    
  4. 部署输出: devtool build 或 bitbake 构建后,在硬件验证。

    备注

    假定预构建镜像已运行于 QEMU 或真实硬件,安装了 SSH;真实硬件与开发 主机之间需网络互通。

    部署命令:

    $ devtool deploy-target recipe target
    

    target 是运行 SSH 服务器的目标机器。

    devtool build-image 生成的镜像也可部署到真实硬件,但 devtool 没有 专门执行此操作的命令。

  5. 完成配方工作: devtool finish 根据本地提交生成补丁,将新版配方 移到长期保存的层,并恢复正常构建。

    oe-local-files 中的修改会保存回配方旁的原文件。

    如果目标层就是原层,先删除旧配方及相关文件,再加入新版:

    $ devtool finish recipe layer
    

    备注

    要转换为补丁的修改必须先提交到源码 Git 仓库。

    最后恢复标准层和上游源码状态,使后续从正常位置而非工作区构建。

    备注

    若决定放弃当前工作,可用 devtool reset,源码树仍保留。

20 深入了解 devtool add

该命令根据给定源码树自动创建配方,目前支持:

  • Autotools(autoconf 和 automake)

  • CMake

  • Scons

  • qmake

  • 普通 Makefile

  • 树外内核模块

  • 二进制包("-b" 选项)

  • Node.js 模块

  • 使用 setuptools 或 distutils 的 Python 模块

除二进制包外,均根据源码树中的文件自动判断。例如,发现 CMakeLists.txt 就按 CMake 项目处理。

备注

通常需要编辑自动生成的配方,经过多轮编辑和构建才能成功。构建成功后, 还可继续在目标上迭代测试。

以下介绍配方各部分如何生成。

20 名称和版本

命令行未指定名称和版本时,工具从源码元数据推断,并据此命名配方文件。

无法判断时会报错,需重新运行,明确给出名称、版本或两者。

如果推断结果不正确,先重置:

$ devtool reset -n recipename

再运行 devtool add 并指定正确名称或版本。

20 依赖检测与映射

工具尝试检测构建依赖并映射到系统其他配方,将名称填入 DEPENDS。 无法映射时,会在配方中注释说明,原因可能是名称无法识别,或依赖根本不存在。 后者需再用 devtool add 创建满足依赖的配方,然后更新原配方 DEPENDS。

运行时依赖可这样添加:

RDEPENDS:${PN} += "dependency1 dependency2 ..."

备注

工具通常不能区分必需与可选依赖,检测到的部分依赖可能可选。不确定时, 查阅软件文档或配置脚本。有时可传入选项禁用相关功能,从而去掉依赖。

20 许可证检测

工具尝试判断软件是否采用常见开源许可证,并设置 LICENSE。应对照 软件文档或源码复核,必要时更正。

它还将 LIC_FILES_CHKSUM 指向疑似许可证文件。但源文件头部注释或 文档中的声明可能无法识别,需要手动补充指向这些文本。对于第三方软件,这 尤其重要:未来升级配方时,机制会检测许可证变化并报错,提示重新检查。

若无法判断许可证,工具设 LICENSE 为 "CLOSED",不设置 LIC_FILES_CHKSUM,让开发可以继续。这未必正确,仍需检查文档或源码 确定实际许可证。

20 添加仅使用 Makefile 的软件

专有和开源软件都常直接使用 Make,但 Makefile 往往未考虑交叉编译,devtool 能自动处理的内容有限。例如,直接调用 gcc 而非 CC 很常见。 在交叉环境中,gcc 通常是主机编译器,目标编译器名称类似 arm-poky-linux-gnueabi-gcc,还可能需要指定目标系统根目录等参数。

编写此类配方时应注意:

  • 通常需要修补 Makefile,以变量代替硬编码的 gcc、g++ 等工具。

  • Make 环境已设置 CC、CXX 等标准变量,与 SDK 环境脚本 类似。运行 devtool build 后,可在 oe-logs/run.do_compile 开头 查看变量列表,Makefile 可以利用它们。

  • Makefile 用 "=" 设置默认值会覆盖环境,通常不符合预期。可改成 "?=", 或在 make 命令行强制赋值。后者通过配方的 EXTRA_OEMAKE 或 PACKAGECONFIG_CONFARGS 实现,例如:

    EXTRA_OEMAKE += "'CC=${CC}' 'CXX=${CXX}'"
    

    变量设置用单引号包围,因为编译器默认选项可能使值包含空格。

  • 硬编码路径在交叉环境中常有问题:它们通常指向主机,可能只读,也可能将 主机内容错误引入目标构建。一般应修补为 prefix 等路径变量。

  • Makefile 有时调用 ldconfig 等目标专用命令,可考虑修补并移除这些调用。

20 添加本机工具

需要构建运行于 Build Host 而非目标的工具时,可在 devtool add 使用以下任一方式:

  • 配方名称以 "-native" 结尾,生成仅面向构建主机的配方。

  • 使用 "--also-native",既构建目标版本,也生成带 "-native" 后缀的主机变体。

备注

如果工具与目标代码在同一源码树中,通常将本机和目标部分分开构建,而不在 同一编译过程中处理。"--also-native" 允许只用一份配方完成。

20 添加 Node.js 模块

警告

NPM 获取器目前因安全问题禁用,详见 355cd22。

可通过 npm,或通过仓库、本地源码添加 Node.js 模块。

npm 方式如下:

$ devtool add "npm://registry.npmjs.org;name=forever;version=0.15.1"

名称和版本是必需参数。工具生成并引用 lockdown 和 shrinkwrap 文件,将依赖 版本固定为首次获取的版本,并保存供未来验证的校验和,确保构建可复现和完整。

备注

  • URL 必须加引号。虽然 devtool 本身不要求,但 Shell 会将分号当作命令 分隔符,导致参数未完整传入并出现多个 "command not found" 错误。

从仓库或本地源码添加时,形式如下:

$ devtool add https://github.com/diversario/node-ssdp

工具获取 Git 仓库,识别 Node.js 代码,通过 npm 获取依赖,并相应设置 SRC_URI。

20 处理配方

devtool build 的典型步骤为:

  1. 获取源码

  2. 解包源码

  3. 配置源码

  4. 编译源码

  5. 安装构建输出

  6. 打包安装结果

工作区源码已准备好并持久保存,因此获取和解包步骤禁用。各步骤以任务函数 定义,通常带 "do_" 前缀,如 do_fetch、do_unpack。 函数通常是 Shell 脚本,也可用 Python。

配方通常不包含完整构建指令,而通过 inherit 复用类中的公共功能,只描述 软件特有内容。所有配方隐式继承 base,获得多数配方需要 的基础功能。

下文介绍配方开发中的其他信息。

20 查找日志和工作文件

首次 devtool build 后,先前通过 add 或 modify 准备的源码树会出现符号链接:

  • oe-logs:指向各构建步骤的日志和运行脚本目录。

  • oe-workdir:指向临时工作区,其中有用位置包括:

    • image/:do_install 安装的全部文件,配方中通过 ${D} 引用。

    • sysroot-destdir/:安装文件中进入共享系统根目录的子集。见 “在配方之间共享文件”。

    • packages-split/:每个输出软件包一个子目录。见 “打包”。

这些链接便于检查各构建步骤的实际结果。

20 设置配置参数

使用 GNU autoconf 时,会传入固定的交叉编译参数,加上配方中的 EXTRA_OECONF 或 PACKAGECONFIG_CONFARGS。额外选项可加入 这些变量。其他构建工具也有类似变量,例如 CMake 的 EXTRA_OECMAKE、 Scons 的 EXTRA_OESCONS。make 命令行参数通过 EXTRA_OEMAKE 或 PACKAGECONFIG_CONFARGS 设置。

devtool configure-help 显示实际传入选项以及自定义参数;适用时,还显示 配置脚本的 "--help" 输出供参考。

20 在配方之间共享文件

配方常需要使用其他配方在 Build Host 提供的文件,例如链接公共库 需要库及头文件。这通过 Sysroot 实现,目标和构建主机各有一个。

配方绝不能直接写系统根目录。应在 do_install 中安装到 ${D} 的标准位置,部分文件会自动进入系统根目录。这样 几乎所有文件都能登记在清单中,配方修改或移除时可清理,避免残留过时文件。

20 打包

镜像内容按软件包而非配方定义,因此理解构建输出如何进入目标镜像,需要 理解打包。

do_package 将安装结果拆分成通常与配方同名的主包,以及若干 其他包,因为并非每个镜像都需要全部文件。例如生产镜像通常不需文档,因此 文档单独进入 -doc;带可选模块或插件的软件还可能进一步拆包。

构建后可在 oe-workdir/packages-split 查看各包内容。除高级情况外,拆分 由 PACKAGES 和 FILES 控制:前者列出所有输出包,后者通过 包名覆盖指定文件,例如 FILES:${PN} 指定主包文件,${PN} 为配方名称。包顺序很重要,每个文件进入第一个匹配其 FILES 的包。 这两个变量都有默认值,除非软件安装到非标准位置,否则往往无需自行设置。

20 将目标设备恢复到原始状态

devtool deploy-target 会备份覆盖的文件。如果修改已有系统组件后需要 恢复,可用 devtool undeploy-target 还原备份,并删除该配方部署的其他文件:

$ devtool undeploy-target lighttpd root@192.168.7.2

部署了多个应用时,用 "-a" 全部移除,恢复原始状态:

$ devtool undeploy-target -a root@192.168.7.2

部署文件记录和备份保存在目标设备本身,因此会额外占用目标空间。

备注

deploy-target 和 undeploy-target 目前不与目标 RPM、OPKG 等包管理器 交互。不要将它们与包管理器操作混用,否则可能产生文件冲突。