1

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.

cambecc
  • 4,083
  • 1
  • 23
  • 24
  • 1
    Or the version control should handle this better? https://help.github.com/articles/dealing-with-line-endings – Jayan Jan 15 '13 at 04:33
  • I would rather not rely on the version control system to deal with line endings here. I'm looking for a solution that would work for any kind of version control system, i.e., a solution that fixes `javah`'s behavior. – cambecc Jan 15 '13 at 04:35
  • I understand. How do you handle other type of files? They too have similar problems? – Jayan Jan 15 '13 at 04:40
  • Other files are fine because most editors know to preserve line endings when editing a file. But these files are auto-generated and `javah` doesn't care to preserve line endings. – cambecc Jan 15 '13 at 04:44

2 Answers2

1

'javah' is the same as every other Java program in this regard. The line terminators are written by e.g. PrintWriter.println(), as determined by the system property 'line.separator'. You could try setting that from the command line but I doubt you will get any joy that way. I would look for a more lateral solution such as reconfiguring the IDE as suggested, or only running javap on one build machine.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • I tried setting the `line.separator` value on the command line... then realized that would be a neat trick. After all, how do you put '\n' on the command line without the command processor interpreting it? And then do that in cross-platform compatible way? (Minor note: your answer refers to `javap`, but I'm talking about `javah`) – cambecc Jan 17 '13 at 05:08
0

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>
cambecc
  • 4,083
  • 1
  • 23
  • 24