如何部署一个混合的C++/Java(JNI)应用程序?

 2023-01-20    391  

问题描述

tl; dr:C ++插件需要致电Java .jar库.如何将其部署给没有太多头痛的用户?

我正在为QT应用程序编写QT插件.该插件需要拨打到现有的Java库.这需要工作跨平台(Win,Mac,Linux)和体系结构(32位和64位Intel,无PPC).

如何部署一个混合的C++/Java(JNI)应用程序?

我得到了一个简单的” Hello World” JNI示例编译和运行.我将cmake脚本更新为” find_package(jni criuns)”等.因此,它针对jni.h标题进行了编译,并针对JVM库动态链接.

至少在Windows上,Cmake在查找合适的JVM时做得很好.它在运行时发现了合适的JRE(JVM.DLL等),因为我对用户的计算机的控制权较少.

当我将插件发送给用户时,它将如何工作?他们将需要安装JRE来进行适当的体系结构.但这并不意味着JRE LIB目录(IES)将在他们的道路上.如果不是,则插件只是释放而不会加载.

在Windows上,64位JDK安装JVm.dll似乎也很麻烦:

C:\Program Files\Java\jre7\bin\server\jvm.dll

但是32位JDK将其安装到:

C:\Program Files (x86)\Java\jre7\bin\client\jvm.dll

我了解PF与PFX86的差异,但是我没有得到的服务器/客户端.这些实际上是不同的jres吗?

如果我已经针对一个JRE版本进行了编译/链接,并且用户具有不同的版本?

我认为这在Linux/Mac上都会更容易,但是我还没有走那么远.

任何帮助将不胜感激.我与使用JNI不匹配,但不能负担2000美元的编译器将Java变成本地代码库(无论如何我都有来源),而且我听说GCJ可能无法完成任务(也许可能是在Windows上无济于事).

推荐答案

仅适用于Windows的解决方案.

使用延迟的DLL加载功能构建QT插件

请参阅 delayloflow”> delaylload 为此,它只是将/DELAYLOAD:jvm.dll和Delayimp.lib添加到链接器命令中.这意味着在加载QT插件时不会加载jvm.dll,但在需要时(请注意,它 not 需要使用LoadLibrary()和GetProcAddress()). (我不知道Linux或Mac上是否有类似的功能)

提供了一种机制来告知QT插件的JRE

这可以是专门针对插件的注册表值,配置文件或环境变量(绝对不是环境变量JAVA_HOME或JRE_HOME其他应用程序可能依赖的).示例环境变量:

  • danqt_32_jre_home = c:\ program Files(x86)\ java \ jre7(对于32位JRE)
  • danqt_64_jre_home = C:\ Program Files \ Java \ Jre7(对于64位JRE)

QT插件修改其路径

在QT插件调用取决于JRE的任何函数之前,它会通过插入%DANQT_32_JRE_HOME%\bin\server;%DANQT_32_JRE_HOME%\bin\client;在PATH的值开始时修改其PATH环境变量.这意味着,当QT插件执行其第一个操作时,需要将JRE从插入的目录加载. (64位的不同环境变量).至于bin\client和bin\client我的理解是,这些基本相同,但出于运行时性能原因,server在初始化过程中执行更多.

如果安装了JRE 6和JRE 7的QT插件,我不确定兼容性.如果存在兼容性问题,则将其作为先决条件要求,或者,如果允许(我不确定合法性),请使用QT插件运送jvm.dll.

其他推荐答案

需要添加到 @HMJD的答案中的一些更详细的注释,其中很多细节使我绊倒了.

这是我用来编译和链接测试程序的命令行:

cl
  -I"C:\Program Files (x86)\Java\jdk1.7.0_02\include"
  -I"C:\Program Files (x86)\Java\jdk1.7.0_02\include\win32"
  /EHsc
  -MD
  Test.cpp
  jvm.lib
  delayimp.lib
  /link
  /LIBPATH:"C:\Program Files (x86)\Java\jdk1.7.0_02\lib"
  /DELAYLOAD:jvm.dll

要注意的几件事:

  1. 包括通往标头文件的路径(jni.h等)
  2. add /EHsc避免此警告:” C:\ Program Files(X86)\ Microsoft Visual Studio 10.0 \ VC \ Incluber \ Xlocale \ Xlocale(323):警告C4530:C ++例外处理程序使用,但未启用Undind Sensics .指定/ehsc”
  3. 仍然需要包括jvm.lib,即使应该延迟加载.
  4. delayimp.lib必须包括在内.
  5. /LIBPATH需要追随/link选项,以便链接器获取它.这是通往 .lib 文件的途径.
  6. /DELAYLOAD获取 .dll 文件,而不是.lib文件!如果您不小心将.lib文件提供给它,您将不会收到有用的错误消息,它只是说”链接:警告LNK4199:/delayload:jvm.lib忽略;从JVM.lib中找到未找到的导入”.

在.cpp文件中,#include “windows.h”,找出哪个目录具有jvm.dll,然后拨打这样的呼叫:

std::string temp = "C:\\Program Files (x86)\\Java\\jdk1.7.0_02\\jre\\bin\\client";
SetDllDirectory(temp.c_str());

在调用库中的任何函数之前就这样做,因此,当称为LoadLibrary()时,它就会知道在哪里找到DLL.另一种选择是用SetEnvironmentVariable()修改PATH变量,但SetDllDirectory()似乎是一个更好的选择.

在您的启动代码中的某个地方,添加这样的代码:

__try
{
  // call a function from the DLL to make sure it can be loaded
  ::JNI_CreateJavaVM(...);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
  // If not, fail
}

最好将其放在自己的功能中,因为__try/__except结构化异常处理(SEH)内容不忍受与可能会放松对象的代码共享函数.

没有SEH的内容,如果找不到DLL,该程序就会崩溃.

一些有用的链接:

  • http:http:http:http:http:http:http:http:http:http:http:http://mindcodeblog.wordpress.com/2011/09/23/link-with-with-a-delayload-library-with-vs2010-cmake/
  • .com/en-us/library/yx9zd12s%28V = vs.100%29.aspx
  • 用cmake
  • 打开链接旗

其他推荐答案

由于我无法在Linux上找到等同于/DELAYLOAD的等效物(在此处问:我如何使懒惰/延迟加载在linux中工作?),我使用dlopen()被卡住了. It’s not as bad as I thought it would be — I can use the technique described here: c ++ 中dlsym()和dlopen()的替代方案.实际上,似乎JNI.H标头是为此方法设计的.也许我首先也应该在窗户上做的事情.

以上所述是小编给大家介绍的如何部署一个混合的C++/Java(JNI)应用程序?,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对77isp云服务器技术网的支持!

原文链接:https://77isp.com/post/26003.html

=========================================

https://77isp.com/ 为 “云服务器技术网” 唯一官方服务平台,请勿相信其他任何渠道。