0
votes

I am writing a simple demo JNI project in Eclipse to integrate Java and C code. I have installed the CDT plugin for Eclipse to do this. With this project structure I have my HelloJNI java file inside the '(default package)' of Eclipse and have no problems using the makefile to generate a HelloJNI.h C header file.

My Makefile:

# Define a variable for classpath
CLASS_PATH = ../bin

# Define a virtual path for .class in the bin directory
vpath %.class $(CLASS_PATH)

# $* matches the target filename without the extension
HelloJNI.h : HelloJNI.class
javah -classpath $(CLASS_PATH) HelloJNI

The problem is that I cannot figure out how to get this to work with HelloJNI.java being inside a package such as com.example instead of the default package. i.e. this structure. When running the same make target I get the error output:

make: *** No rule to make target 'HelloJNI.class', needed by 'HelloJNI.h'. Stop.

I attempted to add the package name to the javah command:

javah -classpath $(CLASS_PATH) com.example.HelloJNI

...but get the same error.

I attempted to change the classpath to:

CLASS_PATH = ../bin/com/example

...but get the following error:

make HelloJNI.h

javah -classpath ../bin/com/example HelloJNI

Error: Could not find class file for 'HelloJNI'.

What do I need to do with my makefile to make this work?

1

1 Answers

1
votes

The javah utility expects you to give it the fully-qualified name of the class you want it to analyze, and it expects to find that class relative to the classpath, according to that name. Thus, if the name of the class is com.example.HelloJNI, then you might tell make something like this:

CLASS_DIR = ../bin

HelloJNI.h : $(CLASS_DIR)/com/example/HelloJNI.class
    javah -force -classpath $(CLASS_DIR) com.example.HelloJNI

You can dress that up a bit if you want. I use something a little DRYer and with a bit more automation in my own Makefiles, but I'm trying to get across the key points. In particular:

  1. Express the correct prerequisite file (the .class file, in the correct directory). If you do not do this correctly then you will end up having your header sometimes being rebuilt when it does not need to be and / or not being updated when it does need to be.

  2. Specify an appropriate -classpath to javah; this follows the normal Java rules for expressing class paths.

  3. Specify the correct, fully-qualified class name to javah.

  4. Use the -force option, else javah will refuse to replace headers that already exist. That default behavior is reasonable when you invoke javah manually, but it will mess you up when you are trying to use make to keep the JNI headers up to date. Of course, it follows that you must not make manual modifications to those headers, because such modifications are likely to be clobbered.