gradle2nix icon indicating copy to clipboard operation
gradle2nix copied to clipboard

Access intermediated build files after build?

Open rolfschr opened this issue 4 years ago • 2 comments

Hi,

I'm trying to compile an Android app with gradle2nix which has worked out of the box. Thanks a lot already for implementing this tool!

The app has some special setup. It uses https://github.com/joshjdevl/libsodium-jni as an input for an additional library (say "libX") that itself is then compiled and used to build the app again.

This is the current non-nixified workflow:

  • Build the app using gradle.
  • Copy the files build/intermediates/merged_native_libs/debug/out/lib/$ARCH/libsodiumjni.so to libX's folder.
  • Build the libX (including the libsodiumjni.so), resulting in libX.so.
  • Copy libX.so to app/src/main/jniLibs.
  • Build the app again, this time including libX.so.

As I said, the first step worked out of the box using gradle2nix! The libsodiumjni.so file is not available after the build so the script that executes steps 2-4 doesn't work. I believe the app is build twice because libsodiumjni.so is only available (as a build artefact) after the first build when gradle has downloaded it. This doesn't feel like a proper workflow anyways.

Is there any way provided by gradle or gradle2nix to have libsodiumjni.so available before the actual build? Ideally, I'd like to replace step 1 by something-that-just-fetches-the-deps and then only build the app once (step 5) with gradel2nix. I've looked into the generated gradle-env.nix and though maybe mkDep might be of some help here. I don't have experience with gradle so I am actually guessing.

Any help is appreciated.

rolfschr avatar Feb 03 '21 13:02 rolfschr

Is this your own project, as in you control the source? Because I would suggest improving the Gradle build instead so you can build the project in one run.

Looking at libsodiumjni, libsodiumjni.so is prebuilt and included in the JAR/AAR artifact. So the build for libX should depend on a Copy task which extracts the library from the JAR/AAR, so libsodiumjni should be part of its own configuration. Something like:

val libsodium by configurations.registering

val copyLibsodium by tasks.registering(Copy::class) {
    from(zipTree(libsodium.singleFile))
    into("libX/build/libsodiumjni")
    include("jni/*/libsodiumjni.so")
}

// I have no idea what builds libX, this is just an example
tasks.compileLibX {
    dependsOn(copyLibsodium)
    somehowIncludeLibrary("libX/build/libsodiumjni/jni/x86_64/libsodiumjni.so")
}

Alternatively, if you only have to do this in Nix, you can use the preBuild hook to copy artifacts into the right places for the build.

let
  libsodiumjni = fetchzip {
    url = "https://repo1.maven.org/maven2/com/github/joshjdevl/libsodiumjni/libsodium-jni-aar/2.0.2/libsodium-jni-aar-2.0.2.aar";
    sha256 = "...";
  };
  
  arch = "x86_64";    # Or obtain from stdenv.hostPlatform / stdenv.targetPlatform

  libX = buildGradle {
    src = ./.;

    gradleFlags = [ ":libX:assemble" ];

    preBuild = ''
      mkdir -p libX/build
      cp ${libsodiumjni}/jni/${arch}/libsodiumjni.so libX/build/
    '';

    installPhase = ''
      cp libX/build/libs/libX.so $out
    '';
  };
in
buildGradle {
  src = ./.;

  gradleFlags = [ ":app:assembleRelease" ];

  preBuild = ''
    mkdir -p app/src/main/jniLibs
    cp "${libX}" app/src/main/jniLibs/
  '';

  installPhase = ''
    cp app/build/outputs/apk/release/app.apk $out
  '';
}

tadfisher avatar Feb 03 '21 23:02 tadfisher

@tadfisher Thanks a lot for the quick and elaborate answer! I will see what I can do. Thank you so much again!

rolfschr avatar Feb 04 '21 20:02 rolfschr