Scala JNI 问题汇总

由于需要设计一个自动的对Scala和Java项目打包生成的可执行的Jar加密的方案,而加密过程是使用C语言所写,而加密打包Docker镜像的过程又在Scala语言的项目里,因此需要使用JNI的技术调用动态链接库里边的函数。

在实现的过程中,由于开发设备是Mac系统,而需要打包加密解密的过程是在Linux系统上运行,所以最终都是以Linux为目标系统进行编译和测试,Scala语言没有明显的系统差异,而使用C语言所写的加密解密的动态链接库是需要编译为目标操作系统格式的,因此整个项目的测试过程都是在Docker镜像中完成,而我们的镜像又是基于Alpine做的极小镜像,在稳定版3.9的系统中又缺少某些必要的lib, 因此出现了很多问题。

好在最终测试完成后,编译、加密、打包的过程和真正运行所依赖的容器基础配置相同,不用担心出现依赖的动态链接库不是编译时依赖的某个具体版本,不需要根据客户环境重新调整的。

Header文件的生成

这一步是一切的基础,一定要先设计好Class的定义再生成对应的.h文件,如果Class做过修改,要重新生成,否则无法调用。不管是Java语言还是Scala语言都可以通过javah 来生成header文件,但是Java 8之后的版本可以直接在javac 编译的过程中同时生成header文件。当时因为第一次生成的Header文件是从Java Class中编译出来的,后来想直接使用该文件在Scala语言中调用native 的实现,结果出现了一些Link不满足的问题。

Scala语言在什么位置加载该JNI类具体的实现

一开始简单的认为动态链接库的加载在任何地方都行,只要在Class的加载之前使用System.loadLibrary 即可,所以一开始将加载类库的调用放在了Scala class的伴生对象中,这个Class就是对应JNI的实现的那个类。然而这样并不起作用,最后还是放到了启动的Main class中。

为什么会出现unsatisfied link的错误,具体是哪里不满足要求

编译生成的.h文件里边的方法signature里边包含了方法的参数、返回类型、包名、类名、方法名,任意一个对应不上就会出现以上错误,前面说过因为是后期实现的Scala的Class 通过@native annotation来对应JNI的实现,可是忽略了包名的对应,以为只是需要类名和方法相关的参数完全对应就可以了,实际上重新通过Javah生成的方法签名,发现最终的方法名里边包含了这个类完整的包名、类名和方法名,中间通过下划线连接,比如com_kongming_license_JarEncrypt_encrypt(),这样才能够满足JNI所load的方法和class中的native方法之间的对应。

动态链接库所依赖的lib版本不匹配的问题

动态链接库libxxx.so.x.不存在的问题由于Docker环境的统一性,已经不存在了。最初希望使用本地Linux系统直接编译的lib应用到生产环境,在没有使用Docker的时候,在客户机上也需要安装这些对应版本的动态链接库,需要额外的部署工作,有一些麻烦。将具体的编译和加密所使用的环境和生产部署的环境统一避免了此类问题,但是同时带来了一些开发上的不便利性,最初是需要将代码放到某个具有和生产环境一样的远程服务器上进行编译,需要根据服务器的环境来修改cmakelist.txt 中的一些路径信息,比如所依赖的jdk的header的路径,脱离了服务器在本地反而无法正常编译,换来换取的比较麻烦,通过在本地的Docker镜像中进行编译解决了这个问题,再配合上vscode最新的remote workspace 环境对容器的支持,可以非常方便的在vscode中进行开发和编译,编译成的动态链接库直接可以在生产环境中使用。

Vscode remote workspace 的惊喜

前边提到过,进行C语言的开发时,所编译的动态链接库对target系统的不同需要进行不同的编译,不像JVM语言这种,一处编译可以处处运行。使用Mac系统进行开发距离真实的Linux环境还是有一些不同,会造成以上一些版本和header文件路径的差别的问题,而vscode对远程开发的支持非常完美的解决了这个问题,目前支持ssh、docker容器和WSL三种远程开发环境,在Mac上开发最简单的就是选择一个Docker的基础镜像,在此基础上build本地的docker镜像,本地的vscode连接到该镜像所生成的container中进行远程的开发、编译,和直接在本地开发没有太多区别,可以在container的vscode server中安装独立的插件,也可以打开新的terminal安装一些所缺少的工具、lib之类。这样既保证了开发生产环境的一致性,又能够像本地开发一样,避免了使用虚拟机等远程开发环境的不便利。

感觉以后可以直接在ipad pro上边写程序了,通过连接远程的容器或者linux服务器,随时随地写程序。

你可能感兴趣的:(Scala JNI 问题汇总)