有台宝塔机,申请 SSL 证书的时候,报了这么一句:
curl: undefined symbol: curl_global_trace第一反应是 curl 坏了。可 curl -V 一看,版本号好端端的;命令行手动 curl https://... 也拉得下来,唯独进宝塔申请证书走不通。回头看,这种「读出来正常、跑起来不对」的毛病,多半跟版本没关系,跟它到底加载了哪一份库有关系。
光看 curl -V 是看不出来的,得看动态链接实际命中的是谁:
ldd $(which curl) | grep libcurl
ldconfig -p | grep libcurl这一看就露馅了:缓存里命中的是 /usr/local/lib 下的一份 7.64.1,而系统自带的 curl 明明是 8.5.0。旧库里根本没有 curl_global_trace 这个符号——它是 8.x 才加进来的。于是符号找不到,「未定义」。

那阵子我想当然地以为,把那份旧库改名成 .bak 就完了。结果没用。绕了一圈才弄明白:ldconfig 认的是库内部的 soname,不是文件名。你把文件叫成什么它不管,内部 soname 还叫 libcurl.so.4,缓存照样把它当 libcurl。删软链也不行——ldconfig 会照着 soname 再把软链重建回来。
正解只有一个:把这份旧库整个挪出 /usr/local/lib,换到别的目录,再跑一次 ldconfig 刷新缓存。让它彻底不在搜索路径里出现,问题当场就好。
回头总结几条:
- 链接层的问题别猜,先把
ldd+ldconfig -p的实际加载路径摆出来,比对着猜版本快得多; - 两个同名库抢位置时,身份是 soname 说了算,改文件名、删软链都是自欺欺人;
- 一台机器上能冒出两套 libcurl,多半是以前编译装东西留下的尾巴——当时把临时库清干净,就能省掉今天这一整出。
这类「同一条命令、两个版本读出两个结果」的事,我之前也写过一起,那条防火墙规则用 netsh 和 PowerShell 读出来的名字对不上(那篇在这);还有磁盘挂载「看着在、其实是空的」,根子也是一行 fstab 写错了盘名(那篇)。套路都一样:别信印象,去看实际值。
这台机器的排查过程,我也发在了论坛:宝塔申请 SSL 报 curl 符号缺失,一份旧 libcurl 残留惹的祸。
机器一多,这种库层问题最烦——一台台上去 ldd,光登录就够呛。平时我会用七亿批量远程管理工具(RdpManager)把一批机器批量连上去看,省掉反复登录那步;但库冲突这种事,输出还是得一台台对。日常拿不准的地方,官网那份说明书里运维相关的部分可以对着查。用七亿批量远程管理工具管机器的,碰上「命令能跑、结果不对」,也可以先按这个思路看一眼它到底加载了什么——这也是七亿批量远程管理工具这类批量运维里,最容易被跳过的一层。
评论