ubuntu20 cmakelist 编译找不到 protobuf 问题解决

参考

cmakelist 的 find_package 分析

问题

编译出现了找不到 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)

......

fig.1 找不到链接

 报错内容是找不到对应函数的链接,估计是安装的库版本和代码中使用的版本不匹配导致的。

分析

排查函数声明是否匹配

用 synaptic pakeage manager 搜索 protobuf 可以看到安装的版本是 3.6.1 版本

fig.2 libprotobuf-dev 版本
​​
fig.3 libprotoc-dev 版本

右键点击 libprotobuf-dev,选择 properties 选项,在 install files 可以看到库头文件的安装位置:

fig. 4 libprotobuf-dev 头文件安装路径

cd 到库的头文件安装目录下

cd /usr/include/google/protobuf

尝试搜索报错中找不到的函数:

find . -name '*' | xargs grep 'JsonStringToMessage'
fig. 5 在库文件中搜索函数

我们再到库头文件目录下 json_util.h 文件中搜索 JsonStringToMessage 函数

fig. 6 库中 JsonStringToMessage 的函数声明

对比一下报错中的 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" 的报错下面,提到了链接配置的文件

fig. 7 报错提示说的链接配置文件

打开相关链接文件后,找到提示说的第 148 行

fig. 8 链接配置文件

这里大概是说 cd 到链接配置的文件夹中, 用一个 cmake 的链接脚本打开链接配置文件去找相关的库文件之类的,然后再打开图 fig.8 中框起来的 link.txt 文件看看

fig. 9 link.txt 文件

一大堆斜杠,一看就是路径!就是说这文件很可能就是链接库时候用来搜索的路径。搜一下 "protobuf",看到链接库时候搜索的路径是 /usr/local/lib/libprotobuf.so

然后再看看本地该路径下是否有这个库

fig. 10 本地 lib 库

:( emmm...不仅有,还很多

排查库与库头文件是否匹配

那么还有一种可能就是库和头文件不匹配的问题了,因为之前安装过 libprotoc 的 2.6.1 版本。虽然后来卸载了,但是有可能卸载不干净?

再次打开 synaptic pakeage manager,右键点击 libprotobuf-dev,选择 properties 选项,拉到最下面看到了的安装路径(上面是库的头文件安装路径):

fig. 11 libprotobuf-dev 库安装路径

看看本地的 /usr/lib/x86_64-linux-gnu/ 路径下是否有 libprotobuf-dev 的库

fig. 12 libprotobuf-dev 本地库路径

在本地的 /usr/lib/x86_64-linux-gnu/ 路径下确实还有个 libprotobuf.so 库。那么基本可以确定是两个不同版本的库导致了头文件函数声明和库的实现不匹配的问题了。

/usr/local/lib 中库是之前旧的 libprotobuf 库

/usr/lib/x86_64-linux-gnu/ 中库是现在新的 libprotobuf 库

我们直接在图 fig.9 的 link.txt 文件中补充上新库路径,可能需要 sudo 权限:

fig. 13 在 link.txt 文件补充路径

再次编译,编译成功了!但是多了条警告:

在本地的 /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
fig. 16 导入路径

在终端里重新 source ~/.bashrc 文件

删除工程的 build 和 devel 文件夹,重新编译,编译成功了!

暴力的办法:

在 /usr/local/lib 目录下新建文件夹叫 "old_protobuf",把旧版本的 proto* 文件移动到这个文件夹中,然后再把 /usr/lib/x86_64-linux-gnu/ 中的 proto* 文件拷贝一份到 /usr/local/lib 目录下。

先屏蔽 ~/.bashrc 文件里补充路径的指令

删除工程的 build 和 devel 文件夹,重新编译,编译成功了!

fig. 17 暴力的解决办法编译成功

小结

docker 容器是要好东西,隔绝环境,希望每个做工程的人都用上 :)

一个好的习惯是写文件记录安装的软件,方便排查问题,也方便以后做 docker 容器。

  • 24
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值