前端时间一位同事遇到一个问题,当时和他一起排查,感觉这个问题挺有意思,在这里记录一下。
背景:
这个同事因为项目需要,需要编译QNX系统上可用的vsomeip库,对于vsomeip库,搞车载软件的应该都知道,这个应该是市面上为数不多的开源的someip通信库。使用过QNX系统的朋友应该都知道,编译这玩意的上的应用程序,都需要交叉编译的。搞Linux嵌入式开发的朋友,应该对交叉编译深有体会,自己写的代码还好,一旦遇到移植开源库的时候,就各种的头疼了。之前为了移植jemalloc到qnx系统上,真是头疼,不仅需要将automake修改cmake(个人习惯,cmake对于交叉编译确实好用),还要去解决Linux系统有而qnx系统没有的一些函数接口问题,老头疼了。
问题:
同事在编译vsomeip的example的时候,编译是通过了,但是不能在QNX系统上运行。一开始还以为是编译的vsomeip库有问题,后来同时单独写了一个类似的demo,交叉编译也是通过了,在qnx系统上也是不能运行,无论是虚拟机还是板子上,都无法运行。代码如下:
#include<iostream>
#include<thread>
#include <mutex>
#include <condition variable>
#include <chrono>
std::mutex mtx;
std::condition variable cv;
bool ready = false;
void do work(){
//模拟工作耗时
std::this thread::sleep for(std::chrono::seconds(2));
std::lock guard<std::mutex>lock(mtx);
ready = true;
//通知一个等待的线程
cv.notify_one();
}
int main(){
std::thread worker(do work);
std::unique lock<std::mutex> lock(mtx);
while (!ready){
if(cv,wait for(lock, std::chrono::seconds(1))== std::cv status::timeout)
{
std::cout<<"still waiting after 1 second..."<<std::endl;
}
else
{
std::cout'<<"Work completed!"<<std::endl,break;//条件满足,退出循环
}
worker.join();
return 0;
}
很简单的一种多线程启动与线程同步的方式。使用QNX的编译器 qcc也是编译通过了。
但是在qnx系统上运行该程序的是就出现问题了
出现的问题是:在libstd++库中没有找到条件变量(condition_variable)对应的符号,或者可以理解为没有在C++库中没有找到条件变量的实现,这一下子有点郁闷了,这不应该啊,不带这么玩了啊,这玩意不是stl携带的吗,怎么就没了尼。一下整不会了。
问题分析与解决
郁闷归郁闷,问题还得解决,工作还得继续干。按照我的理解,如果在编译的环境,能够编译通过,那么理论上编译环境中的libstdc++.so中是携带添加变量符号与实现的(当然有的系统会将libstdc++.so中的服务该剥离了,但是比较少。),所以我当时还以是不是供应商给的QNX系统和编译器版本不对应的。然后让同事通过ldd 命令查看该应用程序依赖的c++库,拷贝到目标系统上。
设置库的环境变量,然后再次运行之前编译的应用程序。
从截图上看,库是已经使用了我们考过去的库了,但是程序依然无法正常运行。不过当前错误不同与前一个错误,这个错误是libc++找不到pthread_cond_clockwait。看到这个第一反应是应用程序没有link libpthread.so。后来一想。md,QNX上没有这玩意,如果有这玩意,编译的时候应该是编译失败的,又是一阵郁闷,到底是哪出错了呢。不过,从这结果上看,系统上库与提供的编译工具链的环境应该存在不一致的情况,至少stdc++和c++这个库是不一致的。这个可以从显示的错误上可以看出来。
现在的情况是:
编译环境:能够编译出应用成,也就是说,编译环境中能够提供应用程序运行所需要的所有代码指令以及相应的库。
运行环境:在运行环境中,无法允许编译环境中编译出来的应用程序。
前面已经证明了运行环境中所需要的库可能存在问题,那么推测,其他库也就有可能出问题或者不一致,因此我和他说,实在不行,咱就把libm.so.libc.so这两库也考过去试试,理论上来说这俩库不应该出现这个问题。
然后奇迹出现了
于是同事喊出了经典的口头禅。哈哈
总结:
这个问题给我的一个提示是:交叉编译中,在编译环境中如果通过,而在运行环境中无法运行,说明:编译环境与运行环境存在不一致的情况,这个就需要验证环境的一致性或者