How can I deploy a mixed C++/Java (JNI) application?

前端 未结 3 397
执笔经年
执笔经年 2021-01-14 04:50

tl;dr: C++ plugin needs to call Java .jar library. How to deploy this to users without too much headache?

I\'m writing a Qt plugin for a Qt applica

3条回答
  •  遥遥无期
    2021-01-14 05:21

    Some more detailed notes to add to @hmjd's answer, a lot of these details tripped me up.

    This is the command line I used to compile and link a test program:

    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
    

    A few things to note:

    1. Include paths to the header files (jni.h, etc.)
    2. Add /EHsc to avoid this warning: "c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\INCLUDE\xlocale(323) : warning C4530: C++ exception handler used, but unwind semantics are not enabled. Specify /EHsc"
    3. Still need to include jvm.lib, even though it should be delay loaded.
    4. delayimp.lib has to be included.
    5. /LIBPATH needs to go after the /link option so the linker gets it. This is the path to the .lib file.
    6. /DELAYLOAD gets the .dll file, not the .lib file! If you accidentally give it the .lib file you don't get a useful error message, it just says "LINK : warning LNK4199: /DELAYLOAD:jvm.lib ignored; no imports found from jvm.lib".

    In the .cpp file, #include "windows.h", figure out which directory has the jvm.dll, and make a call such as this:

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

    Do that before calling any function from the library, so when LoadLibrary() is called it knows where to find the DLL. An alternative is to modify the PATH variable with SetEnvironmentVariable() but SetDllDirectory() seems like a better choice.

    Somewhere in your startup code, add code like this:

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

    Best to put that in its own function somewhere, since the __try/__except Structured Exception Handling (SEH) stuff doesn't tolerate sharing a function with code that might doing object unwinding.

    Without the SEH stuff, the program just crashes if the DLL can't be found.

    Some links that were helpful:

    • http://mindcodeblog.wordpress.com/2011/09/23/link-with-a-delayload-library-with-vs2010-cmake/
    • http://msdn.microsoft.com/en-us/library/yx9zd12s%28v=vs.100%29.aspx
    • Turning on linker flags with CMake

提交回复
热议问题