Search code examples
gradlejavacpp

Build jar with binaries for required platform only (javacpp)


I want to build a fat jar for tesseract. With the following build settings I get a jar of about 68 MB with dependencies for all supported platforms:

dependencies {
    implementation group: 'org.bytedeco', name: 'tesseract-platform', version: '4.1.1-1.5.3'
}
jar {
    manifest { attributes 'Main-Class': 'BasicExample' }
    from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } }
}

In order to reduce this size, I tried to only include the dependencies for my platform following this guideline - but without success, see also this SO question and @Samuel Audet's answer to it (I want to stick with gradle). Therefore I decided to manually include only the required dependencies from the POM file:

dependencies {
    implementation group: 'org.bytedeco', name: 'tesseract', version: '4.1.1-1.5.3'
    implementation group: 'org.bytedeco', name: 'tesseract', version: '4.1.1-1.5.3', classifier: 'windows-x86_64'
    implementation group: 'org.bytedeco', name: 'leptonica', version: '1.79.0-1.5.3', classifier: 'windows-x86_64'
}

This reduces the size of the jar to about 7 MB and works fine (at least for the basic example). Nevertheless I get warnings:

Warning: Could not load ...: java.lang.UnsatisfiedLinkError: no jnijavacpp in java.library.path: ...

Comparing the two jars I found that the small jar lacks the lib path with all the so libs along with header, cmake and pkgconfig files and I assume that this is the reason for the warnings.

So my questions are:

  1. If these files are apparently not necessary to run the jar, why are they included normally?
  2. How can I prevent these warnings while keeping the jar size small?

Any other way to build a jar with just the required dependencies for one platform is of course also welcomed.


Solution

  • I'll have to update that guide a little bit, thanks for reporting! We now also need javacpp-platform, which would give us something like this for windows-x86_64 in this case:

    dependencies {
        implementation group: 'org.bytedeco', name: 'tesseract', version: '4.1.1-1.5.3'
        implementation group: 'org.bytedeco', name: 'tesseract', version: '4.1.1-1.5.3', classifier: 'windows-x86_64'
        implementation group: 'org.bytedeco', name: 'leptonica', version: '1.79.0-1.5.3', classifier: 'windows-x86_64'
        implementation group: 'org.bytedeco', name: 'javacpp', version: '1.5.3', classifier: 'windows-x86_64'
    }
    

    This is needed to fix some issues at load time as explained in this issue:
    https://github.com/bytedeco/javacv/issues/1305

    UPDATE: It's now possible to use Gradle JavaCPP to do this more easily this way:

    plugins {
        id 'java-library'
        id 'org.bytedeco.gradle-javacpp-platform' version "$javacppVersion"
    }
    
    // We can set this on the command line too this way: -PjavacppPlatform=linux-x86_64,macosx-x86_64,windows-x86_64,etc
    ext {
        javacppPlatform = 'linux-x86_64,macosx-x86_64,windows-x86_64,etc' // defaults to Loader.getPlatform()
    }
    
    dependencies {
        api "org.bytedeco:tesseract-platform:$tesseractVersion"
    }