ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

libfastcommon 1.0.7 编译安装避坑:FastDFS 依赖与动态链接指南

libfastcommon 1.0.7 编译安装避坑:FastDFS 依赖与动态链接指南 简介libfastcommon-1.0.7.tar.gz 是 FastDFS 分布式存储系统中不可或缺的基础库源码包为 FastDFS 的稳定运行提供底层支撑面向需要编译安装 FastDFS 5.05 或深入学习其实现细节的开发者与运维人员。压缩包共54个文件骨架由24个 .h 头文件和22个 .c 实现文件构成并附带 make.sh、Makefile.in 构建脚本、说明文档、历史版本记录等辅助文件整体大小仅94KB轻量精简非常便于下载后直接查看源码结构。目前已有565人学习下载属于搭建 FastDFS 环境时的高频依赖资源。版本为1.0.7稳定版覆盖字符串处理、内存池、日志系统、网络通信、线程与锁、时间日期、哈希算法及配置文件解析等核心功能既能通过标准编译流程生成动态库并集成到 FastDFS也可作为研读分布式系统底层库设计的优秀范例帮助理解各功能模块的协作方式为二次开发和疑难排查提供具体参考。1. libfastcommon 1.0.7 是什么FastDFS 编译链条上最容易被忽略的一环如果你动手从源码编译过 FastDFS大概率碰到过这种画面./make.sh跑了一半报fatal error: common_define.h: No such file or directory或者链接阶段提示cannot find -lfastcommon。而正在背后提供这些头文件和函数库的就是 libfastcommon 这个公共基础库。我最初拿到 libfastcommon-1.0.7.tar.gz 时也以为它只是个“附属品”后来才意识到Tracker、Storage、客户端、fdfs_test 等等几乎所有 FastDFS 组件的二进制都会链接它。这个只有几十个源文件的库承担了配置解析、日志、哈希表、内存池、定时调度这些脏活。适合谁如果你是打算自己编译 FastDFS、排查启动时加载失败、或者想在 C 程序里复用这些底层工具的人这份资源值得先拆开看。2. 编译安装 libfastcommon 1.0.7make.sh 这条命令背后的依赖逻辑2.1 为什么先装 libfastcommon 再编 FastDFSFastDFS 在早期版本里把这些公共代码散落在各个组件中后来作者把它们抽成一个独立仓库。从 FastDFS 5.0 开始源码包默认不带common_define.h这类头部而是让外部提供一个已经安装好的基础库。我见过不少人直接在 FastDFS 目录里make结果卡在#include fastcommon/ini_parser.h上就是因为系统里没有 libfastcommon 的头文件。它本质上就是一个前置依赖类似编译 Nginx 前装 PCRE。理解这一点后安装顺序就明确了先./make.sh生成.so再./make.sh install把头文件放到/usr/include/fastcommon最后才轮到 FastDFS 主程序。2.2 我的安装步骤从 tar 到 ldconfig我手上这份是 1.0.7 的 tar.gz 包解压以后没有 configure只有 make.sh 和一堆.c/.h。直接执行tar -zxvf libfastcommon-1.0.7.tar.gz cd libfastcommon-1.0.7 chmod x make.sh ./make.sh ./make.sh install这段脚本会动态检测当前编译环境。在 64 位 Linux 上它默认把libfastcommon.so.1.0.7装到/usr/lib6432 位环境则落到/usr/lib。同时会在同目录下生成软链接libfastcommon.so.1.0.7和libfastcommon.so。前者是运行时加载用的真实文件后者是给编译链接器找的不带版本号。头文件则统一复制到/usr/include/fastcommon下。如果遇到权限问题就改成sudo ./make.sh install。注意这个版本的 make.sh 没有提供PREFIX参数安装路径写死为/usr。如果你非要装到自定义目录得去改脚本里的BASE_INCLUDE_PATH和LIB_PATH。我不建议这么干因为 FastDFS 自己的 make.sh 默认也从标准路径找头文件乱改只会让你后面的编译参数越加越多最后变成一套只有你自己能跑的构建。2.3 安装后的目录结构与版本验证装完以后我习惯先确认三个位置ls -l /usr/lib64/libfastcommon* ls -l /usr/include/fastcommon/ | head ldconfig -p | grep fastcommonldconfig -p能看到解释器缓存的.so记录如果这里没有输出说明安装位置没有被动态链接器识别。通常需要执行ldconfig刷新缓存。这个步骤经常被省略导致后面 FastDFS 编译好了但一运行就报cannot open shared object file。我一般顺手执行ldconfig -v | grep fastcommon看缓存结果再拿一个小 C 测试文件#include fastcommon/ini_parser.h编译一下确认头文件路径没问题。此外1.0.7 版本编出来的是带版本号的.so而不是常见的.so.1结尾。这个细节后面排查时会用到。如果/usr/lib64下只有.so.1.0.7而没有.so软链接链接器依然会失败因为 ld 搜索的是libfastcommon.so。这种情况在部分发行版上发生过我一般手动补一条软链接。2.4 发行版差异lib64 与 lib动态库和静态库libfastcommon 的 make.sh 在判断库目录时依赖uname -m的结果。如果你的系统是 x86_64但某些定制发行版没把/usr/lib64加入默认库搜索路径运行ldconfig -p就会看不到刚装的库。我遇到过一次性把libfastcommon.so.1.0.7装到了/usr/lib64但ldconfig缓存里只有/usr/lib的情况。解决方法是写一个单独的.conf文件而不是改动/etc/ld.so.conf里原有的内容。这样以后卸载也方便。另外make.sh 默认生成动态库。有些场景你想静态链接避免运行时找库但 libfastcommon 1.0.7 的 make.sh 不会自动生成.a除非你手动改gcc -shared为ar rcs。我不建议这样搞因为 FastDFS 本身依赖动态链接你静态链接反而会出现两个符号版本冲突。如果实在要静态优先选官方新版。3. 和 FastDFS 版本怎么匹配tracker/storage 对 libfastcommon 的真实依赖3.1 libfastcommon 在 FastDFS 里的运行边界libfastcommon 并不直接处理文件上传逻辑它给的是底层基础件。举个具体例子FastDFS 的 tracker 在读取tracker.conf时实际调用的是 libfastcommon 里的iniLoadFromFilestorage 写日志用的是log_init和logInfo文件去重计算 MD5则依赖fast_md5_buffer。这些符号不是在 FastDFS 源码里实现的而是在编译期由动态链接器在libfastcommon.so中补全。所以你可以用nm -D查看 FastDFS 可执行文件里哪些符号是 undefined 的。我整理过一个简单关系表对应 1.0.7 与 FastDFS 5.x 的时代组件主要用到的 libfastcommon 模块fdfs_trackerdini 解析、logger、sched_thread、共享内存链fdfs_storagedini 解析、logger、hash_table、fast_md5、skip_listfdfs_test / clientini 解析、logger、连接池、字符串工具这个表说明任何你怀疑的启动崩溃或挂死只要日志能打出来基本说明 logger 初始化成功了如果连日志都不打多半是 ini 解析阶段就挂了。理解这条边界排查时就能少很多试错。3.2 版本匹配的几种组合与我的选择libfastcommon 1.0.7 是和 FastDFS 5.0.5、5.05 这一批同步发布的。如果你用新版本的 FastDFS 6.x再拿 1.0.7 去搭编译可能能过但运行时大概率出现undefined symbol报错因为新版 FastDFS 依赖了 1.0.7 里还没有的新函数。反过来用最新的 libfastcommon 去编译旧 FastDFS 也可能会有头文件变更问题。所以我的选择很简单下载 FastDFS 源码看它src/version.h里FASTDFS_RELEASE_VERSION再对照 libfastcommon 的发布节奏。最保守的做法是让两者同一次发布。检查当前系统里 libfastcommon 实际版本可以读符号nm -D /usr/lib64/libfastcommon.so | grep fast_md5这能确认某接口是否存在于当前.so比看文件名里的版本号更靠谱因为有时候软链接会指错目标。我在一台生产服务器上就见过/usr/lib64/libfastcommon.so指向了旧版而文件名看起来还是新的最终靠nm才定位到问题。3.3 编译 FastDFS 时头文件和链接参数怎么对正常安装到/usr下时FastDFS 的make.sh已经写好了-I/usr/include和-L/usr/lib64你基本不需要额外加参数。但有两个点要留意。第一如果 libfastcommon 安装在/usr/local/lib那么 FastDFS 的 make.sh 是找不到的。我一般会在执行 make.sh 前先导出环境变量export CFLAGS-I/usr/local/include export LDFLAGS-L/usr/local/lib -lfastcommon ./make.sh注意-lfastcommon必须出现在链接阶段单纯给LDFLAGS加-L不够。FastDFS 的 make.sh 会把-lfastcommon硬编码到每个二进制目标里但有些分支或自定义模块不会带所以我在自己的项目里都是把-lfastcommon写在源文件对应的 Makefile 目标末尾。第二头文件和库的位数必须一致。32 位 FastDFS 配 64 位 libfastcommon编译会报skipping incompatible警告然后要么链接失败要么链接成功但运行崩溃。我通常用file /usr/lib64/libfastcommon.so确认是 ELF 64-bit再检查目标机的内核架构避免这种低级翻车。4. 避坑/常见问题链接失败、头文件缺失、运行时加载不上的五个现场这一章我按自己的经历列五个最常见的现场每个都按“现象 → 原因 → 解决”来说。现场一make.sh 一跑就报gcc: command not found现象./make.sh立刻退出看不到任何 C 源码编译信息。原因系统是精简安装没有 gcc 编译器或者只有 cc 但没有 gcc 命令。解决在 CentOS 系执行yum install -y gcc makeDebian/Ubuntu 用apt-get install -y gcc make。安装完重新执行./make.sh。注意 libfastcommon 1.0.7 还需要make别只装 gcc。现场二编译自己的程序时#include fastcommon/ini_parser.h找不到现象fatal error: fastcommon/ini_parser.h: No such file or directory。原因头文件没被make install复制到/usr/include/fastcommon。有时你只跑了./make.sh生成.so但没有执行第二步./make.sh install。解决回到 libfastcommon 目录执行make install或者直接看/usr/include/fastcommon是否存在。如果装到了非标准路径用find / -name ini_parser.h找到然后把对应 include 目录加到CFLAGS。这个坑在我自己写 C 工具时踩过两次都是因为懒少跑了 install。现场三链接阶段报cannot find -lfastcommon现象FastDFS 或自己的 C 程序在最后gcc ... -o时提示找不到库。原因/usr/lib64下只有libfastcommon.so.1.0.7没有libfastcommon.so这个软链接。链接器找的是不带版本号的.so而不是带版本号的。解决手动补软链接ln -s /usr/lib64/libfastcommon.so.1.0.7 /usr/lib64/libfastcommon.so然后重新链接。这个软链接正常应该是make.sh install时自动创建的但有时候因为目录权限或旧版本残留会导致没有创建或指向错误。现场四运行时提示cannot open shared object file: No such file or directory现象FastDFS 的 fdfs_trackerd 编译成功但启动瞬间报错ldd fdfs_trackerd显示libfastcommon.so.1.0.7 not found。原因动态链接器缓存里没有/usr/lib64或者刚安装完还没执行ldconfig。另一种情况是链接的文件名与.so版本号不一致。解决把/usr/lib64写入/etc/ld.so.conf.d/libfastcommon.conf然后执行ldconfig。再用ldd fdfs_trackerd | grep fastcommon确认显示的是绝对路径而不是not found。我遇到过一次是因为系统有多个 libfastcommonld 缓存指向了另一个版本导致启动后行为诡异。现场五FastDFS 启动只打一行日志就崩报undefined symbol现象./fdfs_trackerd /etc/fdfs/tracker.conf时控制台或日志文件里出现undefined symbol: iniGetStr之类。原因FastDFS 源码编译时链接的是新版 libfastcommon但运行时实际加载了旧版 1.0.7旧版没有这个符号。这就是典型的版本不匹配编译期和运行期指向了不同.so。解决先用ldd fdfs_trackerd | grep fastcommon确认运行时加载的是哪个文件再用nm -D 那个文件查是否有报错中的符号。如果没有说明库太旧如果有说明需要清理其他路径的旧库。最彻底的办法是把 FastDFS 和 libfastcommon 放到同一版本重新编译一遍并且清掉/usr/local/lib里可能存在的陈旧副本避免搜索路径抢占。这几条是我实际踩过的坑尤其是软链接和 ldconfig 这两个几乎每次换机器都会遇到一次。建议你在编译前先把ldconfig -p | grep fastcommon看一遍别等到运行才查。5. 把 libfastcommon 当独立工具库用ini 解析与 md5 调用的最小示例5.1 用 ini 解析读一遍配置既然是基础库它完全可以脱离 FastDFS 单独用。比如我写后台守护进程直接用它的 ini 解析比自己写一行行 split 省很多事。下面是最小可用的 C 代码#include stdio.h #include fastcommon/ini_parser.h int main(void) { IniContext ctx; if (iniLoadFromFile(server.conf, ctx) ! 0) { fprintf(stderr, load ini fail\n); return 1; } const char *addr iniGetStr(server, listen, ctx); int port iniGetInt(server, port, ctx, 8080); printf(addr%s port%d\n, addr, port); iniFreeContext(ctx); return 0; }这段代码里iniLoadFromFile把文件内容解析进IniContext第二个iniGetStr传的是 section 和 key最后必须iniFreeContext释放申请的内存。iniGetInt的最后一个参数是默认值键不存在时返回它。libfastcommon 的 ini 解析支持注释和字符串不需要手工处理换行细节这一点比很多自写的解析器稳定。5.2 顺手用它算文件 MD5文件去重或验证完整性时fast_md5 模块可以直接调用#include stdio.h #include fastcommon/fast_md5.h int main(void) { char md5[33] {0}; int rc fast_md5_buffer(hello, 5, md5); printf(md5%s rc%d\n, md5, rc); return 0; }fast_md5_buffer的第一个参数是缓冲区指针第二个是长度第三个是接收 32 位十六进制字符串的数组。注意它输出的是小写字母而且不包含结尾的\n如果需要保存到文件再比对建议直接拷到char[33]里。我一般只在编译验证和服务启动检查时用这些工具函数真正的业务里还是要按项目规范做二次封装。直到现在我每次在新机器上编译 FastDFS都会强制走一遍相同的清单先装 gcc再装 libfastcommonldconfig确认.so存在最后才碰 FastDFS 源码。这个习惯就是从被 undefined symbol 折腾了几小时后养成的。希望帮到你。本文还有配套的精品资源点击获取
返回列表