当前位置: 首页 > article >正文

【AimRT】AimRT Hello World

目录

  • 一、工程结构
  • 二、源码说明
    • /CMakeLists.txt
    • /cmake/GetAimRT.cmake
    • /src/CMakeLists.txt
    • /src/module/helloworld_module/CMakeLists.txt
    • /src/app/helloworld_app/CMakeLists.txt
    • /src/install/cfg/helloworld_cfg.yaml
    • /src/module/helloworld_module/helloworld_module.h
    • /src/module/helloworld_module/helloworld_module.cc
    • /src/app/helloworld_app/main.cc
  • 三、编译与运行

官方 Hello World 文档链接:https://docs.aimrt.org/tutorials/quick_start/helloworld_cpp.html

这里对其增加一些说明。

目前 AimRT 仅支持从源码安装,并且对于第三方依赖,也是通过拉取源码的方式安装,该方式通过 CMake 的FetchContent 实现,虽然该方式可以增强AimRT环境配置的兼容性,但对于封闭网络开发与网络不好的用户不太友好,而且部署一次环境是局部生效的,同一台电脑再新建一个工程还需要拉取源码安装一次。

该 Hello World Demo 涉及以下内容:

  • 基于 CMake FetchContent 通过源码引用 AimRT;
  • 编写一个基础的基于 AimRT CPP 接口的Module
  • 使用基础的日志功能;
  • 使用基础的配置功能;
  • 以 App 模式集成Module
  • 编译项目,并运行进程以执行Module中的逻辑。

一、工程结构

├── CMakeLists.txt                    
├── cmake
│   └── GetAimRT.cmake                # 基于 CMake FetchContent 通过源码引用 AimRT
└── src
    ├── CMakeLists.txt
    ├── install                      # 存放部署时的一些配置、启动脚本等
    │   └── cfg
    │       └── helloworld_cfg.yaml  # AimRT配置文件 
    ├── module                       # 存放业务逻辑代码
    │   └── helloworld_module
    │       ├── CMakeLists.txt
    │       ├── helloworld_module.cc # Module源文件
    │       └── helloworld_module.h  # Module头文件
    └── app                          # 以App模式集成Module
        └── helloworld_app         
            ├── CMakeLists.txt
            └── main.cc

二、源码说明

/CMakeLists.txt

根 CMake ,用于构建工程。

# 指定项目所需的最低CMake版本
cmake_minimum_required(VERSION 3.24)

# 定义项目的名称为helloworld,并指定该项目将使用C和C++语言
project(helloworld LANGUAGES C CXX)

# 设置项目使用的C++标准为C++20
set(CMAKE_CXX_STANDARD 20)
# 要求CMake确保编译器支持指定的C++标准。
# 如果编译器不支持该标准,CMake配置将失败。
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# 禁用编译器特定的扩展
set(CMAKE_CXX_EXTENSIONS OFF)

# 包含一个名为GetAimRT.cmake的CMake模块
# 用于通过源码引用 AimRT
include(cmake/GetAimRT.cmake)

# 添加并处理src子目录
add_subdirectory(src)

/cmake/GetAimRT.cmake

通过源码引用 AimRT

# 包含FetchContent模块,该模块提供了一系列函数和宏,用于从远程仓库获取内容
include(FetchContent)

message("get aimrt ...")

# 使用FetchContent_Declare函数声明一个名为aimrt的外部项目
FetchContent_Declare(
  aimrt
  GIT_REPOSITORY https://github.com/AimRT/aimrt.git # 项目仓库链接
  GIT_TAG v0.9.2) # 项目版本

# 获取aimrt项目属性
# 用于检查项目是否已经被下载、配置和构建
FetchContent_GetProperties(aimrt)

# 检查aimrt项目是否已经下载并准备好用于构建
# 如果项目尚未准备好,则调用FetchContent_MakeAvailable函数下载、配置和构建该项目,
# 并将其添加到当前项目的构建系统中,使其可用
if(NOT aimrt_POPULATED)
  FetchContent_MakeAvailable(aimrt)
endif()

/src/CMakeLists.txt

引用 src 下的各个子目录

add_subdirectory(module/helloworld_module)
add_subdirectory(app/helloworld_app)

/src/module/helloworld_module/CMakeLists.txt

创建helloworld_module静态库

# 递归地查找当前源目录(${CMAKE_CURRENT_SOURCE_DIR})下所有以.cc结尾的文件,
# 并将这些文件的路径列表赋值给变量src
file(GLOB_RECURSE src ${CMAKE_CURRENT_SOURCE_DIR}/*.cc)

# 创建一个名为helloworld_module的静态库目标
add_library(helloworld_module STATIC)
# 为helloworld_module静态库创建一个别名目标helloworld::helloworld_module
# 别名目标允许以更具命名空间风格的方式引用库,这在大型项目中尤其有用,可以避免名称冲突
add_library(helloworld::helloworld_module ALIAS helloworld_module)

# 将之前通过file(GLOB_RECURSE ...)找到的源文件(变量src)添加到helloworld_module目标的私有源文件中
# PRIVATE意味这些文件仅对helloworld_module目标本身可见,不会传播到依赖于它的其他目标
target_sources(helloworld_module PRIVATE ${src})

# 为helloworld_module目标添加公共头文件目录
# 公共头文件目录意味着这些目录不仅可用于构建helloworld_module本身,
# 还可用于构建依赖于helloworld_module的任何目标
target_include_directories(
  helloworld_module
  PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/..)

# 指定helloworld_module目标需要链接的库
target_link_libraries(
  helloworld_module
  # yaml-cpp库是私有依赖项,仅用于构建helloworld_module本身,不会传播到依赖于它的其他目标
  PRIVATE yaml-cpp::yaml-cpp 
  # 公共依赖项,不仅用于构建helloworld_module,还用于构建依赖于helloworld_module的任何目标
  PUBLIC aimrt::interface::aimrt_module_cpp_interface)

/src/app/helloworld_app/CMakeLists.txt

创建helloworld_app可执行文件

# 递归地查找当前源目录(${CMAKE_CURRENT_SOURCE_DIR})下所有以.cc结尾的文件,
# 并将这些文件的路径列表赋值给变量src
file(GLOB_RECURSE src ${CMAKE_CURRENT_SOURCE_DIR}/*.cc)

# 添加名为helloworld_app的可执行文件
add_executable(helloworld_app)

# 为helloworld_app目标指定源文件
target_sources(helloworld_app PRIVATE ${src})

# 为helloworld_app目标指定头文件
target_include_directories(
  helloworld_app
  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})

# 为helloworld_app目标指定链接库
target_link_libraries(
  helloworld_app
  PRIVATE aimrt::runtime::core helloworld::helloworld_module)

/src/install/cfg/helloworld_cfg.yaml

配置文件

aimrt:
  log: # log配置
    core_lvl: Debug # 内核日志等级,可选项:Trace/Debug/Info/Warn/Error/Fatal/Off,不区分大小写
    backends: # 日志后端
      - type: console # 控制台日志
        options:
          color: true # 是否要彩色打印
          module_filter: "(.*)" # 支持以正则表达式的形式,来配置哪些模块的日志可以通过本后端处理
          pattern: "[%c.%f][%l][%t][%n][%G:%R @%F] %v" # 日志格式化输出
      - type: rotate_file # 将日志打印到文件中
        options:
          path: ./log # 日志文件存放目录
          filename: examples_cpp_hello_world.log # 日志文件名称

# 模块自定义业务配置,以模块名称为节点名
HelloWorldModule:
  name: "HelloWorldModule"
  array: 
    - name: hello
      enable: true
    - name: world
      enable: false

/src/module/helloworld_module/helloworld_module.h

Module头文件

// 防止头文件在当前编译单元中被多次引用
#pragma once

#include "aimrt_module_cpp_interface/module_base.h"

// 定义一个 HelloWorldModule 类,继承自aimrt::ModuleBase
class HelloWorldModule : public aimrt::ModuleBase
{
public:
    HelloWorldModule() = default;
    ~HelloWorldModule() override = default;

    // 模块信息,包括name、version、author、description等
    aimrt::ModuleInfo Info() const override
    {
        return aimrt::ModuleInfo{.name = "HelloWorldModule",
                                 .major_version = 0,
                                 .minor_version = 1,
                                 .patch_version = 0,
                                 .build_version = 0,
                                 .author = "vistar",
                                 .description = "AimRT hello world model"};
    }

    // 初始化模块资源
    bool Initialize(aimrt::CoreRef core) override;
    // 启动模块
    bool Start() override;
    // 关闭模块
    void Shutdown() override;

private:
    // 返回一个日志记录器实例
    auto GetLogger() { return core_.GetLogger(); }

private:
    aimrt::CoreRef core_;
    aimrt::parameter::ParameterHandleRef parameter_handle_;
};

/src/module/helloworld_module/helloworld_module.cc

Module源文件

#include "helloworld_module/helloworld_module.h"
#include "yaml-cpp/yaml.h"

bool HelloWorldModule::Initialize(aimrt::CoreRef core)
{
    // Save aimrt framework handle
    core_ = core;

    // Log
    AIMRT_INFO("Init HelloWorldModule.");

    try
    {
        // Read cfg
        auto file_path = core_.GetConfigurator().GetConfigFilePath();
        if (!file_path.empty())
        {
            // 将配置写入到临时文件中,使用YAML-CPP加载配置
            YAML::Node config = YAML::LoadFile(file_path.data());
            
            std::string moduleName = config["name"].as<std::string>();
            AIMRT_INFO("moduleName: {}", moduleName);

            for (const auto &itemNode : config["array"])
            {
                std::string itemName = itemNode["name"].as<std::string>();
                bool enable = itemNode["enable"].as<bool>();
                AIMRT_INFO("name: {}, enable: {}", itemName, enable);
            }
        }
    }
    catch (const std::exception &e)
    {
        AIMRT_ERROR("Init failed, {}", e.what());
        return false;
    }

    AIMRT_INFO("Init HelloWorldModule succeeded.");

    return true;
}

bool HelloWorldModule::Start()
{
    AIMRT_INFO("Start HelloWorldModule succeeded.");
    return true;
}

void HelloWorldModule::Shutdown()
{
    AIMRT_INFO("Shutdown HelloWorldModule succeeded.");
}

/src/app/helloworld_app/main.cc

#include <csignal>
#include <iostream>

#include "core/aimrt_core.h"
#include "helloworld_module/helloworld_module.h"

using namespace aimrt::runtime::core;

AimRTCore *global_core_ptr_ = nullptr;

// 信号处理函数
void SignalHandler(int sig)
{
    if (global_core_ptr_ && (sig == SIGINT || sig == SIGTERM))
    {
        global_core_ptr_->Shutdown();
        return;
    }
    raise(sig);
};

int32_t main(int32_t argc, char **argv)
{
    // 注册 ctrl+c 信号监听,用 SignalHandler 函数处理
    signal(SIGINT, SignalHandler);
    // 注册 kill 信号监听,用 SignalHandler 函数处理
    signal(SIGTERM, SignalHandler);

    std::cout << "AimRT start." << std::endl;

    try
    {
        // 实例化 AimRTCore
        AimRTCore core;
        global_core_ptr_ = &core;

        // register module
        HelloWorldModule helloworld_module;
        core.GetModuleManager().RegisterModule(helloworld_module.NativeHandle());

        // 通过命令行参数读取配置文件路径
        AimRTCore::Options options;
        options.cfg_file_path = argv[1];

        // 初始化AimRT,初始化注册的 Module
        core.Initialize(options);
        // 启动AimRT,启动注册的 Module
        // 阻塞主线程等待结束
        core.Start();

        core.Shutdown();

        global_core_ptr_ = nullptr;
    }
    catch (const std::exception &e)
    {
        std::cout << "AimRT run with exception and exit. " << e.what() << std::endl;
        return -1;
    }

    std::cout << "AimRT exit." << std::endl;
    return 0;
}

三、编译与运行

编译工程和普通编译CMake工程操作一样:

# 在根CMakeList.txt同级目录执行
# 生成构建文件,配置项目
cmake -B build

# 编译和链接可执行文件和库文件
cd build
make -j

运行AimRT可执行文件,需要传入配置文件。

编译完成后,将生成的可执行文件helloworld_app和配置文件helloworld_cfg.yaml拷贝到一个目录下,然后执行以下命令运行进程:

./helloworld_app helloworld_cfg.yaml

欢迎加QQ群,一起讨论学习:894013891


http://www.kler.cn/a/466950.html

相关文章:

  • 在CodeBlocks搭建SDL2工程构建TFT彩屏模拟器虚拟TFT彩屏幕显示
  • C语言延时实现
  • v-model与 mvvm 回顾
  • 单片机-串转并-74HC595芯片
  • RabbitMq的Java项目实践
  • Java 内存溢出(OOM)问题的排查与解决
  • 【Matlab算法】基于改进人工势场法的移动机器人路径规划研究(附MATLAB完整代码)
  • 【计算机视觉技术 - 人脸生成】2.GAN网络的构建和训练
  • 超越YOLO11!DEIM:先进的实时DETR目标检测
  • 服务器信息整理
  • 源代码编译安装X11及相关库、vim,配置vim(1)
  • IDEA 社区版 SpringBoot不能启动
  • QML自定义滑动条Slider的样式
  • [服务器][教程]Ubuntu24.04 Server开机自动挂载硬盘教程
  • 利用ChatGPT API构建智能应用的最佳实践
  • 深度剖析 DeepSeek V3 技术报告:架构创新与卓越性能表现
  • VR 合成层最多支持多少层?
  • 代码实战:基于InvSR对视频进行超分辨率重建
  • 现代光学基础5
  • 电子应用设计方案85:智能 AI门前柜系统设计
  • JVM实战—6.频繁YGC和频繁FGC的后果
  • 小程序添加购物车业务逻辑
  • 在ubuntu22.04中使用bear命令追踪内核编译报错的原因分析和解决方案
  • Three.js教程014:使用tween实现补间动画
  • Dubbo 关键知识点解析:负载均衡、容错、代理及相关框架对比
  • 浅谈分布式共识算法