RFrame 编译指南
文档总入口:《RFrame 使用入口》
1. 文档定位
本文面向使用已安装 RFrame SDK 的 C++ 和 Python 用户,说明:
- C++ 工程如何通过 CMake 消费 RFrame;
- 应该声明哪些 component、链接哪些 target;
- Python wheel 如何与 native RFrame 保持一致;
- 编译期、Python binding 和运行期环境变量如何管理;
- RFrameExample 中可以参考哪些文件。
本文不涉及 RFrame 框架源码编译和 SDK 制作。软件包安装与运行配置见《RFrame 部署指南》,Channel API 见《RFrame 开发指南》。
参考工程:deb 包 robby-r-frame-example(安装后位于 /opt/robby/RFrameExample/)。
2. C++ 用户接入
2.1. 编译前提
- CMake 3.10 或更高版本;
- 支持 C++17 的编译器;
- 已安装匹配版本的
r-frameSDK; - 使用 ROS 2 消息类型时,已安装并加载 ROS 2 Humble;
- 使用自定义消息类型时,已安装并加载对应消息工作区。
cmake --version
c++ --version
dpkg-query -W r-frame
使用 ROS 2 类型时,必须在 CMake configure 前执行:
source /opt/ros/humble/setup.bash
source /path/to/message_workspace/install/setup.bash # 自定义类型时
不要手工设置 AMENT_PREFIX_PATH 或 ROS 相关的多个 CMake 路径;以 source 对应 setup.bash 为准。
标准 deb 安装的布局如下,RFrame 本体和底层依赖库都放在 /usr/local/lib 下:
| 内容 | 安装路径 |
|---|---|
RFrame 本体库 libr_frame_*.so | /usr/local/lib/ |
随包底层库(如 libecdr.so) | /usr/local/lib/ |
| C++ 头文件 | /usr/local/include/r、/usr/local/include/r_c |
| CMake package | /usr/local/lib/cmake/r-frame/ |
Channel/Runtime 插件 .so(r-frame-plugin deb) | /usr/local/lib/<插件名>/ |
| 插件默认 catalog | /opt/robby/r-frame/config/plugins.json |
| 随包第三方底层依赖(fastcdr、rosidl typesupport 等) | /opt/robby/r-frame/lib/third_party/ |
| Python wheel | /usr/local/lib/rframe/ |
find_package(r-frame) 默认能在 /usr/local/lib/cmake/r-frame 找到配置;/usr/local/lib 下的库由系统动态链接器自动解析,正常不需要额外设置 LD_LIBRARY_PATH。
2.2. 推荐 CMake 写法
用户工程只声明代码直接使用的 RFrame component,并链接对应命名空间 target:
cmake_minimum_required(VERSION 3.10)
project(my_rframe_app LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
find_package(r-frame REQUIRED COMPONENTS channel app log)
add_executable(my_rframe_app main.cpp)
target_link_libraries(my_rframe_app
PRIVATE
r::channel
r::app
r::log
)
配置和编译:
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j4
RFrame 的 CMake package 会加载所请求 component 的传递依赖。用户工程不应重复 find_package 或硬编码 Boost、Protobuf、jsoncpp 等 SDK 内部依赖。
2.3. Component 和 target 选择
| 用户代码直接使用 | find_package component | 链接 target |
|---|---|---|
AppCore | app | r::app |
| 日志 API | log | r::log |
ChannelManager、Hybrid Topic/RPC | channel | r::channel |
Target 规则:
r::<component>:推荐;r::frame:聚合 target,仅在确实直接使用大量模块时采用;r_frame_<component>:旧工程兼容写法,不作为新工程首选。
2.4. RFrameExample 参考路径
示例源码由 deb 包交付,下表路径均相对 /opt/robby/RFrameExample/:
| 需求 | 参考文件 |
|---|---|
最小 find_package 和 target 写法 | src/find_package_usage/CMakeLists.txt |
| 日志依赖声明 | src/log/CMakeLists.txt |
AppCore/核心依赖声明 | src/core/CMakeLists.txt |
| Channel demo target | src/channel/CMakeLists.txt |
ChannelManager 基础示例 | src/channel/quickstart/channel_manager_example.cpp |
| JSON 配置检查器 | src/channel/config/channel_config_json_example.cpp |
| typed Hybrid Topic | src/channel/typed/typed_channel_example.cpp |
| typed Hybrid RPC | src/channel/typed/typed_rpc_example.cpp |
需要验证 SDK 接入时,安装示例 deb 后独立编译最小 Channel 示例(散装单元,无需克隆仓库):
sudo apt install robby-r-frame-example
source /opt/ros/humble/setup.bash
cmake -S /opt/robby/RFrameExample/src/channel -B build/channel -DCMAKE_BUILD_TYPE=Release
cmake --build build/channel -j4 --target \
channel_manager_example channel_config_json_example \
typed_channel_example typed_rpc_example
typed_rpc_example 依赖 example_interfaces(sudo apt install ros-${ROS_DISTRO}-example-interfaces);环境缺失时该目标会被自动跳过,其余示例不受影响。
2.5. 非系统安装路径
SDK 不在标准安装路径时,用 CMAKE_PREFIX_PATH 指定该 SDK:
cmake -S . -B build \
-DCMAKE_PREFIX_PATH=/path/to/rframe/install \
-DCMAKE_BUILD_TYPE=Release
cmake --build build -j4
多个前缀用分号分隔:
cmake -S . -B build \
'-DCMAKE_PREFIX_PATH=/path/to/rframe/install;/usr/local'
不要用 link_directories() 或手工 .so 路径代替 find_package。
3. Python wheel 保障
3.1. 交付关系
r-frame deb 同时交付:
- native RFrame library;
- 系统 Python binding:
/usr/lib/python3/dist-packages/rframe; - 同批次 wheel:
/usr/local/lib/rframe/rframe-*.whl。
wheel 的版本来自与 deb 相同的构建 tag。wheel 只提供 Python binding,不能脱离同批次 native r-frame 使用。
3.2. 系统 Python
系统 Python 直接使用 deb 安装的 binding,不需要再次执行 pip:
/usr/bin/python3 -c \
'import rframe; print(rframe.__file__, rframe.__version__, rframe.__build_tag__)'
3.3. 虚拟环境或自定义 Python
虚拟环境安装 deb 内同批次 wheel:
python3 -m venv --system-site-packages .venv
source .venv/bin/activate
ls /usr/local/lib/rframe/rframe-*.whl
python -m pip install --no-deps /usr/local/lib/rframe/rframe-*.whl
python -c \
'import rframe; print(rframe.__file__, rframe.__version__, rframe.__build_tag__)'
使用 ROS 2 Python 消息时保留 --system-site-packages,使虚拟环境能够访问系统安装的 ROS 2 模块。纯 SHM 且不依赖系统消息包时可以省略。
禁止以下组合:
- 只复制 wheel,不安装 native
r-frame; - 使用另一个发布批次生成的 wheel;
- 系统 Python、虚拟环境和 Conda 环境之间混用 site-packages;
- 用
PYTHONPATH指向 RFrame 源码目录替代正式 wheel。
3.4. 3.4 版本一致性检查
dpkg-query -W -f='${Version}\n' r-frame
python -c \
'import rframe; print(rframe.__version__, rframe.__build_tag__)'
__build_tag__ 应对应已安装 deb 的构建批次。PEP 440 wheel 版本和 Debian 版本的标点可能不同,应比较版本主体、rc/dev 编号和构建时间戳。
3.5. Python 示例参考
以下文件均相对 deb 安装路径 /opt/robby/RFrameExample/:
| 需求 | 文件 |
|---|---|
| 日志 | python/log_example.py |
| typed Hybrid Topic | python/typed_channel_interop.py |
| Hybrid RPC、JSON 映射、C++ 互通 | python/rpc_interop.py |
示例运行方式见《RFrame 开发指南》。
4. 环境变量和路径保障
4.1. 变量分类
| 变量或环境 | 阶段 | 正式用法 |
|---|---|---|
CMAKE_PREFIX_PATH | C++ configure | 仅在 SDK 非标准安装路径时设置 |
ROS 2 setup.bash | C++ configure / Python 运行 | 使用 ROS 2 类型或后端时 source |
消息工作区 setup.bash | C++ configure / Python 运行 | 使用自定义消息或 service 时 source |
RFRAME_C_API_LIB | Python native binding | 仅用于非标准 native library 路径或诊断 |
LD_LIBRARY_PATH | 运行时诊断 | 标准 deb 安装不设置;仅临时验证非标准 SDK |
PYTHONPATH | Python import | 正式安装不设置;通过 deb 或 wheel 提供 binding |
RFRAME_CONFIG_PATH | 应用运行 | 选择全局 rframe.json,见部署指南 |
RFRAME_LOG_LEVEL | 应用运行 | 覆盖全局日志级别,见部署指南 |
4.2. RFRAME_C_API_LIB
Python binding 通过 native C API library 工作。标准 deb 安装应由动态链接器自动找到该库,不需要设置变量。
仅在验证非标准 SDK 时显式指定:
export RFRAME_C_API_LIB=/path/to/libr_frame_c_api.so
python -c 'import rframe; print(rframe.__file__)'
该变量必须指向与 wheel 同批次的 library,用完后取消:
unset RFRAME_C_API_LIB
4.3. LD_LIBRARY_PATH
标准 deb 安装的 RFrame 本体库和底层依赖库都在 /usr/local/lib 下(见 §2.1 安装布局),由系统动态链接配置自动解析,不应要求业务设置 LD_LIBRARY_PATH。只有验证非标准 SDK 时临时设置:
export LD_LIBRARY_PATH=/path/to/rframe/install/lib:${LD_LIBRARY_PATH:-}
ldd build/my_rframe_app
不要把该变量写入正式启动脚本来掩盖 SDK 混装问题。
4.4. 运行期变量
RFRAME_CONFIG_PATH 和 RFRAME_LOG_LEVEL 不参与 CMake 和 wheel 安装。它们只在应用运行时生效,配置方式见《RFrame 部署指南》。
5. 用户工程验证
5.1. C++
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j4
ldd build/my_rframe_app
确认:
- CMake 从预期 SDK 找到
r-frame; - 编译和链接成功;
ldd显示 RFrame 与依赖来自同一套安装;- ROS 2 type support 来自已 source 的目标工作区。
5.2. Python
python -c \
'import rframe; print(rframe.__file__, rframe.__version__, rframe.__build_tag__)'
确认:
- import 路径属于预期系统 Python 或虚拟环境;
- wheel build tag 与 native deb 对应;
- 标准安装没有依赖源码
PYTHONPATH; RFRAME_C_API_LIB未意外指向另一套 SDK。
6. 常见问题
6.1. CMake 找不到 r-frame
检查 SDK 是否安装,以及 CMAKE_PREFIX_PATH 是否指向包含 lib/cmake/r-frame 的安装前缀。
6.2. 找不到 ROS 2 或自定义类型
重新 source ROS 2 和消息工作区后,删除旧的用户工程 CMake cache 并重新 configure。
6.3. C++ 链接到错误版本
用 ldd 检查实际 library;清理错误的 CMAKE_PREFIX_PATH、LD_LIBRARY_PATH 和旧 build cache,不要手工补 link_directories()。
6.4. Python 无法导入或加载 native library
依次检查:
- 当前 Python 解释器;
rframe.__file__;- wheel 是否来自
/usr/local/lib/rframe/; - native
r-framedeb 是否安装且版本匹配; RFRAME_C_API_LIB是否错误覆盖。