【源码解析】ubus(1)编译
本文最后更新于 28 天前,其中的信息可能已经有所发展或是发生改变。

编译环境

编译器默认使用gcc
cmake version>=3.13

依赖关系

ubus编译依赖json-clibubox

libubox依赖json-c

源码下载路径

git clone https://github.com/json-c/json-c.git
git clone https://github.com/openwrt/libubox
git clone https://github.com/openwrt/ubus

编译方法

下载json-c、libubox、ubus源代码,解压重并命名文件夹(不要修改源码),保证文件目录结构如下。同时保证cmake文件具有可执行权限

复制粘贴运行本文档中的编译脚本,脚本运行参数all

.
├── build.sh
├── json-c
├── libubox
└── ubus

编译脚本

笔者测试用软件版本
json-c版本:json-c-0.17-20230812
libubox版本:2024-5-17 eb9bcb64185ac155c02cc1a604692c4b00368324
ubus版本:2023-12-18 65bb027054def3b94a977229fd6ad62ddd32345b

编译产物

  • 编译完成后会创建一个products_and_depends名称的文件夹,用于存放编译产物ubusubusd和后续可能使用依赖库和头文件
  • ubus源码目录下的examples也会一起被编译,这个是一个官方demo
#!/bin/bash

base_path=$(pwd)

jsonC_path=$base_path/json-c
jsonC_build_path=$base_path/jsonC_build

libubox_path=$base_path/libubox
libubox_build_path=$base_path/libubox_build

ubus_path=$base_path/ubus
ubus_build_path=$base_path/ubus_build
ubus_examples_build_path=$ubus_path/examples/build

depend_path=$base_path/products_and_depends
depend_libs_path=$depend_path/lib
depend_inc_path=$depend_path/include

# json-c库编译
jsonC_build() {
    echo "Start compiling jsonc"

    mkdir $jsonC_build_path
    cd $jsonC_build_path

    $jsonC_path/cmake-configure --prefix=./ --enable-shared

    make &&

    # 拷贝编译产物
    if [ ! -d "$depend_libs_path" ]; then
        mkdir -p $depend_libs_path
    fi

    cp $jsonC_build_path/libjson-c* $depend_libs_path
}

# libubox库编译
libubox_build() {
    echo "Start compiling libubox"

    mkdir $libubox_build_path
    cd $libubox_build_path

    # 拷贝依赖文件
    if [ ! -d "$depend_inc_path/json" ]; then
        mkdir -p $depend_inc_path/json
    fi

    cp $jsonC_build_path/json.h $depend_inc_path/json &&
    cp $jsonC_build_path/*.h $depend_inc_path &&
    cp $jsonC_path/*.h $depend_inc_path &&

    cmake -Djson=$depend_libs_path/libjson-c.so -DCMAKE_C_FLAGS="-I $depend_inc_path"\
        -DBUILD_LUA:BOOL=OFF -DBUILD_EXAMPLES:BOLL=OFF -DBUILD_STATIC=ON $libubox_path -DCMAKE_BUILD_TYPE=Debug

    make &&

    # 拷贝编译产物
    if [ ! -d "$depend_libs_path" ]; then
        mkdir -p $depend_libs_path
    fi

    cp $libubox_build_path/libblobmsg_json* $depend_libs_path &&
    cp $libubox_build_path/libjson_script* $depend_libs_path &&
    cp $libubox_build_path/libubox* $depend_libs_path
}

# ubus库编译
ubus_build() {
    echo "Start compiling ubus"

    mkdir $ubus_build_path
    cd $ubus_build_path

    # 拷贝依赖文件
    if [ ! -d "$depend_inc_path/libubox" ]; then
        mkdir -p $depend_inc_path/libubox
    fi
    cp $libubox_path/*.h $depend_inc_path/libubox &&

    cmake -Djson=$depend_libs_path/libjson-c.so -Dubox_library=$depend_libs_path/libubox.so \
        -Dblob_library=$depend_libs_path/libblobmsg_json.so -Dubox_include_dir:PATH=$depend_inc_path -DBUILD_LUA=OFF\
        -DBUILD_STATIC=ON $ubus_path -DCMAKE_BUILD_TYPE=Debug

    make &&

    # 拷贝编译产物
    if [ ! -d "$depend_libs_path" ]; then
        mkdir -p $depend_libs_path
    fi

    cp $ubus_path/*.h $depend_inc_path &&
    cp $ubus_build_path/ubus $depend_path &&
    cp $ubus_build_path/ubusd $depend_path &&
    cp $ubus_build_path/libubus.* $depend_libs_path &&
    cp $ubus_build_path/libubusd_library.* $depend_libs_path

    ubus_examples_build
}

# ubus官方demo编译
ubus_examples_build() {
    if [ ! -d "$ubus_examples_build_path" ]; then
        mkdir -p $ubus_examples_build_path
    fi

    cd $ubus_examples_build_path
    cmake .. -DBUILD_EXAMPLES=ON -DCMAKE_PREFIX_PATH=$depend_path -Dubox_library=ubox -DCMAKE_BUILD_TYPE=Debug
    make
}

clean() {
    echo "Clean up old files"
    rm -rf $jsonC_build_path &&
    rm -rf $libubox_build_path &&
    rm -rf $ubus_build_path &&
    rm -rf $depend_path &&
    rm -rf $ubus_examples_build_path
}

build_all() {
    jsonC_build
    libubox_build
    ubus_build
}

# 检查传递的参数并调用相应的函数
case "$1" in
    jsonC)
        jsonC_build
        ;;
    libubox)
        libubox_build
        ;;
    ubus)
        ubus_build
        ;;
    all)
        build_all
        ;;
    clean)
        clean
        ;;
    *)
        echo "Usage: $0 [jsonC|libubox|ubus|all|clean]"
        exit 1
        ;;
esac

在Ubuntu上运行ubus

在Ubuntu上安装相关库

在完成上文中的编译步骤后,依次进入jsonC_buildlibubox_buildubus_build文件夹执行sudo make install命令在Ubuntu上安装json-clibuboxubus

笔者注:此处建议使用包管理工具先对编译成生产的二进制进行打包,然后再安装。这样可以使用包管理器进行管理

在终端手动执行ubus

创建三个终端

  • 终端1:
  su root

  ubusd    #ubusd进程
  • 终端2:
  su root

  ubus listen test    #监听ubus
  • 终端3:
  su root

  ubus send test '{"hi!":"hello!"}'    #发送ubus

如上述操作失败,可尝试将json-clibuboxubus的动态库库路径添加至系统动态库搜索路径

  • 临时设置动态库加载路径 #设置临时动态库加载路径 export LD_LIBRARY_PATH=/path/to/lib:$LD_LIBRARY_PATH
  • 长期设置动态库加载路径
    1. 切换root执行 :su root
    2. 将动态库路径添加至系统动态库搜索路径:echo [依赖库路径] >> /etc/ld.so.conf
    3. 更新动态库搜索路径:ldconfig

运行官方demo

ubus源码中存在一个examples文件夹存,里面是一个官方demo,上文中的编译脚本也会编译这个demo

运行方式

创建三个终端

终端1

su root

./ubusd                     #执行在编译产物(products_and_depends文件夹)中的ubusd

终端2

su root

./server                   #启动ubus/examples文件夹中的server端

clinet端也成功执行后server侧的终端会出现如下打印

Watching object dd66ce76: Success
Object dd66ce76 went away

终端3:

su root

./client                  #启动ubus/examples文件夹中的client端

在启动clinet端后终端会出现如下打印,并不断新增直到client端进程结束

Avg time per iteration: 111 usec
Subscribers active: 1
Got fd from the server, watching...
completed request, ret: 0
Avg time per iteration: 111 usec
Got line: msg1: test received a message: blah
Sending count up to '100100'; string has length '592926'
Server validated our count up to '100100'
Got line: msg2: test received a message: blah
Avg time per iteration: 116 usec
Got line: msg3: test received a message: blah
Avg time per iteration: 121 usec
Got line: msg4: test received a message: blah
Sending count up to '100200'; string has length '593629'
Server validated our count up to '100200'

如果运行时提示找不到依赖库则需手动配置环境依赖(设置 LD_LIBRARY_PATH

例如 libubox.so 位于 /usr/local/lib 目录下,执行以下命令;

PS:如果使用上文中的编译脚本执行ubus编译则libubox.so会在编译时存放在products_and_depends/lib文件中

export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
上一篇
下一篇