开发规范之动态库(使用与容易遗漏的部分)
一、为什么拷贝到/usr/lib必须加sudo?
1. 核心原因:/usr/lib是系统保护目录,普通用户没有写入权限
Linux 权限机制:
/usr/下面属于系统核心目录,存放系统自带软件、基础库、系统程序;- 默认只有root 超级用户才能新建、删除、修改里面的文件;
- 你当前登录的普通用户,执行
cp libxxx.so /usr/lib会直接报错:Permission denied(权限拒绝)。
sudo=superuser do,临时借用 root 管理员权限执行这一条拷贝命令,改完自动收回权限,防止普通用户乱删系统文件破坏系统。
2. 光sudo cp还不够,必须再加一步
sudo cp libadd.so /usr/lib sudo ldconfigLinux 不会每次运行程序遍历所有文件夹找库,而是靠缓存文件/etc/ld.so.cache快速查找;ldconfig就是刷新这个系统动态库缓存,把新放进/usr/lib的 so 录入系统索引,不然程序依旧提示找不到库。
二、那为什么非要丢进/usr/lib?根源是动态库运行时查找规则
静态库编译链接时直接打包进程序,运行不需要原.a文件;动态库只在编译时记录库名,程序运行时才去硬盘搜索.so文件,搜索优先级顺序:
- 编译时
-Wl,-rpath硬编码路径 - 环境变量
LD_LIBRARY_PATH /etc/ld.so.cache系统缓存(包含/usr/lib、/lib)- 兜底默认路径:
/lib、/usr/lib
把 so 放到/usr/lib,就是放进系统默认兜底搜索目录,任何终端、任何用户运行程序,系统都能自动找到库,不用额外配环境变量。
三、完全可以不用 sudo、不用往系统目录拷贝(三种更常用方案)
方案 1:临时环境变量(开发最常用,不用 sudo)
so 还在当前文件夹,执行:
export LD_LIBRARY_PATH=./:$LD_LIBRARY_PATH ./a.out仅当前终端窗口生效,关闭终端就失效,适合调试。
方案 2:编译时指定 rpath,永久绑定库路径
编译 main 时直接写死 so 所在文件夹:
gcc main.c -L. -ladd -Wl,-rpath=.生成的可执行文件自带查找路径,以后直接./a.out就能运行,全程不需要 sudo、不用移动 so 文件。
方案 3:添加自定义路径到系统缓存(推荐正规安装)
- 新建文件夹放库:
sudo mkdir /usr/local/mylib - 复制 so 进去:
cp libadd.so /usr/local/mylib(不用 sudo 也能写自定义目录) - 把路径写入系统配置:
echo "/usr/local/mylib" | sudo tee /etc/ld.so.conf.d/mylib.conf sudo ldconfig后续全局可用,也不会污染原生/usr/lib系统目录。
四、动静库在头文件、声明那套规则完全一致
.so只包含机器码 + 符号,绝不打包.h 头文件;- 库源码
add.c里#include "add.h"只是作者自检,防止声明实现不一致; - 使用者可以丢弃原头文件,自己新建任意命名
.h,只要函数签名匹配就能编译调用; - 结构体、宏、typedef 必须依赖作者提供的
.h,否则无法使用。
极简总结
sudo只是为了突破系统目录写入权限限制,不是动态库本身强制要求;- 放进
/usr/lib只是为了让系统默认路径能搜到 so,属于部署方式,不是唯一用法; - 日常写代码优先用
LD_LIBRARY_PATH或者-rpath,尽量少往/usr/lib塞自定义库,避免系统文件杂乱。