• 正文
  • 相关推荐
申请入驻 产业图谱

一个面向嵌入式Linux C++的应用开发框架!

10/30 13:19
668
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

一、项目简介

AppKit是一个专注于嵌入式Linux应用开发的C++14框架,它的核心目标是提升开发效率和应用健壮性。AppKit提供了一套经过验证的工具集,覆盖了线程管理、定时器、文件IO、串口通信、网络通信、CAN总线GPIO控制等嵌入式开发中的高频需求。

https://gitee.com/newgolo/appkit

双环境支持: 同时支持ROS和非ROS环境编译,既能用于机器人项目,也能用于传统嵌入式应用

跨平台构建: 内置zbuild编译系统,支持x86_64和aarch64平台的本地编译与交叉编译

工程化实践

集成了fmt、spdlog、json、yaml-cpp等成熟的第三方库,避免重复造轮子

二、整体架构

2.1 顶层架构

AppKit的设计哲学是"分层解耦,按需组合"。整个项目分为三个核心层次:

解耦合:核心库不依赖第三方库的具体实现,通过接口隔离

可扩展:新增功能模块只需遵循统一的构建规范,无需修改框架核心

2.2 目录结构解析

项目采用了标准化的ROS工作空间布局,即使在非ROS环境下也保持了这种结构:

appkit/
├── environ/              # 环境配置中枢
│   ├── cmake/           # CMake工具集
│   │   ├── zbuild.cmake      # zbuild函数定义
│   │   ├── finder.cmake      # 依赖查找
│   │   └── common.cmake      # 通用配置
│   ├── config/          # 平台配置文件
│   │   ├── linux-amd64.sh    # x64配置
│   │   └── linux-arm64.sh    # ARM64配置
│   ├── zbuild/          # zbuild工具脚本
│   └── envsetup.sh      # 环境初始化脚本
├── src/
│   ├── appkit/          # 核心库源码
│   │   ├── inc/         # 公共头文件
│   │   └── src/         # 实现代码
│   ├── third_party/     # 第三方依赖
│   ├── demos/           # 示例程序
│   └── include/         # 全局公共头文件
├── prebuilt/            # 预编译库存放
│   ├── linux-amd64/
│   └── linux-arm64/
├── zbuild/              # 非ROS编译入口
└── ws_output/           # ROS编译输出

关键设计点

environ目录:这是整个构建系统的大脑。envsetup.sh通过source的方式注入环境变量,让用户在shell中就能调用zbuild_setup等函数。这种设计比传统的Makefile更灵活,可以根据平台动态配置。

setup.cmake:每个package的CMakeLists.txt都会include这个文件。它统一管理了编译选项、依赖路径、宏定义等,避免了各模块的配置不一致。

prebuilt机制:交叉编译时,先将库安装到prebuilt目录,其他模块再从这里链接。这避免了交叉编译环境下的路径混乱问题。

2.3 构建系统设计

AppKit支持三种编译模式:

zbuild的核心机制

通过环境变量ZBUILD_ENABLE来区分编译模式。当ZBUILD_ENABLE=1时,所有package的CMakeLists.txt都会走非ROS的编译分支:

这种设计的精妙之处在于:同一份CMakeLists.txt,通过环境变量控制就能适配两种完全不同的构建系统。避免了维护两套构建脚本的麻烦。

三、部分代码

3.1 线程封装:Runnable模式

AppKit的线程设计采用了经典的Runnable模式:

使用示例

设计优势:线程逻辑与线程对象分离,符合单一职责原则run()函数可以访问Thread对象,方便检查退出标志支持线程克隆,适合需要动态创建多个相同类型线程的场景

3.2 定时器管理:统一调度

嵌入式系统中常常需要管理大量定时器,如果每个定时器都开一个线程,资源消耗很大。AppKit采用了单线程集中调度的方式:

关键点

    所有定时器共享一个线程,每1ms检查一次定时器回调在TimerManager的线程中执行,注意不要阻塞适合周期在100ms以上的定时任务,对于高精度定时建议使用硬件定时器

3.3 应用框架:Component模式

AppKit提供了一个轻量级的应用框架,类似于ROS的节点概念:

这种设计让应用的生命周期管理变得清晰:

优势

    统一的生命周期管理,不会遗漏资源释放任务自动在后台线程池中执行,无需手动管理线程支持多组件组合,构建复杂应用

四、实战示例

4.1 定时器

#include <appkit/async.h>
#include <appkit/console.h>
#include <appkit/datetime.h>
#include <appkit/strutil.h>
#include <appkit/timer.h>
#include <appkit/tracer.h>

usingnamespace appkit;

void test_timer_manager() {
    Timer t1(500, true);
    Timer t2(1000, true);
    TimerManager tm;
    tm.registerTimer(t1, []() { TRACE_INFO("500 ms timer timeout!"); });
    tm.registerTimer(t2, []() { TRACE_INFO("1000 ms timer timeout!"); });

    while (1) {
        TRACE_YELLOW("01. start.");
        TRACE_YELLOW("02. stop.");
        TRACE_YELLOW("input q to quit!");
        ConsoleIn ci;
        ci.waitInput();
        if (ci.asString() == "01") {
            tm.start();
        } elseif (ci.asString() == "02") {
            tm.stop();
        } elseif (ci.asString() == "q" || ci.asString() == "quit") {
            break;
        }
    }
    tm.stop();
}

void test_timer() {
    while (1) {
        TRACE_YELLOW("----------timer test--------------");
        TRACE_YELLOW("01. timer manager test.");
        TRACE_YELLOW(" q. quit");
        TRACE_YELLOW("please input selection:");
        ConsoleIn ci;
        ci.waitInput();
        if (ci.asString() == "01") {
            test_timer_manager();
        } elseif (ci.asString() == "02") {
            //
        } elseif (ci.asString() == "q" || ci.asString() == "quit") {
            break;
        }
    }
}

五、总结

5.1 值得学习的地方

Runnable模式的线程封装:比直接使用std::thread更符合OOP思想,线程逻辑可复用、可测试

Component生命周期管理:四阶段(init/start/stop/deinit)让资源管理不再混乱

TimerManager的单线程调度:以较小的代价支持多定时器,适合资源受限的嵌入式系统

环境变量驱动的构建系统:灵活性高于硬编码的Makefile,易于扩展

 

相关推荐

登录即可解锁
  • 海量技术文章
  • 设计资源下载
  • 产业链客户资源
  • 写文章/发需求
立即登录

本公众号专注于嵌入式技术,包括但不限于C/C++、嵌入式、物联网、Linux等编程学习笔记,同时,公众号内包含大量的学习资源。欢迎关注,一同交流学习,共同进步!