Unable to build OpenCV with Java bindings

Hello all,

I need java bindings for opencv to be able to use nix in a java/scala project at work. I tried many things and none of them work. Here is the nix flake I am using:

{
  description = "A template that shows all standard flake outputs";

  inputs.nixpkgs.url = "github:NixOS/nixpkgs";

  outputs = {
    self,
    nixpkgs,
    ...
  }: let
    system = "x86_64-linux";
    pkgs = import nixpkgs {inherit system;};
  in {
    packages.${system}.default = (
      pkgs.opencv4.overrideAttrs
      (oldAttr: {
        buildInputs = oldAttr.buildInputs ++ (with pkgs; [ant jdk jre]);
        cmakeFlags = oldAttr.cmakeFlags ++ ["-DWITH_JAVA=ON"];
      })
    );
  };
}

In the package definition in nixpkgs there is no option like enableJava. Also, I didnā€™t find the java bindings in the default build (cached on cache.nixos.org) version of the package.

Can anyone tell me how to get a opencv build with java bindings? I also would appreciate any tips which would push me in the right direction. Thank you!

Doing a quick search on the nixpkgs repo, I see this: nixpkgs/pkgs/by-name/li/libjpeg_turbo/package.nix at 35f9b4c165413eb1f419b3d46889194ec82eda4f Ā· NixOS/nixpkgs Ā· GitHub. Looks like the flag enableJava adds openjdk as part of nativeBuildInputs. You can give that a try.

Hey @aos , thanks you for helping me out!

Can you tell me how you found this option? I did not find this option in package definition for the opencv derivation.

I tried it with enableJava, but unfortunately it did not build the java bindings. I am not sure what is happening there. I also added openjdk and ant to the buildInputs, however it still did not do the trick. I also created a nix shell with all the dependencies and tried doing it manually, however the cmake output says, that it does not find Java, although ant and JNI are found. I am not sure if it is an issue is here ā€¦ Do you have any further tips? I really appreciate your help!

I just did a search on the nixpkgs repo: Code search results Ā· GitHub

This is a good way to figure out what other packages are doing. Chances are usually pretty good that others have run into similar problems.

By this - I mean that you should see what that package is doing, and how itā€™s setting and using the enableJava option. It uses it to add openjdk into nativeBuildInputs ā† native is important, it makes the dependency available during build time.

It would also be helpful to see what the most recent version of your code is now.

1 Like

I see, that actually is quite helpful. Thanks @aos !

Here is the latest version of my flake.nix file for building OpenCV, the devShell is just for testing and debugging, but so far I havenā€™t figured out how to build with java bindings:

{
  description = "OpenCV test flake";

  inputs.nixpkgs.url = "github:NixOS/nixpkgs";

  outputs = {
    self,
    nixpkgs,
    ...
  }: let
    system = "x86_64-linux";
    pkgs = import nixpkgs {
      inherit system;
    };
    cmakePackage = (
      pkgs.cmake.overrideAttrs
      (oldAttr: {
        postPatch =
          oldAttr.postPatch
          or ""
          + ''
            substituteInPlace Modules/FindJNI.cmake \
            --replace "/usr/lib64/jvm/jre" "/usr/lib64/jvm/jre\n${pkgs.corretto21}"
          '';

        # patches = [
        #   (pkgs.writeText "add-custom-jvm.patch" ''
        #     --- a/Modules/FindJNI.cmake
        #     +++ b/Modules/FindJNI.cmake
        #     @@ -312,7 +312,8 @@
        #        # SuSE specific paths for default JVM
        #        /usr/lib64/jvm/java
        #        /usr/lib64/jvm/jre
        #        /usr/lib/corretto
        #        /usr/lib/openjdk
        #        /usr/lib/corretto
        #     -  )
        #     +  )
        #     +set(_JNI_JAVA_AWT_LIBRARY_TRIES)
        #   '')
        # ];
      })
    );
  in {
    devShells.${system}.default =
      (pkgs.buildFHSEnv {
        name = "opencv-fhs";
        targetPkgs = pkgs: (with pkgs;
          [
            ant
            corretto21
            gcc
            jre_minimal
            libgcc
            openblas
            vtk
          ]
          ++ [cmakePackage]);
        profile = ''
          export JAVA_HOME=${pkgs.corretto21}
          export PATH=$JAVA_HOME/bin:$PATH

          echo  "cmake \\" > a.sh
          echo  "-DBUILD_JAVA=ON \\" >> a.sh
          echo  "-DBUILD_SHARED_LIBS=OFF \\" >> a.sh
          echo  "-DBUILD_opencv_core=ON \\" >> a.sh
          echo  "-DBUILD_opencv_imgcodecs=ON \\" >> a.sh
          echo  "-DBUILD_opencv_imgproc=ON \\" >> a.sh
          echo  "-DBUILD_opencv_java=ON \\" >> a.sh
          echo  "-DBUILD_opencv_java_bindings_gen=ON \\" >> a.sh
          echo  "-DJAVA_AWT_INCLUDE_PATH=${pkgs.corretto21}/include \\" >> a.sh
          echo  "-DJAVA_AWT_LIBRARY=${pkgs.corretto21}/lib/libjawt.so \\" >> a.sh
          echo  "-DJAVA_INCLUDE_PATH2=${pkgs.corretto21}/include/linux \\" >> a.sh
          echo  "-DJAVA_INCLUDE_PATH=${pkgs.corretto21}/include \\" >> a.sh
          echo  "-DJAVA_JVM_LIBRARY=${pkgs.corretto21}/lib/server/libjvm.so \\" >> a.sh
          echo  "-DJava_JARSIGNER_EXECUTABLE=${pkgs.corretto21}/bin/jarsigner \\" >> a.sh
          echo  "-DJava_JAR_EXECUTABLE=${pkgs.corretto21}/bin/jar \\" >> a.sh
          echo  "-DJava_JAVAC_EXECUTABLE=${pkgs.corretto21}/bin/javac \\" >> a.sh
          echo  "-DJava_JAVADOC_EXECUTABLE=${pkgs.corretto21}/bin/javadoc \\" >> a.sh
          echo  "-DJava_JAVA_EXECUTABLE=${pkgs.corretto21}/bin/java \\" >> a.sh
          echo  "-D_JNI_JAVA_DIRECTORIES_BASE=${pkgs.corretto21}/bin/java \\" >> a.sh
        '';
      })
      .env;

    packages.${system} = {
      cmake = cmakePackage;

      default = (
        pkgs.opencv4.overrideAttrs
        (oldAttr: {
          buildInputs =
            oldAttr.buildInputs
            ++ (with pkgs; [
              ant
              corretto21
              gcc
              jre_minimal
              libgcc
            ]);
          cmakeFlags =
            oldAttr.cmakeFlags
            ++ [
              "-DBUILD_JAVA=ON"
              "-DBUILD_SHARED_LIBS=OFF"
              "-DBUILD_opencv_core=ON"
              "-DBUILD_opencv_imgcodecs=ON"
              "-DBUILD_opencv_imgproc=ON"
              "-DBUILD_opencv_java=ON"
              "-DBUILD_opencv_java_bindings_gen=ON"
              "-DJAVA_AWT_INCLUDE_PATH=${pkgs.corretto21}/include"
              "-DJAVA_AWT_LIBRARY=${pkgs.corretto21}/lib/libjawt.so"
              "-DJAVA_INCLUDE_PATH2=${pkgs.corretto21}/include/linux"
              "-DJAVA_INCLUDE_PATH=${pkgs.corretto21}/include"
              "-DJAVA_JVM_LIBRARY=${pkgs.corretto21}/lib/server/libjvm.so"
              "-DJava_JARSIGNER_EXECUTABLE=${pkgs.corretto21}/bin/jarsigner"
              "-DJava_JAR_EXECUTABLE=${pkgs.corretto21}/bin/jar"
              "-DJava_JAVAC_EXECUTABLE=${pkgs.corretto21}/bin/javac"
              "-DJava_JAVADOC_EXECUTABLE=${pkgs.corretto21}/bin/javadoc"
              "-DJava_JAVA_EXECUTABLE=${pkgs.corretto21}/bin/java"
              "-D_JNI_JAVA_DIRECTORIES_BASE=${pkgs.corretto21}/bin/java"
            ];
        })
      );
    };
  };
}

I followed you advice and added java and ant to the build inputs. Here I added corretto21 instead of openjdk, but it does not work with openjdk either.

In the devShell, I did some testing and found out that the issue most likely comes from CMake. OpenCV uses the two modules FindJNI and FindJava from CMake. As I understand, the CMake modules define some base directories to search, however this is a collection for different Linux distributions such as Ubuntu, OpenSUSE, etc. The patches I tried havenā€™t worked. I also, did not find anything in nixpkgs which has done this before.

Do you have any other suggestions or hints to get this to work? I really do appreciate you taking the time to help me out!