Search code examples
javagradlejava-native-interface

Including subproject gradle build outputs in JAR file and runtime library path


I have a Java application that uses JNI and I'm using gradle to build the C++ shared library containing the code I load as part of JNI. The C++ build is a subproject of the root build. I can put a dependency on :jnisubproject:assembleRelease from my root project's run or jar tasks, which does build the shared library (at jnisubproject/build/lib/main/release/libjnisubproject.so), but it doesn't add that shared library into my JAR file, nor does it set up my Java library path to be able to access the shared object at runtime. With some hackery (explicitly modifying the java.library.path system property in my run task) I can get it to work when I use gradle run, but I'd like to be able to build a JAR file for redistribution.

I've tried adding the subproject as a runtime dependency by adding

dependencies {
    runtime project(":jnisubproject")
    // runtime ":jnisubproject:assembleRelease" also doesn't work
}

to my root project's dependencies, but this is neither enough to get gradle jar to build the subproject, nor to include its files in the JAR; this actually appears to do nothing. If I add an explicit dependency in the JAR task, like this:

jar {
    dependsOn ":jnisubproject:assembleRelease"
}

it will build my subproject when I run gradle jar but unsurprisingly the shared library doesn't end up in the JAR. The last thing I tried was both the snippet above with the explicit dependency in addition to adding a file dependency on the output directory:

dependencies {
    runtime files('jnisubproject/build/lib/main/release/*')    
}

but that both feels extremely hacky and doesn't work, an awesome combination. If I explicitly include the built files in the JAR by doing

jar {
    include 'jnisubproject/build/lib/main/release/*'
}

Then my JAR file ends up being completely empty other than a manifest.

In short, my problem is this:

  • I have a subproject that builds a shared library
  • I want the root project (a Java project) to express a dependency on that shared library.
  • I want that dependency to cause the shared library to be added to java.library.path and my output JAR file.

Any ideas?


Solution

  • Try that in your root project :

    processResources {
        from project(':jnisubproject').buildDir + '/lib/main/release/*'
    }
    

    It will tell the main processResources task to include your lib.

    About the java.library.path addition, I don't think it's possible to directly link a lib from inside a Jar. More information here.