manjaro 官方包没有静态库,是出于什么考虑?

2018-11-24 11:39:19 +08:00
 catror

最近把工作机的 ubuntu 换成了 manjaro,但是发现官方的包里没有静态库,不是很方便。

2567 次点击
所在节点    Linux
15 条回复
catror
2018-11-24 11:40:10 +08:00
可能应该问 arch 是出于什么考虑?
AEANWspPmj3FUhDc
2018-11-24 11:59:45 +08:00
Linux 不都是用的动态库吗?
catror
2018-11-24 12:36:13 +08:00
@ivlioioilvi 有些项目为了部署方便,链接的是静态库。
iwtbauh
2018-11-27 15:42:33 +08:00
节省硬盘空间,提升系统更新、安装速度。

毕竟讲真,装静态库真的是几乎用不到,白白浪费系统空间。我就很不喜欢 Debian 把静态库动态库放一个包里面。

如果你的项目要静态连接个什么东西吧,拿 openssl 举例,正确做法不应该是编译 openssl 吗,难道用系统的 .a ?
iwtbauh
2018-11-27 15:43:58 +08:00
@iwtbauh #4

说错了,是把静态库也塞到 libxxx-dev 包里面,99%的情况下只需要.h,.pc 等
catror
2018-11-27 17:37:41 +08:00
@iwtbauh 系统里有的话当然用系统的. a,何必再费力去找代码编译呢?不过已经改用 docker 来编译了。
iwtbauh
2018-11-27 18:59:16 +08:00
@catror

如果是为当前发行版编译安装软件,当然要用系统的 lib,而且当然动态链接更好,这个时候肯定选择动态链接(减少程序体积,利用 cow 机制提示程序运行速度和减少内存占用),静态库用不到

如果是编译出来想作为二进制向用户发行,我反正是不敢用某一个发行版的 .a,换一个发行版(甚至版本)就是一堆堆的坑,这个时候肯定从上游拿代码,定制编译选项(例如减少 .a 本身带来的依赖)编译

所以往系统里装静态库真的是个糟主意
catror
2018-11-27 19:43:05 +08:00
@iwtbauh 😂谢谢回复,我大致描述一下自己发这个贴的情况:
1. 已有的项目(不存在向用户发行,运行环境也不是 manjaro),为了部署方便,里面有大量的静态库链接
2. 我换用了 manjaro 系统,想直接本地调试,编译时提示找不到静态库
3. 进而发现 manjaro 的包没有静态库
4. 网上搜了一圈没什么人讨论这个问题(静态库确实是小众需求)
5. 发了这个贴
catror
2018-11-27 19:47:52 +08:00
@iwtbauh
另外,内存或者磁盘空间早就不是什么问题了,看看现在 go 语言和 rust 生成可执行文件的方案,根本不怎么考虑这些。
真的有程序要向用户发行的话,还是每个发行版编译一次保险,实在懒就用 appimage。
关于你说的运行速度那点,静态链接比不上动态链接?愿闻其详
catror
2018-11-27 19:50:45 +08:00
@iwtbauh 噢,另外我要本地调试自己修改链接项为动态库也行,但就是懒,而且临时修改有时候不注意就上库了。
iwtbauh
2018-11-27 20:34:37 +08:00
@catror #9

像 steam、nvidia 闭源驱动、oracle jdk 等等软件,你会发现他们发布的二进制文件能在几乎所有的现代发行版上运行!其实就是尽量避免对发行版的库依赖实现的。但是如果没有向用户分发二进制的需求时,就不用考虑这些乱七八糟的事情了。

制作纯静态 elf 时,无法使用 dlopen()系列的调用!这对需要制作需要运行时加载插件 elf 的程序是个灾难(虽然也有很脏的方法达到大致等价的效果),所以总是不应该制作纯静态 elf !这也是我为什么讨厌 golang。rust 则没有这个糟心的问题。

运行速度快我说的有歧义,我是指“程序启动时速度快”,你的 elf 依赖 a.so, b.so, c.so ,知名的库很可能早就由其他程序加载了,运行时肯定内核只需要从硬盘上加载你的 elf 即可(现代系统的写时复制机制)。如果你静态链接,这些“ so 的代码”(其实是.a 的代码)还得费劲给你从硬盘上加载到内存里,相当于白白重复做事,加载后还得进行重定位等“修剪”工作,这些 I/O 和修剪都是需要花费 CPU 时间去等待 /完成的。启动后的运行速度就不受影响了。但是启动时会慢,而且也会占用更多内存。(如果是动态链接,写时复制机制使 .so 在主存中只有 1 份)
catror
2018-11-27 22:14:30 +08:00
@iwtbauh 嗯,你说的这个动态库的加载机制我知道。其实静态库是没有经过链接的,可以就看做是.o 文件的合集,在链接成可执行文件的时候,符号都定位好了,你说的重定位也只发生在载入的时候。反而是动态库,可能存在延迟加载,延迟定位,会有性能上损失。至于代码重复,静态链接可以削减没有使用到的部分,不同程序可能使用到的部分并不同。至于插件,万不可能使用静态库,因为链接成可执行文件之后,库已经是可执行文件的一部分了。两种库的使用方式只能说各有优劣吧。
catror
2018-11-27 22:18:47 +08:00
@iwtbauh NVIDIA 的驱动没看过,stream 和 jdk 看过,为了灵活,他们里面有自己的 so。这些基本是只依赖系统的 libc 之类的基本库,appimage 其实也是这样。
iwtbauh
2018-11-28 00:54:20 +08:00
@catror #12

.a 是.o 的集合我知道,但是在二进制层次上裁剪静态库需要的部分然后只链接需要的部分真的安全吗,感觉这种做法有些 dirty hack 了,我没有见过这样做的例子。

延迟加载并不是问题,因为库代码本身无论如何都要加载到内存,然后重定位,无非是早是晚罢了。另一方面,延迟加载也可能在某些情况下避免加载一些库从而提升性能。由于 cow,加载到内存的过程也很可能免了,如果是静态库则还是需要重复加载代码然后重定位的。


#13

没错,但不静态链接实际上一部分是避免一些库的许可问题,另一部分是某些库静态链接会有坑(例如坑爹的全局变量符号可见性的问题)。通过 rpath 指定自己的库目录,其实实际上效果大致等价于静态链接了。
catror
2018-11-28 02:24:26 +08:00
@iwtbauh
裁剪静态库并不是 hack,gcc 编译的时候,默认的情况下,每个.o 文件一个代码段,链接时指定参数可以裁剪掉没有引用到的代码段。更进一步,可以在生成.o 文件时,指定参数,让每个函数独立一个代码段,那就可以做到函数级别的裁剪。
全局变量的问题,是因为静态库被重复链接了。通常是两个动态库用了同一个静态库,或者动态库和可执行文件用了同一个静态库。

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

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

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

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

© 2021 V2EX