动态库尤其是共享库在 Linux 环境下普遍存在库文件名包含版本号的情况,比如 Linux 环境下经常会发现一个共享库的真实文件名是 libfoo.so.1.1.0,而同时会有多个指向该真实库文件的软连接短文件名:libfoo.so.1.1、libfoo.so.1、libfoo.so。那么我们在使用 GCC 开发程序时如果要用这样的共享库输出的函数,就需要到动态链接这样的共享库(我们这里不考虑静态链接的方式),那么和库文件就有很大关系。另一方面,JNA 中载入共享库,根据其文档我们一般都只使用库的短文件名,比如载入 libfoo.so,我们只需要在 JNA 中指定库文件名为 foo,那么针对真实的长库文件名,又当如何?
1、GCC 使用动态库/共享库
如果使用 GCC 开发程序需要用到共享库提供的函数,且采用动态链接该共享库的话,需要用到 -l 参数。比如动态链接 libfoo.so 这个共享库,参数指定为 -lfoo。但是现实情况是,如果共享库的文件名是 libfoo.so.1.1.0 这样的,而且默认情况下没有 libfoo.so 的软连接,那么 -lfoo 这种方式会出错。所以,此时你可以手工创建一个软连接,用 libfoo.so 这样的不含版本号的共享库文件名指向实际的共享库文件,那么 -lfoo 参数执行时就不会出错了。这样生成的程序,在运行时,即使 libfoo.so 这样的软连接不存在,也不会有问题,会自动找到共享库并将其载入,因为在实际的共享库生成时,就已经在共享库内部指定了寻找共享库时所依赖的名称,有可能是 libfoo.so.1,也有可能是 libfoo.so.1.1……这个取决于共享库在创建时是如何指定唯一的库名称的。
2、GCC 生成动态库/共享库
这里只讨论使用 NetBeans 搭配 GCC 的开发情况。其实主要就是在于控制目标文件名的生成,对于 Linux、Windows 都是适用的。
3、JNA 使用动态库/共享库
JNA 是 Java 中取代 JNI 的最好实现。JNA 中载入动态库、共享库很简单,使用 Native.loadLibrary() 方法即可。根据 JNA 文档,Native.loadLibrary() 方法中指定库文件名一般都是短文件名,不需要含 .dll 以及 lib 和 .so 字符串,比如,Windows 环境下载入 foo.dll,则 Native.loadLibrary() 方法中的库文件名指定为 foo 即可;Linux 环境下载入 libfoo.so,则 Native.loadLibrary() 方法中的库文件名指定为 foo 即可。但是针对 GCC 生成的 libfoo.dll(Windows 环境下)以及 libfoo.so.1.1.0 这两种情况,JNA 文档并没有细说,只是提到 NativeLibrary 这个类的 getInstance() 方法可以指定上面的库短名称,也可以指定带版本号的长名称。后来测试发现,Native.loadLibrary() 方法也是支持库短名称和带版本号的长名称的,因为猜测 NativeLibrary.getInstance() 方法就是 Native 类内部使用的。同时测试还发现,Native.loadLibrary() 方法使用短名称时,能够自动侦测并适应库文件名是否有 lib 前缀以及是否带有版本号。比如,在 Windows 环境下,libfoo.dll 这种情况,使用 foo 作为短名称,JNA 也是能够自动识别并支持的。在 Linux 环境下,libfoo.so.1.1.0 这种情况,使用 foo 作为短名称,JNA 也能够自动识别并支持。当然,你使用完整的长文件名也没有问题。