Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support native code only usage of JVM #127

Open
jpphillips opened this issue May 1, 2023 · 8 comments
Open

Support native code only usage of JVM #127

jpphillips opened this issue May 1, 2023 · 8 comments
Labels
enhancement New feature or request
Milestone

Comments

@jpphillips
Copy link

jpphillips commented May 1, 2023

Here is what I have:

HelloWorld.java

package com.test;

public class HelloWorld {

    public void sayHello(String msg) {
        System.out.println("Hello from Java: " + msg);
    }
}

Compile it:

$ javac com/test/HelloWorld.java

The Google JNI-BIND C++ code:

#include "jni_bind_release.h"


// 1: Setup JNI Bind in your OnLoad call (needed only once).
std::unique_ptr < jni::JvmRef < jni::kDefaultJvm >> jvm;

extern "C" {
    JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM * pjvm, void * ) {
        jvm.reset(new jni::JvmRef < jni::kDefaultJvm > (pjvm));
        return JNI_VERSION_1_6;
    }
}

int main() {

    // 2: Define the class
    static constexpr jni::Class kClass {
        "com.test.HelloWorld",
        jni::Method {
            "sayHello",
            jni::Return < void > {},
            jni::Params < jstring > {}
        }
    };

    // 3: Use the class
    jni::LocalObject < kClass > obj {}; // Constructs new instance.

    obj("sayHello", "a cool string from C++");

    return 0;
}

I have the JNI-BIND sources inside a local jni_bind folder. So to compile the code above I do on a Mac:

$ tree -L 1
.
├── HelloWorld.cpp
├── com
└── jni_bind

$ tree com
com
└── test
    ├── HelloWorld.class
    └── HelloWorld.java

C++ compilation:

$ clang++ -std=c++17 -I./jni_bind -I"$JAVA_HOME/include"
-I"$JAVA_HOME/include/darwin/" HelloWorld.cpp -o HelloWorld

And it compiles fine, great!

But now when I run it, I get a segmentation fault because it is not able to find the ./com/test/HelloWorld.class file to load.

$ ./HelloWorld
zsh: segmentation fault  ./HelloWorld

Setting the CLASSPATH does not work either:

$ CLASSPATH=. ./HelloWorld
zsh: segmentation fault  CLASSPATH=. ./HelloWorld

Perhaps I have to set JavaVMOption with -Djava.class.path=. to pass to its embedded JVM? But how would I go about doing that?

@jwhpryor
Copy link
Collaborator

jwhpryor commented May 1, 2023

Ah wow, so, it's great that you're able to compile and run, although, it looks like you're driving control of the binary entirely through native.

While this is actually possible, I don't have the sample released yet. Unfortunately, I think you need to initiate control from Java, and send it to native.

If you really want this as native only (i.e. you deliberately wanted control to emanate from native), please change the bug name and file it against me. It would be helpful for me to understand what folks would find most useful to help adoption of the library.

@coralblocks
Copy link

Very nice project! Congratulations for the hard and meticulous work you did there. I'm maintaining a GitHub repo (JavaToCppAndBack) with an assortment of examples of Java to C++ and C++ to Java integration. I would love to include a JNI-BIND HelloWorld there eventually!

@jwhpryor
Copy link
Collaborator

jwhpryor commented May 1, 2023

That is very kind, I appreciate the compliment! It has been a tremendous amount of work so it is nice that it is getting closer to being in people's hands. I'd love to be used by other projects, although to start i imagine that would be done most simply through the Bazel/WORKSPACE mechanisms.

If you would like to file a new issues for "Distribution to third party projects" that would be great, although, realistically I'm afraid I need to address other issues for the 1.0 release. In the meantime, any mentions/stars help the project gain traction which I would be very grateful for 🙂

@jwhpryor jwhpryor changed the title How to make the HelloWorld work with "jni_bind_release.h"? Support native code only usage of JVM May 31, 2023
@jwhpryor jwhpryor added this to the Release 1.5 milestone Mar 18, 2024
@jwhpryor jwhpryor added the enhancement New feature or request label Mar 18, 2024
@ltungv
Copy link

ltungv commented Aug 9, 2024

For anyone trying to use this project for native code only usage and needs to get the classpath to work, I guess we can initiate the JavaVM ourselves with the correct classpath.

void run(JavaVM *jvm) {
  jni::JvmRef<jni::kDefaultJvm> jvm_ref = jni::JvmRef<jni::kDefaultJvm>(jvm);
  // ...
}

int main(int argc, char **argv) {
  std::string classpath = "-Djava.class.path=example.jar";

  JavaVMOption options[1];
  options[0].optionString = classpath.data();

  JavaVMInitArgs init_args = {
      .version = JNI_VERSION,
      .nOptions = 1,
      .options = options,
      .ignoreUnrecognized = false,
  };

  JavaVM *jvm;
  JNIEnv *env;
  if (JNI_CreateJavaVM(&jvm, (void **)&env, (void *)&init_args) != JNI_OK) {
    return 1;
  }

  run(jvm);
  return 0;
}

I'm not 100% percent sure if this is the correct use of the library, but it works for my purpose of using Java classes in C++.

@jwhpryor
Copy link
Collaborator

jwhpryor commented Sep 16, 2024

Ah, this is similar to the unreleased binary I have. If you manage to add it as a binary in the tree as a pull request I'd love to add your work to the tree. Realistically I don't think I have time to do this myself.

(Also, apologies, I missed this comment when you posted it).

@ltungv
Copy link

ltungv commented Oct 17, 2024

Ah, this is similar to the unreleased binary I have. If you manage to add it as a binary in the tree as a pull request I'd love to add your work to the tree. Realistically I don't think I have time to do this myself.

(Also, apologies, I missed this comment when you posted it).

By adding a binary, do you mean adding an example to README or creating some compilation unit that uses classpath and invokes Java methods from C++? If it's the latter case, I'm not sure where and how to create such a binary.

@jwhpryor
Copy link
Collaborator

Let me try to take some time this weekend and open source the existing code we have. I took a stab last night but it's more than an hour's work.

By binary, I mean, add a cc_binary target, which obviously is Bazel specific. I'm sure there's a way you could do it in CMAKE or whatever, but for now the project mostly focuses on header only, or using Bazel.

As I said, I have an internal binary which runs with no Java entrypoint, but sadly it references locations of solibs for the JVM that are Google specific, and thus not useful for open source.

@jwhpryor
Copy link
Collaborator

Ok, I put some time into this and I've got something that's at least partially there.

#343

Unfortunately, on my machine, when I launch it I immediately see the following failure:

Error occurred during initialization of VM
Unable to load native library: /usr/local/buildtools/java/jdk-sts/lib/libjava.so: undefined symbol: JVM_GetClassFileVersion, version SUNWprivate_1.1

I haven't polished this code at all so buyer beware. This works with our internal tooling, but somehow I'm getting a different result from my Bazel invocation. I would figure it's accessing the same solibs so I'm not sure what's going on.

copybara-service bot pushed a commit that referenced this issue Oct 20, 2024
See #127.

PiperOrigin-RevId: 687715496
copybara-service bot pushed a commit that referenced this issue Oct 25, 2024
See #127.

PiperOrigin-RevId: 687715496
copybara-service bot pushed a commit that referenced this issue Oct 25, 2024
See #127.

PiperOrigin-RevId: 687715496
copybara-service bot pushed a commit that referenced this issue Oct 25, 2024
See #127.

PiperOrigin-RevId: 689950666
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

4 participants