Adding Applications and Third-Party Libraries
Overview
This document guides users to add custom applications and third-party libraries to the Yocto build system (using helloworld as an example). Through the steps in this document, you can:
- Integrate custom code into Yocto projects
- Generate IPK installation packages
- Compile and use third-party library files
- Integrate components into system images
Prerequisites
Environment Requirements
- Necessary development toolkits installed
- Yocto project code cloned
- Familiar with basic C programming
- Understand Makefile and BitBake basics
Project Directory Structure
Create a custom meta layer, recommended directory structure:
meta-custom/
├── conf/
│ └── layer.conf # Layer configuration file
├── recipes-apps/ # Application recipe directory
│ └── helloworld/
│ ├── files/
│ │ ├── helloworld.c # Application source code
│ │ ├── Makefile # Build script
│ │ └── helloworld.service # systemd service file
│ └── helloworld_1.0.bb # BitBake recipe
└── recipes-libs/ # Library recipe directory
└── lib-helloworld/
├── files/
│ ├── lib_helloworld.c # Library source code
│ ├── lib_helloworld.h # Library header file
│ └── Makefile # Build script
└── lib-helloworld_1.0.bb # BitBake recipe
Adding Custom Applications
1. Create Layer Directory Structure
Create Directories
mkdir -p ${YOCTO_DIR}/layers/meta-custom/recipes-apps/helloworld/files
mkdir -p ${YOCTO_DIR}/layers/meta-custom/conf
Configure Custom Layer
Add the following to the layers/meta-custom/conf/layer.conf file:
BBPATH .= ":${LAYERDIR}"
BBFILES += "${LAYERDIR}/recipes-*/*/*.bb"
LAYERDEPENDS_meta-custom = "core"
LAYERSERIES_COMPAT_meta-custom = "kirkstone"
Register Layer to Build System
Edit layers/meta-qcom-distro/conf/bblayers.conf, add custom layer path:
BBLAYERS = " \
${WORKSPACE}/layers/meta-custom \
"
Add to Image Recipe
Edit layers/meta-quectel/recipes-products/images/qcom-multimedia-image.bbappend, add:
# Add application
IMAGE_INSTALL:append = " helloworld"
# Add library files (if needed)
IMAGE_INSTALL:append = " \
lib-helloworld \
lib-helloworld-dev \
lib-helloworld-staticdev \
"
2. Create Application Source Code
Write Main Program
Create helloworld.c in the meta-custom/recipes-apps/helloworld/files/ directory:
// helloworld.c
#include <stdio.h>
int main() {
printf("Hello, world!\n");
return 0;
}
Write Makefile
Create Makefile in the meta-custom/recipes-apps/helloworld/files/ directory:
# Use compilation flags provided by Yocto
all: helloworld
helloworld: helloworld.c
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
clean:
rm -f helloworld
.PHONY: all clean
Create Systemd Service File
Create helloworld.service in the meta-custom/recipes-apps/helloworld/files/ directory:
[Unit]
Description=Hello World Service
[Service]
Type=simple
ExecStart=/usr/bin/helloworld
[Install]
WantedBy=multi-user.target
3. Write BitBake Recipe
Create helloworld_1.0.bb in the meta-custom/recipes-apps/helloworld/ directory:
SUMMARY = "Hello World application"
DESCRIPTION = "A simple Hello World application."
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
# Source code file list
SRC_URI = "file://helloworld.c \
file://Makefile \
file://helloworld.service"
# Set working directory
S = "${WORKDIR}"
# Inherit systemd class
inherit systemd
# Define systemd service file name
SYSTEMD_SERVICE:${PN} = "helloworld.service"
# Configuration phase (skip)
do_configure() {
bbnote "skip do_configure"
}
# Compilation phase
do_compile() {
# Clean first
oe_runmake -f ${S}/Makefile clean
# Execute compilation
oe_runmake -f ${S}/Makefile
}
# Installation phase
do_install() {
# Create executable installation directory
install -d ${D}${bindir}
# Install executable
install -m 0755 ${S}/helloworld ${D}${bindir}
# Create systemd service directory
install -d ${D}${systemd_system_unitdir}
# Install service file
install -m 0644 ${S}/helloworld.service ${D}${systemd_system_unitdir}
}
4. Build and Install Application
Configure Build Environment
Enter the code working directory and execute:
source quectel_build/compile/build.sh
Method 1: Compile and Install IPK Package Separately
Step 1: Compile Application
bitbake helloworld
Step 2: Find Generated IPK Package
find ~/build-qcom-wayland/tmp-glibc/deploy -name "helloworld*.ipk"
Example output:
/home/quectel/build-qcom-wayland/tmp-glibc/deploy/ipk/armv8-2a/helloworld_1.0-r0_armv8-2a.ipk
Step 3: Push to Device
adb push helloworld_1.0-r0_armv8-2a.ipk /mnt
Step 4: Install IPK Package
Execute on the device:
# Mount filesystem as read-write mode
mount -o remount,rw /usr
# Install IPK package
opkg install /mnt/helloworld_1.0-r0_armv8-2a.ipk
Step 5: Verify Installation
/usr/bin/helloworld
Expected output:
Hello, world!
Method 2: Full System Image Build
Step 1: Configure Build Parameters
# Users can customize input parameters, select from prompted valid options
buildconfig QSM565DWF SG565DWFPARL1A01_BL01BP01K0M01_QDP_LP6.6.0XX.01.00X_V0X STD
Step 2: Compile Entire System
buildall
Step 3: Package Image
buildpackage
Step 4: Flash Image
The generated image is located at quectel_build/SG565DWFPARL1A01_BL01BP01K0M01_QDP_LP6.6.0XX.01.00X_V0X.
Refer to the following documents for flashing:
Step 5: Verify Installation
After flashing is complete, execute on the device:
/usr/bin/helloworld
Expected output:
Hello, world!
Adding Third-Party Libraries
1. Create Library Files
Create Directory
mkdir -p ${YOCTO_DIR}/layers/meta-custom/recipes-libs/lib-helloworld/files
Create Library Header File
Create lib_helloworld.h in the meta-custom/recipes-libs/lib-helloworld/files/ directory:
// lib_helloworld.h
#ifndef LIB_HELLO_H
#define LIB_HELLO_H
void hello_print(const char* name);
#endif
Create Library Source Code
Create lib_helloworld.c in the meta-custom/recipes-libs/lib-helloworld/files/ directory:
// lib_helloworld.c
#include <stdio.h>
#include "lib_helloworld.h"
void hello_print(const char* name) {
printf("[LIB] Hello, %s!\n", name);
}
Write Makefile
Create Makefile in the meta-custom/recipes-libs/lib-helloworld/files/ directory:
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* lib_helloworld.o libhello.a
2. Write BitBake Recipe
Create lib-helloworld_1.0.bb in the meta-custom/recipes-libs/lib-helloworld/ directory:
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://lib_helloworld.h \
file://Makefile"
S = "${WORKDIR}"
EXTRA_OEMAKE = "'CC=${CC}' 'CFLAGS=${CFLAGS} -fPIC' 'LDFLAGS=${LDFLAGS}'"
do_install() {
# Create target directories
install -d ${D}${libdir}
install -d ${D}${includedir}
# Install shared library and symbolic links
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
# Install static library
install -m 0644 ${S}/libhello.a ${D}${libdir}/
# Install header file
install -m 0644 ${S}/lib_helloworld.h ${D}${includedir}/
}
# Package file allocation
FILES:${PN} = " \
${libdir}/libhello.so.1 \
${libdir}/libhello.so.${PV} \
"
FILES:${PN}-dev = " \
${libdir}/libhello.so \
${includedir}/lib_helloworld.h \
"
FILES:${PN}-staticdev = " \
${libdir}/libhello.a \
"
3. Build and Use Third-Party Libraries
Configure Build Environment
source quectel_build/compile/build.sh
Method 1: Compile and Install Separately
Step 1: Compile Library
bitbake lib-helloworld
Step 2: Find Generated Library Files
find ./* -name "libhello*"
Step 3: Push to Device
adb push libhello.so libhello.so.1 libhello.so.1.0 libhello.a /usr/lib
Step 4: Fix Permissions and Symbolic Links
Execute on the device:
# Set execute permissions
chmod 755 /usr/lib/libhello.so*
chmod 644 /usr/lib/libhello.a
# Rebuild symbolic links
cd /usr/lib
ln -sf libhello.so.1.0 libhello.so.1
ln -sf libhello.so.1 libhello.so
Step 5: Write Test Program
Create static library test program static_test_helloworld.c:
#include <stdio.h>
void hello_print(const char*);
int main() {
printf("static lib test\n");
hello_print("world");
return 0;
}
Create dynamic library test program dynamic_test_helloworld.c:
#include <stdio.h>
void hello_print(const char*);
int main() {
printf("dynamic lib test\n");
hello_print("world");
return 0;
}
Step 6: Compile and Run Test Program
Static library test:
gcc static_test_helloworld.c -lhello -static -o static_hello
./static_hello
Expected output:
static lib test
[LIB] Hello, world!
Dynamic library test:
gcc dynamic_test_helloworld.c /usr/lib/libhello.so -o dynamic_hello
./dynamic_hello
Expected output:
dynamic lib test
[LIB] Hello, world!
Method 2: Full System Image Build
Compile and Flash
Refer to the steps in the "Method 2: Full System Image Build" section of the "Adding Custom Applications" chapter for compilation and flashing.
Verify Library Files
After flashing is complete, check library files on the device:
ls -l /usr/lib/libhello*
Expected output:
-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
Run Test Program
Static library test:
gcc static_test_helloworld.c -lhello -static -o static_hello
./static_hello
Expected output:
static lib test
[LIB] Hello, world!
Dynamic library test:
gcc dynamic_test_helloworld.c /usr/lib/libhello.so -o dynamic_hello
./dynamic_hello
Expected output:
dynamic lib test
[LIB] Hello, world!
Notes
- Layer Priority: Ensure custom layer configuration is correct to avoid conflicts with other layers
- License Declaration: Must correctly set LICENSE and LIC_FILES_CHKSUM
- File Permissions: Pay attention to executable and library file permission settings
- Symbolic Links: Dynamic library symbolic links must be correctly set
- Dependencies: If the library depends on other packages, declare DEPENDS in the recipe
- Version Management: It is recommended to use version numbers to manage library files
Common Issues
Q1: BitBake Compilation Failed?
Check Items:
- Is the recipe syntax correct
- Are source file paths correct
- Does the LICENSE file exist
Q2: IPK Installation Failed?
Solution:
- Ensure filesystem is mounted as read-write mode
- Check if disk space is sufficient
- View opkg error logs
Q3: Dynamic Library Not Found?
Solution:
- Check LD_LIBRARY_PATH environment variable
- Confirm symbolic links are correct
- Run
ldconfigto update library cache
Related Documents
- Development Environment Setup
- Image Build
- Image Flashing
- Cross Compilation Toolchain
- Kernel Compilation and Update
Summary
Through the guidance in this document, you can in the Yocto environment:
- Create custom applications and libraries
- Generate IPK installation packages for separate deployment
- Integrate components into system images
- Verify and test custom components
After mastering these skills, you can expand and customize system functionality according to actual needs.