如何在编译时检测全局FTS64定义并验证FTS兼容性?
问题背景与需求
我正在基于老旧头文件进行项目构建,同时要使用新特性并配合各类运行时检查。当前核心需求是:在编译时断言<fts.h>(即/usr/include/fts.h)中定义的FTS和FTS64结构体具备二进制兼容性——也就是在64位平台上,二者的接口调用可以完全等价。
具体限制和要求:
- 必须适配早于1994年GNU C库版权声明的古老头文件,这类头文件完全未定义
FTS64 - 在使用新头文件或新平台构建时,需要编译器触发
static_assert,以便平台变更时重新验证代码是否需要调整 - 无法通过简单的类型存在性断言实现,也没有与
FTS64结构体及fts64_open()等相关方法同步推出的#define宏用于条件判断,因此需要能检测FTS64结构体或相关函数是否已声明的机制,进而控制static_assert的启用
当前实现方案
我目前想到的可行方案是通过三层嵌套命名空间,强制重新包含头文件来实现检测:
#include <fts.h> namespace outer { typedef FTS FTS64; namespace middle { enum {FTS}; namespace inner { #undef _FTS_H #undef __BEGIN_DECLS // 确实够丑陋,但暂时没别的办法 #define __BEGIN_DECLS #undef __END_DECLS #define __END_DECLS #include <fts.h> static_assert(sizeof(::FTS)==sizeof(FTS) , "疑似<fts.h>未被重新加载?") static_assert(sizeof(::FTS)==sizeof(FTS64) , "FTS64已定义,但与FTS结构体结构不兼容") // 还可以添加成员偏移检查... }; }; };
该方案的逻辑是:默认将FTS64定义为FTS的别名以确保断言通过,同时允许重新加载的头文件覆盖这个定义,进而触发兼容性检查。
不同环境的库符号对比
针对“glibc从未只存在fts”的质疑,以下是不同环境下objdump的输出:
旧环境
bash-4.1$ objdump -T /lib64/libc.so.6 | grep fts 00000000000ddc90 g DF .text 00000000000000d4 GLIBC_2.2.5 fts_close 00000000000dee40 g DF .text 000000000000056c GLIBC_2.2.5 fts_read 00000000000dd980 g DF .text 0000000000000024 GLIBC_2.2.5 fts_set 00000000000ddd70 g DF .text 00000000000005ab GLIBC_2.2.5 fts_open 00000000000dece0 g DF .text 0000000000000152 GLIBC_2.2.5 fts_children
新环境
[root@d6be84af3eb8 linux]# objdump -T /lib64/libc.so.6 | grep fts 00000000000f1880 w DF .text 0000000000000024 GLIBC_2.23 fts64_set 00000000000f18b0 w DF .text 0000000000000140 GLIBC_2.23 fts64_children 00000000000f0f20 w DF .text 0000000000000309 GLIBC_2.23 fts64_open 00000000000f1230 g DF .text 00000000000000e8 GLIBC_2.2.5 fts_close 00000000000f1320 g DF .text 0000000000000553 GLIBC_2.2.5 fts_read 00000000000f1880 g DF .text 0000000000000024 GLIBC_2.2.5 fts_set 00000000000f0f20 g DF .text 0000000000000309 GLIBC_2.2.5 fts_open 00000000000f1320 w DF .text 0000000000000553 GLIBC_2.23 fts64_read 00000000000f18b0 g DF .text 0000000000000140 GLIBC_2.2.5 fts_children 00000000000f1230 w DF .text 00000000000000e8 GLIBC_2.23 fts64_close
寻求更优解
当前嵌套命名空间的方案已经可以正常工作,但我希望找到更简洁的实现方式,比如利用C++模板和using的技巧?另外使用autoconf也是可行方向。
注:<fts.h>是C头文件,但我用C开发,接受C或C方案;也欢迎使用C++11及以上特性的方案(尽管当前暂无法使用);C语言中虽无static_assert,但也可以接受类似的编译时错误生成技巧。
内容的提问来源于stack exchange,提问作者Gem Taylor
相关产品推荐
相关产品推荐

