JDK-8170730 : javac always generates JNI header regardless of source change
  • Type: Enhancement
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 8,9
  • Priority: P3
  • Status: New
  • Resolution: Unresolved
  • Submitted: 2016-12-05
  • Updated: 2017-11-30
Related Reports
Blocks :  
Relates :  
Recently we have switched from "javah" to "javac -h" for JavaFX build. After the migration we encountered a huge impact in the build time. See JDK-8170591.

In short, the behaviour of "javah" and "javac -h" seems to be different. "javac -h" generates header file(with new timestamp) regardless of any change in the given source file, but "javah" seems to be intelligent enough to avoid generating a header unless there is change in the class file. Try the below test,

echo "class Foo {native void foo();}" > Foo.java && javac Foo.java -h . && javah -o Foo_javah.h Foo && ls -lh Foo.class Foo.h Foo_javah.h 

You will see something like below,

-rw-r--r-- 1 ARAJKUMA wheel 200B Dec 2 17:12 Foo.class 
-rw-r--r-- 1 ARAJKUMA wheel 338B Dec 2 17:12 Foo.h 
-rw-r--r-- 1 ARAJKUMA wheel 338B Dec 2 17:04 Foo_javah.h 

Look at the timestamp of generated file, timestamp of "Foo.h" which is generated by "javac -h" is close to timestamp of "Foo.class", but timestamp of "Foo_javah.h" never changes unless there is a change the class file related to JNI.
This is per design, and so is not a bug. But arguably, it is a reasonable feature request. That being said, javac has no precedent for not generating files if the output would be the same as any file it might be overwriting. This is arguably better handled as a higher level than javac -- e.g. like the smart file manager in sjavac. FWIW, The JDK build stages the headers through a temporary area, so that the update to the headers used by the native code only occurs when the file has changed.