FastDDS(原名FastRTPS)作为一款高性能的DDS(Data Distribution Service)中间件实现,在工业物联网和分布式系统中应用广泛。但在实际编译过程中,环境配置往往是第一个拦路虎。根据我在多个项目中的实践经验,编译环境需要特别注意以下三点:
首先是系统版本的选择。虽然官方文档声称支持Ubuntu 16.04及以上版本,但实测发现18.04 LTS和20.04 LTS的兼容性最佳。特别提醒:在Ubuntu 22.04上会遇到GCC版本过高导致的模板元编程问题,需要额外打补丁。建议使用Docker容器隔离开发环境,我常用的基础镜像是ubuntu:18.04。
其次是工具链的版本控制。必须严格匹配的组件包括:
最后是依赖库的完整安装。除了文档列出的libasio-dev、libtinyxml2-dev等基础依赖外,这些隐藏依赖也必不可少:
bash复制sudo apt-get install libssl-dev libboost-chrono-dev libboost-system-dev
libboost-thread-dev libboost-regex-dev libp11-kit-dev
重要提示:在ARM架构设备(如树莓派)上编译时,必须预先安装
libatomic-ops-dev,否则会因内存模型问题导致链接失败。
官方推荐的源码获取方式是通过GitHub克隆:
bash复制git clone --recursive https://github.com/eProsima/Fast-DDS.git
但这里有个大坑:--recursive参数必须加上,否则会缺失关键子模块(特别是foonathan_memory)。我曾因此浪费两小时排查编译错误。
源码目录结构需要特别关注:
code复制Fast-DDS
├── cmake/ # 自定义CMake脚本
├── include/ # 公共头文件
├── src/cpp/ # 核心实现
├── thirdparty/ # 第三方依赖(最易出问题)
└── tools/ # 辅助工具
配置阶段建议使用以下CMake命令:
bash复制mkdir build && cd build
cmake .. -DTHIRDPARTY=ON -DBUILD_SHARED_LIBS=ON \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=/usr/local/fastdds
关键参数解析:
THIRDPARTY=ON:强制编译第三方依赖(避免系统版本冲突)BUILD_SHARED_LIBS=ON:生成.so动态库(默认静态库体积过大)最常见的错误是foonathan_memory编译报错:
code复制CMake Error at thirdparty/foonathan_memory/CMakeLists.txt:50 (add_subdirectory):
The source directory does not contain a CMakeLists.txt file.
解决方法:
bash复制git submodule update --init
在GCC 11+环境下会出现大量模板递归深度报错:
code复制fatal error: template instantiation depth exceeds maximum of 900
临时解决方案(不推荐长期使用):
bash复制export CXXFLAGS="-ftemplate-depth=2048"
cmake ..
当系统中已安装旧版FastRTPS时,可能出现:
code复制undefined reference to `eprosima::fastrtps::rtps::RTPSDomain::createParticipant()
彻底解决方案:
bash复制sudo apt remove *fastrtps*
rm -rf /usr/local/include/fastrtps /usr/local/lib/libfastrtps*
成功编译后,执行安装:
bash复制make -j$(nproc)
sudo make install
验证安装是否成功的正确姿势:
检查库文件:
bash复制ls /usr/local/fastdds/lib | grep libfastrtps
应看到.so动态库和.a静态库
运行测试用例:
bash复制cd examples/C++/HelloWorldExample
mkdir build && cd build
cmake .. -DCMAKE_PREFIX_PATH=/usr/local/fastdds
make
./HelloWorldExample
正常应看到发布者和订阅者的交互日志
在调试模式下编译时,启用内存分析工具:
bash复制cmake .. -DCMAKE_BUILD_TYPE=Debug -DBUILD_MEMORY_TOOLS=ON
这会集成foonathan_memory的调试功能,可以检测:
生产环境推荐使用以下配置:
bash复制cmake .. -DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DENABLE_STRICT_MODE=ON \
-DSECURITY=ON \
-DCMAKE_CXX_FLAGS="-march=native -O3"
针对ARM平台(如Jetson TX2)的编译示例:
bash复制cmake .. -DCMAKE_TOOLCHAIN_FILE=../cmake/toolchains/arm-linux-gnueabihf.cmake \
-DTHIRDPARTY=FORCE \
-DCMAKE_BUILD_TYPE=Release
库文件瘦身:
bash复制strip -s libfastrtps.so.2.3
可减少约40%的体积
依赖项检查:
bash复制ldd libfastrtps.so.2.3
确保所有依赖都能在目标机器解析
运行时配置:
创建fastdds.xml配置文件,内容示例:
xml复制<profiles>
<transport_descriptors>
<transport_descriptor>
<transport_id>udp_transport</transport_id>
<type>UDPv4</type>
</transport_descriptor>
</transport_descriptors>
</profiles>
通过环境变量加载:
bash复制export FASTRTPS_DEFAULT_PROFILES_FILE=fastdds.xml
现象:同一机器上的发布/订阅无法通信
解决方案:
xml复制<participant profile_name="eth0_profile">
<rtps>
<builtin>
<initialPeersList>
<locator>
<udpv4>
<address>192.168.1.100</address>
</udpv4>
</locator>
</initialPeersList>
</builtin>
</rtps>
</participant>
调整QoS参数:
cpp复制PublisherQos pubQos;
pubQos.history().kind = KEEP_LAST_HISTORY_QOS;
pubQos.history().depth = 50;
pubQos.reliability().kind = RELIABLE_RELIABILITY_QOS;
pubQos.publish_mode().kind = ASYNCHRONOUS_PUBLISH_MODE;
建议配置:
xml复制<transport_descriptor>
<transport_id>shm_transport</transport_id>
<type>SHM</type>
</transport_descriptor>
cpp复制ParticipantQos pqos;
pqos.wire_protocol().builtin.discovery_config.leaseDuration = eprosima::fastrtps::c_TimeInfinite;
pqos.wire_protocol().builtin.discovery_config.leaseAnnouncementPeriod = {3, 0};
从FastRTPS迁移到FastDDS 2.0+的注意事项:
头文件路径变更:
cpp复制// 旧版
#include <fastrtps/fastrtps_fwd.h>
// 新版
#include <fastdds/fastdds.hpp>
API变化点:
Domain::createParticipant()改为DomainParticipantFactory::create_participant()Publisher::write()现在返回ReturnCode_t新增必须调用的初始化:
cpp复制eprosima::fastdds::dds::Log::SetVerbosity(eprosima::fastdds::dds::Log::Kind::Info);
内置统计模块启用:
cpp复制DomainParticipantQos pqos;
pqos.properties().properties().emplace_back("fastdds.statistics", "HISTORY_LATENCY_TOPIC");
使用fastddsmon工具:
bash复制git clone https://github.com/eProsima/Fast-DDS-monitor.git
cd Fast-DDS-monitor && mkdir build && cd build
cmake .. -Dfastdds_DIR=/usr/local/fastdds/cmake
make
Prometheus监控集成示例:
cpp复制#include <fastdds/statistics/IListeners.hpp>
class MyListener : public eprosima::fastdds::statistics::IListener {
void on_rtps_sent(const statistics::RtpsSentData& data) override {
// 推送指标到Prometheus
}
};
只编译所需模块(如仅核心库):
bash复制cmake .. -DCOMPILE_EXAMPLES=OFF -DCOMPILE_TOOLS=OFF
替换默认内存分配器:
cpp复制// 在包含Fast-DDS头文件前定义
#define FOONATHAN_MEMORY_NAMESPACE my_mem
#include <foonathan/memory/namespace_alias.hpp>
// 初始化自定义分配器
my_mem::memory_pool<> pool;
my_mem::allocator_reference<my_mem::memory_pool<>> alloc(pool);
减少动态库的符号暴露:
cmake复制add_compile_options(-fvisibility=hidden)
set(CMAKE_CXX_VISIBILITY_PRESET hidden)
set(CMAKE_VISIBILITY_INLINES_HIDDEN ON)
经过这些年的实践,我认为FastDDS的编译过程虽然坑多,但只要掌握了环境隔离、依赖控制和编译选项这三个关键点,就能建立起稳定的编译流水线。建议将成功编译的Dockerfile保存为模板,新项目直接基于此扩展。