必须加 -fPIC,否则报 relocation 错误;-fPIC 生成位置无关代码供动态库加载时重定位;编译需 -c -fPIC 生成 .o,再用 -shared 链接;必须指定 --sysroot 或 -I/-L,否则头文件和库路径错误;运行时推荐 -Wl,-rpath,'$ORIGIN' 而非 LD_LIBRARY_PATH。

交叉编译动态库必须加 -fPIC
不加 -fPIC 会直接报错:relocation R_ARM_MOVW_ABS_NC against `a local symbol' can not be used when making a shared object(ARM)或类似 invalid operation for shared object(x86_64)。这是因为动态库在加载时地址不确定,所有代码必须能被重定位到任意内存位置。
-fPIC 生成位置无关代码,而 -fpic 在某些架构(如 ARM)上受限更严、可能失败,所以统一用 -fPIC 更稳妥。
- 编译源文件时必须带 -fPIC:
arm-linux-gnueabihf-gcc -c -fPIC libsrc.c -o libsrc.o
- 即使只有一个源文件,也不能跳过 -c 和 -fPIC 直接 -shared
- 如果用了多个 .c 文件,每个都要先编译成 .o,再统一链接
-shared 是链接动态库的关键开关
-shared 告诉链接器生成 .so 文件,而不是可执行文件或静态库。它必须和 -fPIC 配合使用,单独用会失败。
- 正确命令:
arm-linux-gnueabihf-gcc -shared -Wl,-soname,libmylib.so.1 -o libmylib.so.1.0 libsrc.o
- -Wl,-soname,xxx 设置运行时 SONAME,影响 ldd 输出和动态链接器查找逻辑
- 不加 -soname 会导致后续版本升级困难,且 ldconfig 无法正确管理符号链接
- 输出文件名(如 libmylib.so.1.0)和 -soname(如 libmylib.so.1)通常不同,前者是实际文件,后者是运行时链接名
目标平台头文件和库路径必须显式指定
交叉编译器默认只查本机系统路径(如/usr/include),不是目标平台的。不指定就会报 fatal error: xxx.h: No such file or directory。
- 用 -I 指向目标平台的头文件目录:
-I/opt/sysroot/usr/include(假设 sysroot 路径为 /opt/sysroot)
- 用 --sysroot 更彻底(推荐):
arm-linux-gnueabihf-gcc --sysroot=/opt/sysroot -fPIC -c libsrc.c -o libsrc.o
它自动把 --sysroot 下的 include 和 lib 加入搜索路径
- 若依赖第三方库(如 OpenSSL),需确保其头文件和 .a/.so 也在 --sysroot 内,否则链接阶段报 undefined reference to `XXX'运行时找不到动态库?别只改 LD_LIBRARY_PATH
交叉编译出的 .so 放到目标设备后,./app 报 error while loading shared libraries: libmylib.so.1: cannot open shared object file 很常见。
- 先确认目标设备上 ldd ./app 显示的路径是否真实存在
- LD_LIBRARY_PATH 是临时方案,重启失效,且易污染环境
- 更可靠的是在链接时用 -rpath:
-Wl,-rpath,/usr/local/lib 或 -Wl,-rpath,\$ORIGIN/../lib(相对路径)
- 还可修改 DT_RUNPATH:
arm-linux-gnueabihf-gcc -shared -Wl,-rpath,'$ORIGIN' -o libmylib.so.1.0 libsrc.o
这样程序运行时就在自身所在目录找库,无需设环境变量
- 注意:单引号包裹 $ORIGIN,避免 shell 提前展开
交叉编译动态库真正卡住人的地方,往往不是语法,而是头文件路径没对上、--sysroot 没配全、或者 -rpath 里写了绝对路径却忘了目标设备上根本不存在那个目录。


















