C++动态库向前兼容的能力,真是一言难尽。

2023-01-17 09:48:13 +08:00
 tool2d
公司有个运行在外网的生产环境,是 linux 早期版本,本着只要代码能运行,就没人去动的原则,内核一直比较老。

然后我想加一点小功能,想着现在 clang 那么强大了,跨平台编译应该轻轻松松,然而测试结果让我大跌眼镜。

目前几乎所有的 clang 交叉编译环境,都是基于新版本的 GLIBC ,相当于 VC 的 Runtime Lib ,而这货竟然严重依赖于系统内核版本?测试了好几个打包编译器,都是顺利生成 ELF ,可运行报错,提示让先升级内核。

无奈,一点点换老款编译器,从 2022 年的 clang ,到 2020 年的 clang ,到 2012 年的 gcc, 再到 2007 年的 gcc ,最后一个终于运行成功!

硬着头皮,用最原始的编译器,写最炫酷的 2023 新代码。
7501 次点击
所在节点    C++
53 条回复
zunceng
2023-01-17 11:19:32 +08:00
正常的 c++ 只有代码能跨平台
geelaw
2023-01-17 11:21:39 +08:00
跨 DLL 请自觉 extern C 或者 COM
yolee599
2023-01-17 11:33:14 +08:00
编译器的锅关我 C++ 什么事?:doge:
yolee599
2023-01-17 11:43:19 +08:00
我用 gcc 编译过很多代码,从来没遇到过内核版本的问题,无论是 x86 项目,还是 arm 项目,都很顺利啊。OP 文中说的“交叉编译环境”,一般指在 x86 下编译 arm 的环境,这个你得用“交叉编译器”,还要配置好环境变量,指定到你这个交叉编译器
yolee599
2023-01-17 11:49:50 +08:00
交叉编译器一般使用 gcc ,除了 NDK ,我还没见过有什么项目使用 clang 作为交叉编译器
tool2d
2023-01-17 11:57:35 +08:00
@yolee599 CLANG 比想的要更强,我就是编译 NDK 时发现,改改 taget 就能跨平台编译,就让人感觉很舒适。

最近 CLang 又加了对 VS IDE 编译和调试支持,生成的 OBJ 可以无缝嵌入 VC2015-VC2022 编译器。于是,我就想 ALl in one 一把,让 CLANG 也支持生成 Linux ELF 。

结果还是太傻太天真了。
julyclyde
2023-01-17 13:29:01 +08:00
@ysc3839 正因为是运行时库,才依赖内核
C“语言本身”有啥可用库的……
maxxfire
2023-01-17 13:45:23 +08:00
没有什么是不能通过增加一层中间层来解决的问题,这个中间层可以理解为转换层、适配层。
具体技术可以是 函数指针,虚函数表,dlopen 等等,可以参考 COM 组件对象模型。
nmgwddj
2023-01-17 13:49:40 +08:00
目前跨平台项目编译问题我还是推荐使用 conan ,对于三方库的管理和编译工具链没有重度依赖。

我们现在工程 C++ 标准锁定在 14 ,Windows > MSVC15 (如果没有用一些较新的 API ,使用 7.0 SDK XP 都可以支持)、macOS 、iOS apple-clang > 12.4 ( macOS ARM64 支持) 以上、Android NDK21 clang9 以上、Linux GCC5 以上。GCC5 已经支持大部分 C++14 标准,如果是为了兼容一些 GCC5 没有支持的特性或者旧内核系统,可以考虑 GCC7+ glibc2.23 的 docker 镜像,这样 Ubuntu 16.04 都可以跑。

主流的 libevent 、openssl 、sqlite3 、libcurl 、zlib 、qt 等都验证编译通过。
icyalala
2023-01-17 14:15:15 +08:00
@wingkwanli888 包管理 vcpkg 、conan ,国内的 xmake 也可以试试。只是还是一言难尽。。
duke807
2023-01-17 14:25:19 +08:00
要查清楚是谁报内核太低这个错,就是谁的锅
weidaizi
2023-01-17 14:37:02 +08:00
@wingkwanli888 历史问题,如果依赖库的工程用的全是 cmake 的话,FetchContent 也是可以一把梭的
mingl0280
2023-01-17 16:27:28 +08:00
哈哈哈哈,跟我遇到的坑一模一样。
当然,新版 gcc 还有更坑的……我之前用 elf 编辑绕过了一下(就是去掉签名里面的 @版本),结果新版 gcc 加了几个 @@版本开头的隐藏函数( elf 编辑器里面根本找不着)直接干死了我试图绕过这个问题的方法……
zhyl
2023-01-17 16:46:00 +08:00
glibc 不能够静态链接的,换 musl 就行了
newmlp
2023-01-17 16:50:55 +08:00
这方面还是微软兼容性好,ntdll 从 xp 到 11 ,基本没什么问题
newmlp
2023-01-17 16:52:52 +08:00
@lhbc 微软 nt 就很容易,xp 到 11 ,兼容性杠杠的
ipwx
2023-01-17 17:22:41 +08:00
你遇到的大概是安全检查。如果没这个拦着你,等 syscall 行为不符合预期的时候,出 bug 你都不知道哪里死的。

怪就怪 Linux 内核 syscall 一直在升级 ( doge
icylogic
2023-01-17 17:28:57 +08:00
glibc 的兼容性,和 C++ 动态库的兼容性是两件事,而且这两点几乎都和 clang 没什么关系。你提到的这些问题,大部分锅是 glibc 的。

glibc 几乎很少有人需要最新版的特性,所以只要你去链最老的 glibc 就可以了,一般会推荐让你到所有目标平台中最老的那个去编译。glibc 就是唯一特殊的那个崽,不能静态链接。

c++ 你想用新的编译器、新的库(包括 std )是完全可以的,既可以静态链接(如果你能搞到静态库),也可以自己打包动态库(比如 /usr/lib/myapp/libxxx.so )然后设置 rpath 到 $ORIGIN 之类的,后者其实就是 Windows 那种一个 exe 带一堆 dll ( vcruntime140.dll, etc) 的风格。

这两点综合起来就是,比如你需要给 Ubuntu 18.04, 20.04, ... 这些平台提供支持,那你首先准备一台 Ubuntu18.04 的环境,然后通过 toolchain ppa 之类的东西安装或者编译一套新版的 g++/clang ,多新的都可以,只要你能在 18.04 上跑。最后用这套工具链去编译你的 app ,然后把所有依赖 (除了 glibc) 通过静态或者动态的东西打包带走。

这个你找台环境试一下就知道怎么回事了,比如尝试一下给一台默认 gcc 5.x 的环境编一个使用了 C++17 Filesystem 的应用。







你要是觉得麻烦就直接 docker 得了。
lhbc
2023-01-17 17:55:03 +08:00
@newmlp runtime 也是要装一堆的,还有 .net 也是 n 个版本
jworg
2023-01-17 18:10:45 +08:00
@icylogic 我那公司跑还是原生跑,不过特意准备了好几套不同的 linux 环境的容器然后在 docker 里面编译,配合 jenkins 分发到对应的服务器,都是当初运维偷懒没有升级,最后谁也不敢动,结果各种版本都有。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/909407

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX