在Yocto环境中添加自定义应用程序和库

概述

本文档指导用户在Yocto构建系统中添加自定义应用程序和库文件(以helloworld为例)。通过以下步骤,您可以将自己的代码集成到Yocto项目中,并生成包含这些组件的安装包和库以供使用。

目录

  1. 准备环境
  2. 用户新增APP
  3. 添加第三方库

准备环境

安装准备

  • 安装必要的支持软件包。
  • 克隆代码。

具体的环境准备见:开发环境准备

创建项目目录

  • 设定目录结构以便于管理和开发。
meta-custom/
├── conf/
│   └── layer.conf
├── recipes-apps/
│   └── helloworld/
│       ├── files/
│       │   ├── helloworld.c
│       │   ├── Makefile
│       │   └── helloworld.service
│       └── helloworld_1.0.bb
└── recipes-libs/
    └── lib-helloworld/
        ├── files/
        │   ├── lib_helloworld.c
        │   ├── lib_helloworld.h
        │   └── Makefile
        └── lib-helloworld_1.0.bb

新增APP

创建应用程序文件

创建层目录

mkdir -p ${YOCTO_DIR}/layers/meta-custom/recipes-apps/helloworld/files
mkdir -p ${YOCTO_DIR}/layers/meta-custom/conf

配置层

  • 编辑layers/meta-custom/conf/layer.conf文件:

    BBPATH .= ":${LAYERDIR}"
    BBFILES += "${LAYERDIR}/recipes-*/*/*.bb"
    LAYERDEPENDS_meta-custom = "core"
    LAYERSERIES_COMPAT_meta-custom = "kirkstone"
    
  • 将以下内容添加到layers/meta-qcom-distro/conf/bblayers.conf

    BBLAYERS = "
      ${WORKSPACE}/layers/meta-custom \
    "
    
  • 同时在layers/meta-quectel/recipes-products/images/ qcom-multimedia-image.bbappend添加以下内容:

    IMAGE_INSTALL:append = "helloworld"
    IMAGE_INSTALL:append = " \
        lib-helloworld \
        lib-helloworld-dev \
        lib-helloworld-staticdev \
    "
    

创建应用程序源代码

  • meta-custom/recipes-apps/helloworld/files目录下创建helloworld.c

    // helloworld.c
    #include <stdio.h>
    
    int main() {
        printf("Hello, world!\n");
        return 0;
    }
    

编写Makefile

  • meta-custom/recipes-apps/helloworld/files下创建Makefile

    # 使用Yocto提供的编译标志
    all: helloworld
    
    helloworld: helloworld.c
    $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
    
    clean:
    rm -f helloworld
    
    .PHONY: all clean
    

创建Systemd服务文件

  • meta-custom/recipes-apps/helloworld/files下创建helloworld.service

    [Unit]
    Description=Hello World Service
    
    [Service]
    Type=simple
    ExecStart=/usr/bin/helloworld
    
    [Install]
    WantedBy=multi-user.target
    

编写BitBake配方

  • meta-custom/recipes-apps/helloworld/下创建helloworld_1.0.bb

    SUMMARY = "Hello World application"
    DESCRIPTION = "A simple Hello World application."
    LICENSE = "MIT"
    LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
    
    # 源代码文件列表(包含helloworld.c源文件、Makefile和systemd服务文件)
    SRC_URI = "file://helloworld.c \
           file://Makefile \
           file://helloworld.service"
    
    # 设置工作目录(${WORKDIR}是BitBake构建时的工作目录)
    S = "${WORKDIR}"
    
    # 继承systemd类(添加对systemd服务的支持)
    inherit systemd
    
    # 定义systemd服务文件名(${PN}会自动替换为软件包名)
    SYSTEMD_SERVICE:${PN} = "helloworld.service"
    
    # 配置阶段(这里跳过配置阶段)
    do_configure () {
    bbnote skip do_configure  # 记录跳过配置阶段的日志
    }
    
    # 编译阶段
    do_compile() {
    # 先执行make clean清理
    oe_runmake -f ${S}/Makefile clean
    # 然后执行make编译
    oe_runmake -f ${S}/Makefile
    }
    
    # 安装阶段
    do_install() {
    # 创建安装目录(${D}是目标根目录,${bindir}通常是/usr/bin)
    install -d ${D}${bindir}
    # 安装helloworld可执行文件到/usr/bin,设置权限为755
    install -m 0755 ${S}/helloworld ${D}${bindir}
    
    # 创建systemd服务目录(${systemd_system_unitdir}通常是/lib/systemd/system)
    install -d ${D}${systemd_system_unitdir}
    # 安装helloworld.service服务文件,设置权限为644
    install -m 0644 ${S}/helloworld.service ${D}${systemd_system_unitdir}
    }
    

应用程序的构建与运行

设置构建环境

  • 进入编译环境代码工作目录,配置编译环境:

    source quectel_build/compile/build.sh
    

    -用户可以根据自己需要去选择安装应用程序,采取单编或是rootfs 整编方式。

安装应用程序(单编,ipk安装)

  • meta-custom/recipes-apps/目录下执行以下命令:

    bitbake helloworld
    
  • 构建完成后,生成的.ipk文件位于:

    find ~/build-qcom-wayland/tmp-glibc/deploy -name "helloworld*.ipk"
    /home/quectel/build-qcom-wayland/tmp-glibc/deploy/ipk/armv8-2a/helloworld_1.0-r0_armv8-2a.ipk
    
  • 将生成的.ipk文件推送至设备:

    adb push .\helloworld_1.0-r0_armv8-2a.ipk /mnt
    
  • 安装.ipk文件:

    # 安装前需挂载文件系统为读写模式
    mount -o remount,rw /usr
    root@qcm6490-idp:/mnt# opkg install helloworld_1.0-r0_armv8-2a.ipk
    
  • 验证安装:

    root@qcm6490-idp:/mnt# /usr/bin/helloworld
    Hello, world!
    

安装应用程序(rootfs 整编)

  • meta-custom/recipes-apps/目录下执行以下命令:

    #用户可自定义输入 "ProjectName" "ProjectRev” "CustName",从提示的 Valid Projects 和 Valid CUST_NAME 里面选择当前有效的字段进行用户定制。
    buildconfig QSM565DWF SG565DWFPARL1A01_BL01BP01K0M01_QDP_LP6.6.0XX.01.00X_V0X STD
    #上述命令完成后执行 buildall
    buildall
    #上述命令完成后执行 buildpackage
    buildpackage
    
  • 生成的镜像包含在quectel_build/SG565DWFPARL1A01_BL01BP01K0M01_QDP_LP6.6.0XX.01.00X_V0X路径下,

用户可参考链接使用 Yocto 构建 PI-SG565D 单板电脑镜像 QDL 介绍和镜像烧录
.

进行烧录。

  • 验证安装:
    root@qcm6490-idp:~# /usr/bin/helloworld
    Hello, world!
    

添加第三方库

创建库文件

创建层目录

mkdir -p ${YOCTO_DIR}/layers/meta-custom/recipes-libs/lib-helloworld/files

创建库源代码

  • meta-custom/recipes-libs/lib-helloworld/files/下创建lib_helloworld.clib_helloworld.h

    // lib_helloworld.c
    #include <stdio.h>
    
    void hello_print(const char* name) {
        printf("[LIB] Hello, %s!\n", name);
    }
    
    // lib_helloworld.h
    #ifndef LIB_HELLO_H
    #define LIB_HELLO_H
    
    void hello_print(const char*);
    
    #endif
    

编写Makefile

  • meta-custom/recipes-libs/lib-helloworld/files下创建Makefile
    ```Makefile
    LIB_VERSION = "1.0"

      all:
          ${CC} ${CFLAGS} -fPIC -c lib_helloworld.c -o lib_helloworld.o
          ${CC} ${CFLAGS} -fPIC -shared lib_helloworld.o -o libhello.so.${LIB_VERSION} \
              -Wl,-soname,libhello.so.1 ${LDFLAGS}
          ar rcs libhello.a lib_helloworld.o
          ln -sf libhello.so.${LIB_VERSION} libhello.so
          ln -sf libhello.so.${LIB_VERSION} libhello.so.1
    
      clean:
          rm -f libhello.so*
          rm -f lib_helloworld.o
          rm -f libhello.a
      ```
    

编写BitBake配方

  • meta-custom/recipes-libs/lib-helloworld/下创建lib-helloworld_1.0.bb

    SUMMARY = "Hello World Library"
    SECTION = "libs"
    LICENSE = "MIT"
    LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
    
    SRC_URI = "file://lib_helloworld.c \
               file://Makefile \
               file://lib_helloworld.h"
    
    S = "${WORKDIR}"
    
    EXTRA_OEMAKE = "'CC=${CC}' 'CFLAGS=${CFLAGS} -fPIC' 'LDFLAGS=${LDFLAGS}'"
    
    do_install() {
        # 1. 创建目标目录
        install -d ${D}${libdir}
    
        # 2. 安装共享库并创建符号链接
    
        install -m 0755 ${S}/libhello.so.${PV} ${D}${libdir}/
        ln -sf libhello.so.${PV} ${D}${libdir}/libhello.so
        ln -sf libhello.so.${PV} ${D}${libdir}/libhello.so.1
    
        # 3. 安装静态库
        install -m 0644 ${S}/libhello.a ${D}${libdir}/
    
    }
    
    # 包文件分配
    FILES:${PN} = " \
        ${libdir}/libhello.so.1 \
        ${libdir}/libhello.so.${PV} \
    "
    
    FILES:${PN}-dev = " \
        ${libdir}/libhello.so \
    "
    
    FILES:${PN}-staticdev = " \
        ${libdir}/libhello.a \
    "
    
    
    

库的构建与使用

设置构建环境

  • 进入编译环境代码工作目录,配置编译环境:

    source quectel_build/compile/build.sh
    

三方库的使用(bitbake单编)

  • bitbake构建:

    bitbake lib-helloworld
    
  • 根目录下搜索生成的动态库文件:

    find ./* -name "libhello*"
    
  • 将库文件推送至设备:

    adb push libhello.so libhello.so.1 libhello.so.1.0 libhello.a /usr/lib
    
  • 修复执行权限并重建符号链接:

    chmod +x /usr/lib/libhello.so /usr/lib/libhello.so.1 /usr/lib/libhello.so.1.0 /usr/lib/libhello.a
    ln -sf libhello.so.1.0 libhello.so.1
    ln -sf libhello.so.1 libhello.so
    
  • 编写测试程序:

    // static_test_helloworld.c
    #include <stdio.h>
    
    void hello_print(const char*);
    
    int main() {
        printf("static lib test\n");
        hello_print("world");
        return 0;
    }
    
    //dynamic_test_helloworld.c
     #include <stdio.h>
    
    void hello_print(const char*);
    
    int main() {
        printf("dynamic lib test\n");
        hello_print("world");
        return 0;
    }
    
  • 编译并运行测试程序:

    #静态库测试
    gcc static_test_helloworld.c -lhello -static -o static_hello
    ./static_hello
    # 输出: 
    static lib test
    [LIB] Hello, world!
    
    #动态库测试
    gcc dynamic_test_helloworld.c /usr/lib/libhello.so -o dynamic_hello
    ./dynamic_hello
    # 输出: 
    dynamic lib  test
    [LIB] Hello, world!
    
    

三方库的使用(rootfs整编)

  • 编译和烧录可参考上述安装应用程序(rootfs 整编)中的方法

  • 验证使用(需要参考三方库的使用描述的编写测试程序):

    /mnt# ls -l /usr/lib/libhello*
    -rw-r--r--. 2 root root 5002 Jan  1  1970 /usr/lib/libhello.a
    lrwxrwxrwx. 1 root root   15 Jul 25 06:26 /usr/lib/libhello.so -> libhello.so.1.0
    lrwxrwxrwx. 1 root root   15 Jul 25 06:26 /usr/lib/libhello.so.1 -> libhello.so.1.0
    -rwxr-xr-x. 2 root root 5968 Jan  1  1970 /usr/lib/libhello.so.1.0
    
    #静态库测试
    gcc static_test_helloworld.c -lhello -static -o static_hello
    ./static_hello
    # 输出: 
    static lib test
    [LIB] Hello, world!
    
    #动态库测试
    gcc dynamic_test_helloworld.c /usr/lib/libhello.so -o dynamic_hello
    ./dynamic_hello
    # 输出: 
    dynamic lib  test
    [LIB] Hello, world!
    

结论

通过本文档的指导,用户可以在Yocto环境中顺利添加自定义应用程序和库,实现个性化的功能集成。