Java JNI调用PJSIP加载so库报UnsatisfiedLinkError求助
问题根因
这个报错和JNI语法本身无关,是Linux动态链接器的加载机制导致的:你用System.load()指定绝对路径加载libpjsua2.so时,JVM只会按你给的路径加载这一个文件,后续加载这个库依赖的其他子库时,会走系统默认的动态库搜索规则,不会自动把/usr/local/lib这类目录纳入搜索范围。你手动执行ldd能看到所有依赖路径,是因为你当前shell环境的动态搜索路径配置和JVM运行时的配置不一致,所以递归加载到libpjsip-ua.so.2的时候就会抛出文件不存在的错误。
参考文档
- PJSIP官方Java绑定(pjsua2 JNI层)的编译、部署说明,直接查看PJSIP源码包内
pjsip-apps/src/swig/java路径下的README文档,这是官方维护的全平台(Windows DLL/Linux so/macOS dylib)编译指南,没有第三方内容的错漏。 - JNI的官方规范直接对应Oracle JDK自带的JNI说明文档,里面明确标注了
System.load/System.loadLibrary的搜索逻辑、依赖加载规则,是JNI开发的权威参考。
修复方案
- 方案1:临时生效(开发调试用)
启动Java程序前先配置当前终端的动态库搜索路径,执行以下命令:
配置完成后再执行Java主类即可,这个配置仅对当前终端会话生效。export LD_LIBRARY_PATH=/usr/local/lib:/home/sip:$LD_LIBRARY_PATH - 方案2:永久生效(服务器部署用)
把PJSIP库所在路径写入系统动态库配置,执行以下命令:
执行完会刷新系统动态链接器缓存,之后所有用户启动Java程序都能正常搜索到PJSIP的依赖库。echo "/usr/local/lib" | sudo tee /etc/ld.so.conf.d/pjsip.conf sudo ldconfig - 方案3:不修改系统配置(应用打包分发用)
把ldd结果里所有/usr/local/lib路径下的PJSIP相关so文件全部拷贝到/home/sip/目录下,然后在Java代码的static块里按依赖层级从底层到上层依次加载所有库,最后再加载JNI封装层libpjsua2.so,示例代码:public class Main { static { try { // 从最底层依赖开始加载 System.load("/home/sip/libpj.so.2"); System.load("/home/sip/libpjlib-util.so.2"); System.load("/home/sip/libpjnath.so.2"); System.load("/home/sip/libpjmedia.so.2"); System.load("/home/sip/libpjmedia-audiodev.so.2"); System.load("/home/sip/libpjmedia-codec.so.2"); System.load("/home/sip/libsrtp.so.2"); System.load("/home/sip/libresample.so.2"); System.load("/home/sip/libspeex.so.2"); System.load("/home/sip/libwebrtc.so.2"); System.load("/home/sip/libgsmcodec.so.2"); System.load("/home/sip/libilbccodec.so.2"); System.load("/home/sip/libpjsip.so.2"); System.load("/home/sip/libpjsip-ua.so.2"); System.load("/home/sip/libpjsip-simple.so.2"); System.load("/home/sip/libpjsua.so.2"); // 最后加载JNI适配库 System.load("/home/sip/libpjsua2.so"); System.out.println("Loaded"); } catch (UnsatisfiedLinkError e) { System.err.println("Native code library failed to load.\n" + e); System.exit(1); } } public static void main(String argv[]) { Call call = new Call(null, 0); System.out.println("this is call: "+call); } }
注意事项
- 你代码里加载的
libpjsua2.so是SWIG生成的JNI封装层,不是PJSIP核心库,它本身依赖整套PJSIP核心so文件,缺任意一个依赖都会报链接错误。 - 后续编译Windows平台DLL时逻辑完全一致:要么把所有PJSIP依赖的DLL放到jar包同目录,要么把DLL所在路径加入系统PATH环境变量,要么在Java代码里按依赖顺序手动加载所有DLL,不然一样会抛出找不到依赖的错误。
- 编译JNI库的时候必须保证Java版本、PJSIP版本、CPU架构(32/64位)和运行环境完全匹配,不然即使路径配置正确,也会报符号找不到、架构不匹配的加载错误。
内容的提问来源于stack exchange,提问作者AHM200
相关产品推荐
相关产品推荐

