12

I'm trying to experiment with using the JNI and JDK 9. I have a class NativeTest.java that looks like this:

public class NativeTest {

    static {
        System.loadLibrary("hello");
    }

    private native void sayHello();

    public static void main(String[] args) {
        new NativeTest().sayHello();
    }
}

I compile the class, then use javah NativeTest to generate the header file.

Upon issuing javah, I get this warning:

Warning: The javah tool is planned to be removed in the next major
JDK release. The tool has been superseded by the '-h' option added
to javac in JDK 8. Users are recommended to migrate to using the
javac '-h' option; see the javac man page for more information.

I know it'll be quite a while before the next major JDK release, but I figured I'd start getting used to this new option now.

So upon trying javac -h NativeTest.java (and other variations like NativeTest, NativeTest.class, etc.) I keep getting this error:

javac: no source files

I haven't been able to find any help online, probably because this feature is relatively new, and I can't find anything about this new -h option in the man page.

Anyone else try this yet? What am I missing?

David Mordigal
  • 813
  • 2
  • 9
  • 22
  • 2
    Ah, nevermind, I found it. You need to specify the directory for where to put the header files. `javac -h . NativeTest.java`. I'll leave the question up in case anyone else runs into the same oversight. – David Mordigal Oct 05 '17 at 03:04
  • You can answer your own question and mark it as the accepted answer. That will reduce the number of unanswered questions. – cup Oct 05 '17 at 05:26

3 Answers3

14

The solution I discovered was that I was not specifying the directory where javac should place the header files.

Executing javac -h . NativeTest.java worked.

David Mordigal
  • 813
  • 2
  • 9
  • 22
  • Note this just chucks the generated `.class` files somewhere else, most likely messing up your source tree. (At least with openjdk version 13 javac). – Bathsheba Apr 15 '20 at 15:10
9

In Java 8, you had to make intermediate step of generating class files to get C headers

Lets say you have following structure

recipeNo001
├── Makefile
├── README.md
├── c
│   └── recipeNo001_HelloWorld.c
├── java
│   └── recipeNo001
│       └── HelloWorld.java
├── lib
└── target

In Java (prior to JDK 9) you had to compile class and use javah with compiled sources

> export JAVA_HOME=$(/usr/libexec/java_home -v 1.8.0_11)
> ${JAVA_HOME}/bin/javac -d target java/recipeNo001/*.java
> ${JAVA_HOME}/bin/javah -d c -cp target recipeNo001.HelloWorld
# -d c       -> put generated codes inside c directory
# -cp target -> compiled classes are inside target dir

In Java 9 you can use javac -h with Java source code

> export JAVA_HOME=$(/usr/libexec/java_home -v 9)
> ${JAVA_HOME}/bin/javac -h c java/recipeNo001/HelloWorld.java
# -h c       -> create header file inside c directory
Oo.oO
  • 12,464
  • 3
  • 23
  • 45
3

The javah tool has been superseded by the "javac -h" feature . we should be able to just use the normal Java compiler (with the -h flag in Java 8+) to output those files during the Java compilation step.

Usage: -h directory Specifies where to place generated native header files.

When you specify this option, a native header file is generated for each class that contains native methods or that has one or more constants annotated with the java.lang.annotation.Native annotation. If the class is part of a package, then the compiler puts the native header file in a subdirectory that reflects the package name and creates directories as needed.

javac -h directory name NativeTest.java will solve the problem