参考
问题
编译出现了找不到 protobuf 的问题
ubuntu20 下安装了 protobuf
sudo apt install libprotobuf-dev libprotoc-dev
继续编译跑到一半报错 !
undefined reference to `google::protobuf::util::JsonStringToMessage(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, google::protobuf::Message*, google::protobuf::util::JsonParseOptions const&)
undefined reference to `google::protobuf::internal::ArenaImpl::AllocateAlignedAndAddCleanup(unsigned long, void (*)(void*))
undefined reference to `google::protobuf::io::CodedInputStream::DecrementRecursionDepthAndPopLimit(int)
......
![](https://img-blog.csdnimg.cn/direct/0aa7a27087f94813ab5df27e22259297.png)
报错内容是找不到对应函数的链接,估计是安装的库版本和代码中使用的版本不匹配导致的。
分析
排查函数声明是否匹配
用 synaptic pakeage manager 搜索 protobuf 可以看到安装的版本是 3.6.1 版本
![](https://img-blog.csdnimg.cn/direct/9c98cc4cbf004ad48ce857f63f436a79.png)
![](https://img-blog.csdnimg.cn/direct/804d4fc145714991ad4ada894e482d80.png)
右键点击 libprotobuf-dev,选择 properties 选项,在 install files 可以看到库头文件的安装位置:
![](https://img-blog.csdnimg.cn/direct/3fef5403328f4e37b33a2b13ac78ce4c.png)
cd 到库的头文件安装目录下
cd /usr/include/google/protobuf
尝试搜索报错中找不到的函数:
find . -name '*' | xargs grep 'JsonStringToMessage'
![](https://i-blog.csdnimg.cn/direct/864da9f35d4f41aa9b4cfbe055dc0e80.png)
我们再到库头文件目录下 json_util.h 文件中搜索 JsonStringToMessage 函数
![](https://img-blog.csdnimg.cn/direct/8c3004bb47a543c5a8b8a012b4d151a2.png)
对比一下报错中的 JsonStringToMessage 函数:
undefined reference to `google::protobuf::util::JsonStringToMessage(
std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, google::protobuf::Message*,
google::protobuf::util::JsonParseOptions const&)
居然是一样的 :( 那么问题出在哪里?
排查是否能找到库
再仔细看看报错,在 "undefined reference to xxx" 的报错下面,提到了链接配置的文件
![](https://i-blog.csdnimg.cn/direct/66976f3d2418443097c17e6181e76588.png)
打开相关链接文件后,找到提示说的第 148 行
![](https://i-blog.csdnimg.cn/direct/4f0a7de948a1493faafc8c00148b6881.png)
这里大概是说 cd 到链接配置的文件夹中, 用一个 cmake 的链接脚本打开链接配置文件去找相关的库文件之类的,然后再打开图 fig.8 中框起来的 link.txt 文件看看
![](https://i-blog.csdnimg.cn/direct/73441d4ec5e345839e4c7f3b1d006270.png)
一大堆斜杠,一看就是路径!就是说这文件很可能就是链接库时候用来搜索的路径。搜一下 "protobuf",看到链接库时候搜索的路径是 /usr/local/lib/libprotobuf.so
然后再看看本地该路径下是否有这个库
![](https://img-blog.csdnimg.cn/direct/c2d0d5b6821e429bb65b61244384a058.png)
:( emmm...不仅有,还很多
排查库与库头文件是否匹配
那么还有一种可能就是库和头文件不匹配的问题了,因为之前安装过 libprotoc 的 2.6.1 版本。虽然后来卸载了,但是有可能卸载不干净?
再次打开 synaptic pakeage manager,右键点击 libprotobuf-dev,选择 properties 选项,拉到最下面看到了库的安装路径(上面是库的头文件安装路径):
![](https://img-blog.csdnimg.cn/direct/02358021cc1e4dfcafa96bfb3927f569.png)
看看本地的 /usr/lib/x86_64-linux-gnu/ 路径下是否有 libprotobuf-dev 的库
![](https://img-blog.csdnimg.cn/direct/d8dcac34effa4322a8dc7e204635e11b.png)
在本地的 /usr/lib/x86_64-linux-gnu/ 路径下确实还有个 libprotobuf.so 库。那么基本可以确定是两个不同版本的库导致了头文件函数声明和库的实现不匹配的问题了。
/usr/local/lib 中库是之前旧的 libprotobuf 库
/usr/lib/x86_64-linux-gnu/ 中库是现在新的 libprotobuf 库
我们直接在图 fig.9 的 link.txt 文件中补充上新库路径,可能需要 sudo 权限:
![](https://i-blog.csdnimg.cn/direct/9e99f2444e99437fb4f9f0a9926e0ef7.png)
再次编译,编译成功了!但是多了条警告:
在本地的 /usr/local/lib 中找到了 libprotobuf.so.9 而 libprotobuf.so.17 是在 /usr/lib/x86_64-linux-gnu/ 路径中,库名都不一样,大概率没事吧 emmm
解决办法
当清除 devel 和 build 包后,重新编译仍然会链接不到库,那么要彻底解决问题还得编译的时候自动包含新库的链接地址。
完美的办法:
link.txt 文件只有旧库的路径,说明编译时候搜索到的版本是旧版本,只要让 cmake 搜索到新库的头文件路径和库路径就可以完美解决问题了。那么 cmakelist.txt 中是如何搜索头文件路径和库路径的呢?
//TODO:折腾了一段时间没解决库链接的问题,太费时间了,这里先挖个坑。
偷懒的办法:
把新库的路径导入到环境变量 PATH 中,但这样会污染 PATH 环境?
sudo vim ~/.bashrc
![](https://i-blog.csdnimg.cn/direct/f077e48c877b40ce975d222a568594f1.png)
在终端里重新 source ~/.bashrc 文件
删除工程的 build 和 devel 文件夹,重新编译,编译成功了!
暴力的办法:
在 /usr/local/lib 目录下新建文件夹叫 "old_protobuf",把旧版本的 proto* 文件移动到这个文件夹中,然后再把 /usr/lib/x86_64-linux-gnu/ 中的 proto* 文件拷贝一份到 /usr/local/lib 目录下。
先屏蔽 ~/.bashrc 文件里补充路径的指令
删除工程的 build 和 devel 文件夹,重新编译,编译成功了!
![](https://i-blog.csdnimg.cn/direct/dcfd96b97383489f84056662fb441163.png)
小结
docker 容器是要好东西,隔绝环境,希望每个做工程的人都用上 :)
一个好的习惯是写文件记录安装的软件,方便排查问题,也方便以后做 docker 容器。