需求:用bitbake去编译openocd需要openbmc环境,构建起来很不方便,需要把openocd的编译过程从openbmc中分离出来,单独编译其依赖库和标准库,bmc环境中有相关库的so文件,因此我们只关心编译出的openocd二进制可执行文件

目标架构

用bitbake对openocd进行编译,获得openocd_git.bb文件,阅读bb文件

SUMMARY = "Free and Open On-Chip Debugging, In-System Programming and Boundary-Scan Testing"
LICENSE = "GPL-2.0-only"
LIC_FILES_CHKSUM = "file://COPYING;md5=b234ee4d69f5fce4486a80fdaf4a4263"
DEPENDS = "libusb-compat libftdi"
RDEPENDS:${PN} = "libusb1"

依赖库为libusb-compat和libftdi,运行时依赖为libusb1

再阅读bitbake编译过程中生成的do_compile log文件,得到在openbmc中bitbake编译openocd时使用的目标架构配置

arm-openbmc-linux-gnueabi-gcc -march=armv7-a -mfpu=vfpv4-d16 -mfloat-abi=hard -fstack-protector-strong -O2 -D_FORTIFY_SOURCE=2 -Wformat -Wformat-security -Werror=format-security

目标架构指定 ARMv7-A 架构,确保生成的代码针对 ARMv7-A 指令集优化(-march=armv7-a)

浮点单元指定使用 VFPv4-D16 浮点单元,支持 16 个双精度寄存器(-mfpu=vfpv4-d16)

浮点ABI使用硬浮点 ABI,直接调用浮点硬件,生成的代码与硬浮点库(如 libc.so)兼容(-mfloat-abi=hard)

启用优化级别 2,平衡性能和编译时间,生成高效代码。

后面的配置是一些安全和调试的选项,具体作用如下:

-fstack-protector-strong

  • 作用:启用栈溢出保护(buffer overflow protection),在函数中插入代码检查栈溢出,增强程序安全性。
  • 影响:增加少量代码大小和运行时开销(通常微小),提高对栈溢出攻击的防御能力。
  • 适用性:常见于嵌入式系统(如 OpenBMC),因为 BMC 固件可能面临安全威胁。

-D_FORTIFY_SOURCE=2

  • 作用:启用源代码级别的缓冲区溢出保护,增强标准库函数(如 strcpy, memcpy)的安全检查。
  • 影响:可能略微增加运行时检查开销,但显著提高安全性,防止常见漏洞。
  • 适用性:Yocto/OpenBMC 默认启用,适合生产环境。

-Wformat -Wformat-security

  • 作用:
    • -Wformat:启用格式字符串警告,检查 printf 等函数的格式字符串是否安全。
    • -Wformat-security:进一步检查格式字符串漏洞(如用户控制的格式字符串)。
  • 影响:仅影响编译时,生成警告但不改变代码行为。
  • 适用性:增强编译时安全检查,适合严格的开发环境。

-Werror=format-security

  • 作用:将格式字符串安全警告升级为错误,强制修复潜在问题。
  • 影响:如果代码有格式字符串问题,编译会失败,迫使开发者修复。
  • 适用性:适合高质量代码要求(如 OpenBMC)。

从配置来看,-march=armv7-a -mfpu=vfpv4-d16 -mfloat-abi=hard -02,这四个配置足以确保两者的核心架构和优化一致,生成的 OpenOCD 可执行文件在功能上基本相同(支持相同的硬件接口和调试功能)。

bitbake使用yocto配方构建的工具链(arm-openbmc-linux-gnueabi-gcc),由bb文件(gcc_12.2.bb,glibc_2.34.bb)从源码编译而成,sysroot 动态生成,包含所有依赖(如 libusb, libconfuse)。

Linaro工具链交叉编译

我们要将openocd的编译过程分离出来,不能使用bitbake,手动实现交叉编译工具链过于复杂,且维护更新成本较高,因此使用linaro工具链,其中gcc, binutils, glibc等工具已经在目标架构上进行了预编译,解压工具链即可使用,因此实现过程只需要关注openocd依赖库以及本体软件的编译实现。

首先需要下载对应依赖库的tar压缩包并且分别解压到libusb,libcheck,libconfuse,libftdi,libusb-compat-0.1.5文件夹中,对应版本压缩包的下载链接已经贴到博客最后,用cp或者scp传到本地开发环境或者研发服务器中,可进行以下开发。

#!/bin/bash
# build_openocd.sh
# Cross-compile OpenOCD for armv7ahf-vfpv4d16-openbmc-linux-gnueabi on Ubuntu 22.04
  
set -e
  
# 配置
# CUSTOM_DIR="/home/lip"  # 自定义文件夹路径,替换为实际路径
# 获取 CUSTOM_DIR
if [ -z "$1" ]; then
    echo "请输入 CUSTOM_DIR 的路径"
    read -r CUSTOM_DIR
    if [ -z "$CUSTOM_DIR" ]; then
        echo "错误:未提供 CUSTOM_DIR 路径"
        exit 1
    fi
else
    CUSTOM_DIR="$1"
fi
 
# 验证 CUSTOM_DIR 是否有效
if [ ! -d "$CUSTOM_DIR" ]; then
    echo "错误:目录 $CUSTOM_DIR 不存在,请确保路径正确"
    exit 1
fi
 
DEPS_DIR="$CUSTOM_DIR/.openocd_deps"
TOOLCHAIN_DIR="$CUSTOM_DIR/arm-toolchain"
TARGET="arm-linux-gnueabihf"
TOOLCHAIN_URL="https://snapshots.linaro.org/gnu-toolchain/12.2-2022.09-1/arm-linux-gnueabihf/gcc-linaro-12.2.1-2022.09-x86_64_arm-linux-gnueabihf.tar.xz"
TOOLCHAIN_TARBALL="gcc-linaro-12.2.1-2022.09-x86_64_arm-linux-gnueabihf.tar.xz"
 
echo "验证主机依赖..."
for pkg in autoconf automake libtool pkgconf git make gcc g++ curl texinfo; do
    if ! command -v $pkg >/dev/null 2>&1; then
        echo "Error: $pkg is not installed."
        echo "Installing $pkg..."
        sudo apt-get update
        sudo apt-get install -y $pkg
        if [ "$pkg" = "libtool" ]; then
            echo "Additionally installing libtool-bin..."
            sudo apt-get install -y libtool-bin
        fi
        if ! command -v $pkg >/dev/null 2>&1; then
            echo "Error: Failed to install $pkg."
            exit 1
        fi
    fi
    echo "$pkg found at $(command -v $pkg)"
done
echo "All host dependencies are installed."
  
# 下载并安装Linaro工具链
echo "Linaro toolchain..."
if [ ! -f "$TOOLCHAIN_DIR/bin/$TARGET-gcc" ]; then
    echo "Downloading toolchain..."
    curl -L -o "$CUSTOM_DIR/$TOOLCHAIN_TARBALL" "$TOOLCHAIN_URL"
    mkdir -p "$TOOLCHAIN_DIR"
    tar -xvf "$CUSTOM_DIR/$TOOLCHAIN_TARBALL" -C "$TOOLCHAIN_DIR" --strip-components=1
    rm "$CUSTOM_DIR/$TOOLCHAIN_TARBALL"
fi
if [ ! -f "$TOOLCHAIN_DIR/bin/$TARGET-gcc" ]; then
    echo "Error: $TARGET-gcc not found in $TOOLCHAIN_DIR/bin"
    exit 1
fi
export PATH="$TOOLCHAIN_DIR/bin:$PATH"
export CC="$TARGET-gcc"
export CXX="$TARGET-g++"
export LD="$TARGET-ld"
export AR="$TARGET-ar"
export AS="$TARGET-as"
export RANLIB="$TARGET-ranlib"
export CFLAGS="-march=armv7-a -mfpu=vfpv4-d16 -mfloat-abi=hard -O2 -pipe -fstack-protector-strong -D_FORTIFY_SOURCE=2 -Wformat -Wformat-security -Werror=format-security"
export LDFLAGS="-L$DEPS_DIR/usr/lib -L$TOOLCHAIN_DIR/arm-linux-gnueabihf/libc/lib"
export DEPS_DIR=$CUSTOM_DIR/.openocd_deps_test
export TOOLCHAIN_DIR=$CUSTOM_DIR/arm-toolchain
$CC --version || { echo "Error: Failed to run $CC"; exit 1; }
echo "Toolchain: $($CC --version)"
  
echo "Creating directories..."
mkdir -p "$DEPS_DIR/usr/lib" "$DEPS_DIR/usr/include" "$DEPS_DIR/usr/lib/pkgconfig" "$CUSTOM_DIR/openocd-install"
  
# 编译依赖
echo "正在编译依赖..."
  
# libusb-v1.0.25
if [ ! -d "$CUSTOM_DIR/libusb1" ]; then
    echo "解压 libusb-1.0.25..."
    mkdir -p "$CUSTOM_DIR/libusb1"
    tar -xjf "$CUSTOM_DIR/libusb-1.0.25.tar.bz2" -C "$CUSTOM_DIR/libusb1" --strip-components=1
fi
 
if [ ! -f "$DEPS_DIR/usr/lib/libusb-1.0.so" ]; then
    echo "Building libusb-1.0..."
    cd "$CUSTOM_DIR"
    cd libusb1
    make clean >/dev/null 2>&1 || true
    export PKG_CONFIG_PATH="$DEPS_DIR/usr/lib/pkgconfig"
    export ac_cv_func_malloc_0_nonnull=yes
    export ac_cv_func_realloc_0_nonnull=yes
    # ./autogen.sh --host="$TARGET" --prefix="$DEPS_DIR/usr" --disable-udev
    ./configure --host="$TARGET" --prefix="$DEPS_DIR/usr" \
        --with-sysroot="$TOOLCHAIN_DIR/arm-linux-gnueabihf/libc" \
        CFLAGS="$CFLAGS -I$TOOLCHAIN_DIR/arm-linux-gnueabihf/libc/usr/include" \
        LDFLAGS="$LDFLAGS" \
        --disable-examples-build --disable-tests-build --disable-udev
    make
    make install
fi
echo "libusb-1.0 found at $DEPS_DIR/usr/lib/libusb-1.0.so"
  
# libcheck-v0.15.2
if [ ! -d "$CUSTOM_DIR/libcheck1" ]; then
    echo "解压 libcheck-0.15.2..."
    mkdir -p "$CUSTOM_DIR/libcheck1"
    tar -xzf "$CUSTOM_DIR/check-0.15.2.tar.gz" -C "$CUSTOM_DIR/libcheck1" --strip-components=1
fi
if [ ! -f "$DEPS_DIR/usr/lib/libcheck.so" ]; then
    cd "$CUSTOM_DIR"
    cd libcheck1
    make clean >/dev/null 2>&1 || true
  
    # 运行 autoreconf 以重新生成构建系统
    autoreconf -i
    export PKG_CONFIG_PATH="$DEPS_DIR/usr/lib/pkgconfig"
    ./configure --host=arm-linux-gnueabihf --prefix="$DEPS_DIR/usr" \
        --with-sysroot="$TOOLCHAIN_DIR/arm-linux-gnueabihf/libc" \
        CFLAGS="$CFLAGS -I$DEPS_DIR/usr/include -I$TOOLCHAIN_DIR/arm-linux-gnueabihf/libc/usr/include" \
        LDFLAGS="$LDFLAGS -L$TOOLCHAIN_DIR/arm-linux-gnueabihf/libc/lib"
    make
    make install
fi
echo "libcheck found at $DEPS_DIR/usr/lib/libcheck.so"
  
# libconfuse-v3.3
if [ ! -d "$CUSTOM_DIR/libconfuse" ]; then
    echo "解压 libconfuse-3.3..."
    mkdir -p "$CUSTOM_DIR/libconfuse"
    tar -xzf "$CUSTOM_DIR/confuse-3.3.tar.gz" -C "$CUSTOM_DIR/libconfuse" --strip-components=1
fi
 
if [ ! -f "$DEPS_DIR/usr/lib/libconfuse.so" ]; then
    echo "Building libconfuse..."
    cd "$CUSTOM_DIR"
    cd libconfuse
    make clean >/dev/null 2>&1 || true
  
    export PKG_CONFIG_PATH="$DEPS_DIR/usr/lib/pkgconfig"
    export ac_cv_func_malloc_0_nonnull=yes
    export ac_cv_func_realloc_0_nonnull=yes
    ./configure --host="$TARGET" --prefix="$DEPS_DIR/usr" \
        --enable-shared --disable-static \
        CFLAGS="$CFLAGS -I$DEPS_DIR/usr/include -I$TOOLCHAIN_DIR/arm-linux-gnueabihf/libc/usr/include" \
        LDFLAGS="$LDFLAGS -L$DEPS_DIR/usr/lib -L$TOOLCHAIN_DIR/arm-linux-gnueabihf/libc/lib"
    make
    make install
fi
echo "libconfuse found at $DEPS_DIR/usr/lib/libconfuse.so"
  
# libftdi-v1.5
if [ ! -d "$CUSTOM_DIR/libftdi" ]; then
    echo "解压 libftdi-1.5..."
    mkdir -p "$CUSTOM_DIR/libftdi"
    tar -xjf "$CUSTOM_DIR/libftdi1-1.5.tar.bz2" -C "$CUSTOM_DIR/libftdi" --strip-components=1
fi
if [ ! -f "$DEPS_DIR/usr/lib/libftdi1.so" ]; then
    echo "Processing libftdi-1.5..."
    cd "$CUSTOM_DIR"
    rm -rf libftdi-build  # 清理旧的构建目录
    mkdir -p libftdi-build
    cd libftdi-build
  
    export PKG_CONFIG_PATH="$DEPS_DIR/usr/lib/pkgconfig:$PKG_CONFIG_PATH"
    # 验证依赖文件是否存在
    ls -l $DEPS_DIR/usr/lib/libusb-1.0.so || { echo "Error: libusb-1.0.so not found"; exit 1; }
    ls -l $DEPS_DIR/usr/lib/libconfuse.so || { echo "Error: libconfuse.so not found"; exit 1; }
  
    echo "运行 CMake 配置..."
    cmake \
        -DCMAKE_TOOLCHAIN_FILE="$CUSTOM_DIR/toolchain-arm-linux-gnueabihf.cmake" \
        -DCMAKE_INSTALL_PREFIX=$DEPS_DIR/usr \
        -DBUILD_SHARED_LIBS=ON \
        -DLIBUSB_LIBRARIES=$DEPS_DIR/usr/lib/libusb-1.0.so \
        -DLIBUSB_INCLUDE_DIR=$DEPS_DIR/usr/include/libusb-1.0 \
        -DCONFUSE_LIBRARIES=$DEPS_DIR/usr/lib/libconfuse.so \
        -DCONFUSE_INCLUDE_DIR=$DEPS_DIR/usr/include \
        "$CUSTOM_DIR/libftdi"
    if [ $? -ne 0 ]; then
        echo "CMake 配置失败,请检查 cmake.log"
        cmake \
            -DCMAKE_TOOLCHAIN_FILE="$CUSTOM_DIR/toolchain-arm-linux-gnueabihf.cmake" \
            -DCMAKE_INSTALL_PREFIX=$DEPS_DIR/usr \
            -DBUILD_SHARED_LIBS=ON \
            -DLIBUSB_LIBRARIES=$DEPS_DIR/usr/lib/libusb-1.0.so \
            -DLIBUSB_INCLUDE_DIR=$DEPS_DIR/usr/include/libusb-1.0 \
            -DCONFUSE_LIBRARIES=$DEPS_DIR/usr/lib/libconfuse.so \
            -DCONFUSE_INCLUDE_DIR=$DEPS_DIR/usr/include \
            "$CUSTOM_DIR/libftdi" > cmake.log 2>&1
        exit 1
    fi
  
    make
    make install
fi
echo "libftdi-1.5 found at $DEPS_DIR/usr/lib/libftdi1.so"
  
# libusb-compat-v0.1.5
if [ ! -d "$CUSTOM_DIR/libusb-compat" ]; then
    echo "解压 libusb-compat-0.1.5..."
    mkdir -p "$CUSTOM_DIR/libusb-compat"
    tar -xjf "$CUSTOM_DIR/libusb-compat-0.1.5.tar.bz2" -C "$CUSTOM_DIR/libusb-compat" --strip-components=1
fi
 
if [ ! -f "$DEPS_DIR/usr/lib/libusb.so" ]; then
    echo "Building libusb-compat-0.1.5..."
    cd "$CUSTOM_DIR"
    cd libusb-compat
    make clean >/dev/null 2>&1 || true
    export PKG_CONFIG_PATH="$DEPS_DIR/usr/lib/pkgconfig:$PKG_CONFIG_PATH"
    ./configure --host="$TARGET" --prefix="$DEPS_DIR/usr" \
        --enable-shared --disable-static \
        CFLAGS="$CFLAGS -I$DEPS_DIR/usr/include -I$TOOLCHAIN_DIR/arm-linux-gnueabihf/libc/usr/include" \
        LDFLAGS="$LDFLAGS -L$DEPS_DIR/usr/lib -L$TOOLCHAIN_DIR/arm-linux-gnueabihf/libc/lib"
    make
    make install
fi
echo "libusb-compat-0.1.5 found at $DEPS_DIR/usr/lib/libusb.so"
  
# openocd
if [ ! -f "$CUSTOM_DIR/ybopenocd-install/bin/openocd" ]; then
    echo "Building OpenOCD..."
    cd "$CUSTOM_DIR/openocd"
    make clean >/dev/null 2>&1 || true
    export PKG_CONFIG_PATH="$DEPS_DIR/usr/lib/pkgconfig:$PKG_CONFIG_PATH"
    ./bootstrap
    ./configure --host="$TARGET" --prefix="$CUSTOM_DIR/openocd-install" \
        --with-sysroot="$TOOLCHAIN_DIR/arm-linux-gnueabihf/libc" \
        CFLAGS="$CFLAGS -I$DEPS_DIR/usr/include -I$TOOLCHAIN_DIR/arm-linux-gnueabihf/libc/usr/include" \
        LDFLAGS="$LDFLAGS -L$DEPS_DIR/usr/lib -L$TOOLCHAIN_DIR/arm-linux-gnueabihf/libc/lib" \
        --enable-ftdi
    make
    make install
fi
echo "OpenOCD found at $CUSTOM_DIR/openocd-install/bin/openocd"

在编译libftdi时,cmake工具链文件如下:

set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)
 
# 指定交叉编译工具链
set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)
set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++)
 
# 指定 sysroot(工具链的根文件系统)
set(CMAKE_SYSROOT $ENV{TOOLCHAIN_DIR}/arm-linux-gnueabihf/libc)
 
# 指定依赖库和头文件的查找路径
set(CMAKE_PREFIX_PATH $ENV{DEPS_DIR}/usr)
set(CMAKE_FIND_ROOT_PATH $ENV{DEPS_DIR}/usr $ENV{TOOLCHAIN_DIR}/arm-linux-gnueabihf/libc)
 
# 确保 CMake 只查找目标系统的库和头文件
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
 
# 设置 CFLAGS 和 LDFLAGS
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I$ENV{DEPS_DIR}/usr/include -I$ENV{TOOLCHAIN_DIR}/arm-linux-gnueabihf/libc/usr/include" CACHE STRING "C flags")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -I$ENV{DEPS_DIR}/usr/include -I$ENV{TOOLCHAIN_DIR}/arm-linux-gnueabihf/libc/usr/include" CACHE STRING "C++ flags")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L$ENV{DEPS_DIR}/usr/lib -L$ENV{TOOLCHAIN_DIR}/arm-linux-gnueabihf/libc/lib" CACHE STRING "Linker flags")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -L$ENV{DEPS_DIR}/usr/lib -L$ENV{TOOLCHAIN_DIR}/arm-linux-gnueabihf/libc/lib" CACHE STRING "Shared linker flags")
 
# 显式声明libconfuse的库和头文件
set(CONFUSE_LIBRARY /home/lip/.openocd_deps/usr/lib/libconfuse.so CACHE PATH "Path to libconfuse")
set(CONFUSE_INCLUDE_DIR /home/lip/.openocd_deps/usr/include CACHE PATH "Path to confuse include directory")

保存在~/toolchain-arm-linux-gnueabihf.cmake中

执行该脚本,编译好的依赖库文件保存在~/.openocd_deps下,openocd可执行文件保存在~/ybopenocd-install/bin中,把该可执行文件复制到bmc中/tmp路径下,相关板卡cfg文件需要被上传到相同路径下,即可在bmc环境下运行调试openocd

版本管理以及下载链接:

Linaro工具链-v12.2.1:

https://snapshots.linaro.org/gnu-toolchain/12.2-2022.09-1/arm-linux-gnueabihf/gcc-linaro-12.2.1-2022.09-x86_64_arm-linux-gnueabihf.tar.xz

libusb-v1.0.25:

https://github.com/libusb/libusb/releases/download/v1.0.25/libusb-1.0.25.tar.bz2

libcheck-v0.15.2:

https://github.com/libcheck/check/releases/download/0.15.2/check-0.15.2.tar.gz

libconfuse-v3.3:

https://github.com/libconfuse/libconfuse/releases/download/v3.3/confuse-3.3.tar.gz

libftdi-v1.5:

https://www.intra2net.com/en/developer/libftdi/download/libftdi1-1.5.tar.bz2

libusb-compat-v0.1.5

https://sourceforge.net/projects/libusb/files/libusb-compat-0.1/libusb-compat-0.1.5/libusb-compat-0.1.5.tar.bz2

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐