System designTroubleshooting

CMake cannot find Java or Ant in the OpenCV Android build

Why the OpenCV Android build reports ant: NO and Java wrappers: NO, and how to fix CMake detection with a JDK, ant.bat and the Gradle project type.

LumaSpec Vision9 min read Share on LinkedIn

On this page 9 sections
  1. 01What the NO lines actually mean
  2. 02Cause 1: Ant is invisible to CMake
  3. 03Cause 2: the JDK is mismatched and too new for 4.6.0
  4. 04Cause 3: the ANT project type crashes on current SDK tools
  5. 05The fix, step by step
  6. 06Worked example: OpenCV 4.6.0, SDK tools 26.1.1, JDK 18
  7. 07Checks before you rebuild
  8. 08When the usual answer is wrong
  9. 09Questions

You configured OpenCV 4.6.0 with opencv_contrib for Android, every native module landed under "To be built", and the summary still printed ant: NO, Java wrappers: NO and Java tests: NO. Configure even ended with "Configuring done", so the miss is easy to overlook: the native SDK builds fine, and you discover the gap only when the installed SDK has no Java API for your app. The cause is never the contrib modules. It is CMake's host-side probes for a JDK and Apache Ant, plus an Ant/Eclipse project type that current Android SDK tools no longer run cleanly. This guide ranks the causes, gives the exact -D lines that fix them, and ends with the one summary line that counts: Java wrappers: YES.

What the NO lines actually mean

OpenCV treats Java as an optional module. Failed detection moves java into the "Unavailable" list, prints the three NO lines, and configure still finishes with exit code zero. Nothing halts and nothing errors; the wrapper and its jar are simply never generated. The pass test is therefore the summary block itself, not the build result: ant must show a path to ant.bat, and Java wrappers must read YES.

The scope is narrow. The log lists aruco, ximgproc and the other opencv_contrib modules under "To be built", so OPENCV_EXTRA_MODULES_PATH is doing its job and the failure is confined to the host toolchain. A contrib module that goes missing is a different failure with its own fix, covered in Missing OpenCV aruco module: fix the CMake calibration build.

Cause 1: Ant is invisible to CMake

Three things hide ant.bat from OpenCV's detection, and this configure shows all the signs.

  • The console that launches cmake.exe must inherit the variables. Run where ant, where java and echo %JAVA_HOME% in that same console. The reported environment contradicts itself: JAVA_HOME points at jdk-18.0.1.1 while the machine reports Java 19, the signature of one environment being edited and another doing the building.
  • An environment variable named ANT_EXECUTABLE is never read. CMake reads the cache variable ANT_EXECUTABLE, which you set with -D on the command line, and searches the PATH and the ANT_HOME hint. Pass -DANT_EXECUTABLE=C:/ant/bin/ant.bat and the search stops being a question.
  • ANT_HOME must name the Ant root, the folder that contains bin\ant.bat. Here it is C:\ant\bin, so anything that appends \bin to ANT_HOME looks in C:\ant\bin\bin, which does not exist. Set ANT_HOME=C:\ant.
What you see Test Fix
ant: NO where ant in the build console -DANT_EXECUTABLE=C:/ant/bin/ant.bat
ant: NO, ANT_HOME ends in \bin echo %ANT_HOME% point ANT_HOME at the Ant root
Java wrappers: NO with ant: NO read the summary top to bottom fix Ant first; the wrappers follow it
null returned: -1073741819 mid-build convert the code below ANDROID_PROJECTS_BUILD_TYPE=GRADLE
Android ABI: arm64-v8a despite three ABI flags your own configure log one ABI per build tree; the last flag wins

Cause 2: the JDK is mismatched and too new for 4.6.0

JAVA_HOME must name a JDK root, the folder that holds bin\javac.exe, never a JRE, because the wrapper build runs javac, jar and javadoc from it. Then pin the line: JDK 8 for OpenCV 4.6.0. The 4.6-era Android toolchain assumes that Java line, and JDK 18 or 19 only adds risk to javadoc and header-generation steps written long before them. Your summary did print a Java section ("export all functions"), so a JDK was visible and the decisive NO was Ant, but jdk-18.0.1.1 in JAVA_HOME with java reporting 19 is two toolchains pretending to be one. Install JDK 8, point JAVA_HOME at it, and let the rest of the machine keep its newer JDK.

Cause 3: the ANT project type crashes on current SDK tools

Even with Ant found, ANDROID_PROJECTS_BUILD_TYPE="ANT" sends the Android projects through the SDK's Ant/Eclipse scripts, the "Projects build scripts: Ant/Eclipse compatible" line in the summary. With SDK tools 26.1.1 and build tools 33.0.0, that path dies inside tools/ant/build.xml at lines 649 and 655 with null returned: -1073741819. Convert the code:

-1073741819 + 4294967296 = 3221225477 3221225477 = 0xC0000005 = STATUS_ACCESS_VIOLATION

An access violation inside the legacy script's own process is not an OpenCV compile error. The historical remedy, sdk tools 25.2 with platform tools 25 and Java 8, reinstalls 2016-era software to keep a deprecated path alive. Switch the project type to GRADLE: the projects then build as Gradle projects and the SDK's Ant scripts drop out of the path. Ant is still needed for the wrapper jar itself, which is why Cause 1 must be fixed regardless.

The fix, step by step

  1. Unpack Apache Ant so that C:\ant\bin\ant.bat exists, set ANT_HOME=C:\ant, and put C:\ant\bin on PATH.
  2. Install JDK 8, set JAVA_HOME to its root, and put its bin directory first on PATH in the build console. Confirm java -version reports 1.8 and where java resolves inside that JDK.
  3. Delete the build directory. Stale cached values from a failed detection survive a rerun, so removing the tree is the documented first move in OpenCV's own Android build troubleshooting: check the paths, remove the build directory, retry.
  4. Configure with ANDROID_PROJECTS_BUILD_TYPE=GRADLE, keep BUILD_JAVA=ON, BUILD_opencv_java=ON and BUILD_FAT_JAVA_LIB=ON, and add -DANT_EXECUTABLE=C:/ant/bin/ant.bat with forward slashes.
  5. Read the summary block before building. Accept it only when ant shows the ant.bat path, Java wrappers reads YES, Java tests reads YES, and java has moved from "Unavailable" to "To be built"; the "Projects build scripts" line changes from "Ant/Eclipse compatible".
  6. Build with ninja and install to your CMAKE_INSTALL_PREFIX. The installed SDK then carries the Java API and the fat jar beside the native libraries.

OpenCV builds live and die by exact CMake paths, the same discipline as cross-compiling for a PLC target, shown in OpenCV builds that require CMake paths and a PLCnext target, and the same first move as CMake missing dependency diagnostics for vision builds.

Worked example: OpenCV 4.6.0, SDK tools 26.1.1, JDK 18

Inputs, each taken from the failing configure:

  • Sources: OpenCV 4.6.0 with opencv_contrib-4.6.0 at OPENCV_EXTRA_MODULES_PATH=E:/OpenCV/opencv_contrib-4.6.0/modules, Ninja with CMAKE_MAKE_PROGRAM=c:/ninja/ninja, install to E:/OpenCVAndroidSdk.
  • Toolchain: NDK r25b (ver 25.1.8937393), SDK tools 26.1.1, build tools 33.0.0, ANDROID_SDK_TARGET=30, ANDROID_NATIVE_API_LEVEL=21.
  • Environment: JAVA_HOME=C:\Program Files\Java\jdk-18.0.1.1, ANT_HOME=C:\ant\bin, ANT_EXECUTABLE=C:\ant\bin\ant.bat set as an environment variable, ANDROID_PROJECTS_BUILD_TYPE="ANT".

The rule: every detection input must reach cmake.exe either as a cache variable on the command line or through the PATH it inherits, and the project type must be one the installed SDK tools can execute. Four inputs fail that rule:

Input Was Becomes
Project type ANDROID_PROJECTS_BUILD_TYPE="ANT" ANDROID_PROJECTS_BUILD_TYPE=GRADLE
Ant location env var ANT_EXECUTABLE -DANT_EXECUTABLE=C:/ant/bin/ant.bat
ANT_HOME C:\ant\bin C:\ant
JAVA_HOME C:\Program Files\Java\jdk-18.0.1.1 the JDK 8 root

Corrected command, trimmed to the lines that change the outcome:

cmake -GNinja -DCMAKE_MAKE_PROGRAM=c:/ninja/ninja ^
  -DCMAKE_INSTALL_PREFIX=E:/OpenCVAndroidSdk ^
  -DANDROID_PROJECTS_BUILD_TYPE=GRADLE ^
  -DANT_EXECUTABLE=C:/ant/bin/ant.bat ^
  -DBUILD_JAVA=ON -DBUILD_opencv_java=ON -DBUILD_FAT_JAVA_LIB=ON ^
  -DOPENCV_EXTRA_MODULES_PATH=E:/OpenCV/opencv_contrib-4.6.0/modules ^
  -DANDROID_ABI=arm64-v8a

One ABI flag, on purpose. The original command passed arm64-v8a, x86_64, x86 and arm64-v8a again, and repeated -D flags overwrite each other, so the summary's "Android ABI: arm64-v8a" is simply the last value standing. Use one build tree per ABI and merge the installs.

Decision: rerun in a clean build directory and hold the line at Java wrappers: YES. A configure that stops short of it installs an SDK with no Java side, and no amount of ninja fixes that afterwards.

Checks before you rebuild

  • where ant, where java and echo %JAVA_HOME% run in the console that builds, not a fresh one.
  • ANT_HOME names the folder containing bin\ant.bat, not bin itself.
  • The build directory was deleted after the last failed detection.
  • -DANT_EXECUTABLE sits on the cmake command line, written with forward slashes.
  • ANDROID_PROJECTS_BUILD_TYPE is GRADLE.
  • The summary block shows an ant path, Java wrappers: YES and Java tests: YES.
  • The Android ABI line names the one ABI this tree builds.

When the usual answer is wrong

You need no Java API at all. Configure with -DBUILD_JAVA=OFF and -DBUILD_ANDROID_PROJECTS=OFF: headers and native libraries only, and the Ant and JDK questions disappear. That is the right call for a pure C++ Android app.

You need OpenCV in an app, not a custom build. The prebuilt OpenCV4Android SDK or the Gradle dependency route replaces the whole exercise, and Migrate an OpenCV Android project from Manager to a Gradle SDK setup walks that consumption path.

The inverse failure, where CMake finds your toolchain but an SDK sample cannot find OpenCV, has its own fix in CMake can't find OpenCV in SDK samples: fix the config path.

Once the SDK is in place the next decisions are hardware: pick sensors in the area scan camera finder or a vision controller for the cell, and bring your configure log to the contact page if the stack still refuses.

Questions

Why does configure finish with Configuring done when Java wrappers still read NO?

Because OpenCV marks Java as an optional module: cmake exits zero, the native modules build, and the skip shows only in the summary block and later in the missing Java folder of the installed SDK. The exit code is not the test. Read the block itself: ant must print a path and Java wrappers must read YES, or the jar is never generated and your app has no Java API to import.

Which JDK should I use for the OpenCV 4.6.0 Android Java wrappers?

JDK 8. Point JAVA_HOME at a JDK root, the folder holding bin\javac.exe, never a JRE, because the wrapper build drives javac, jar and javadoc. Confirm `java -version` reports 1.8 in the console that runs cmake; a newer JDK elsewhere on the machine is harmless because only that console's inherited environment matters. The 18 and 19 lines configure the native side happily while the Java steps run on ground they were never written for.

What does the ant error null returned -1073741819 mean?

It is a Windows exit code printed in signed decimal. Adding 4,294,967,296 gives 3,221,225,477, which is 0xC0000005, an access violation. The process that died is the one running the SDK's legacy Ant build.xml, not the OpenCV C++ compile. Downgrading to sdk tools 25.2 and platform tools 25 chases 2016-era software; switching ANDROID_PROJECTS_BUILD_TYPE to GRADLE takes that script out of the build entirely.

My command lists arm64-v8a, x86_64 and x86, so why does the log show only arm64-v8a?

Repeated -DANDROID_ABI flags do not accumulate; each one overwrites the cached value, so the last flag wins. In that command line the last value is arm64-v8a, which is exactly what the Android ABI summary line reports. Use one build directory per ABI, run configure, build and install into each, then merge the installed trees, or follow the multi-ABI handling in the official OpenCV4Android build guide.

Do I need BUILD_FAT_JAVA_LIB=ON, and what does it change?

It bundles every OpenCV module into the single native library behind the jar. With BUILD_SHARED_LIBS=OFF, a static native build as in this command line, that fat library is the form the Java wrapper expects, so keep it ON whenever you want the Java API. Turn it OFF and you get per-module native libraries that your own packaging then has to match. It has no effect on whether CMake finds Ant or the JDK.