I have a maven project that generates .h JNI files by executing javah
as part of the normal build process of a java library. These .h files are then checked in to source control (such as git) and used to build the accompanying native library.
One minor annoyance is the files generated by javah
differ by line endings depending on the platform where it is run. So if a Mac OSX developer runs the build and checks in (UNIX-style line endings), then a Windows developer will subsequently see that their build has changed all the .h files (to Windows-style line endings). But they've not actually changed--javah
is just behaving in a platform dependent way.
How can I coax javah
to always use, for example, UNIX-style line endings when generating .h files? There appears to be no appropriate command-line switch:
> javah.exe
Usage:
javah [options] <classes>
where [options] include:
-o <file> Output file (only one of -d or -o may be used)
-d <dir> Output directory
-v -verbose Enable verbose output
-h --help -? Print this message
-version Print version information
-jni Generate JNI-style header file (default)
-force Always write output files
-classpath <path> Path from which to load classes
-bootclasspath <path> Path from which to load bootstrap classes
<classes> are specified with their fully qualified names
(for example, java.lang.Object).
Perhaps it would be possible to manually launch the same class as the javah
executable launches, except to explicitly set the "line.separator"
property before doing so. However, I could not find what class that would be, or where.
I solved this problem by writing a custom launcher that explicitly sets the line.separator
property, and then invoking that launcher during the build:
public class JavahLauncher {
public static void main(String[] args) {
String original = System.getProperty("line.separator");
System.setProperty("line.separator", "\n");
try {
com.sun.tools.javah.Main.run(args, new PrintWriter(System.out));
}
finally {
System.setProperty("line.separator", original);
}
}
}
The try-finally allows this launcher to be invoked inside another JVM, such as Maven's JVM instance while performing a build, without permanently changing the line.separator
value. One interesting note is com.sun.tools.javah.Main.main
is unusable because it calls System.exit
, which, if called as part of the Maven build causes Maven to exit!
Compiling this launcher requires a dependency on tools.jar
, something like:
<dependency>
<groupId>com.sun</groupId>
<artifactId>tools</artifactId>
<version>1.7.0</version>
<scope>system</scope>
<systemPath>${java.home}/../lib/tools.jar</systemPath>
</dependency>