From 433c36445691c081c75bb9cefbacd7f9384334dc Mon Sep 17 00:00:00 2001 From: Dmitry Kurtaev Date: Fri, 16 Jun 2023 19:58:20 +0300 Subject: [PATCH] Merge pull request #23724 from dkurt:java_without_ant Build Java without ANT #23724 ### Pull Request Readiness Checklist Enables a path of building Java bindings without ANT * Able to build OpenCV JAR and Docs without ANT ``` -- Java: -- ant: NO -- JNI: /usr/lib/jvm/default-java/include /usr/lib/jvm/default-java/include/linux /usr/lib/jvm/default-java/include -- Java wrappers: YES -- Java tests: NO ``` * Possible to build OpenCV JAR without ANT but tests still require ANT **Merge with**: https://github.com/opencv/opencv_contrib/pull/3502 Notes: - Use `OPENCV_JAVA_IGNORE_ANT=1` to force "Java" flow for building Java bindings - Java tests still require Apache ANT - JAR doesn't include `.java` source code files. See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request - [x] I agree to contribute to the project under Apache 2 License. - [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV - [x] The PR is proposed to the proper branch - [ ] There is a reference to the original bug report and related work - [x] There is accuracy test, performance test and test data in opencv_extra repository, if applicable Patch to opencv_extra has the same branch name. - [x] The feature is well documented and sample code can be built with the project CMake --- CMakeLists.txt | 12 +- modules/core/misc/java/src/java/core+Mat.java | 3 + modules/dnn/include/opencv2/dnn/dnn.hpp | 1 - modules/java/CMakeLists.txt | 4 +- modules/java/jar/CMakeLists.txt | 117 +++++++++++++----- modules/java/jar/MANIFEST.MF.in | 5 + modules/java/jar/list_java_sources.cmake | 19 +++ 7 files changed, 130 insertions(+), 31 deletions(-) create mode 100644 modules/java/jar/MANIFEST.MF.in create mode 100644 modules/java/jar/list_java_sources.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index abff989606..ceeb8b8d7d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -777,6 +777,15 @@ if(BUILD_JAVA) include(cmake/android/OpenCVDetectAndroidSDK.cmake) else() include(cmake/OpenCVDetectApacheAnt.cmake) + if(ANT_EXECUTABLE AND NOT OPENCV_JAVA_IGNORE_ANT) + ocv_update(OPENCV_JAVA_SDK_BUILD_TYPE "ANT") + elseif(NOT ANDROID) + find_package(Java) + if(Java_FOUND) + include(UseJava) + ocv_update(OPENCV_JAVA_SDK_BUILD_TYPE "JAVA") + endif() + endif() find_package(JNI) endif() endif() @@ -1802,9 +1811,10 @@ if(BUILD_JAVA) status(" Java:" BUILD_FAT_JAVA_LIB THEN "export all functions" ELSE "") status(" ant:" ANT_EXECUTABLE THEN "${ANT_EXECUTABLE} (ver ${ANT_VERSION})" ELSE NO) if(NOT ANDROID) + status(" Java:" Java_FOUND THEN "YES (ver ${Java_VERSION})" ELSE NO) status(" JNI:" JNI_INCLUDE_DIRS THEN "${JNI_INCLUDE_DIRS}" ELSE NO) endif() - status(" Java wrappers:" HAVE_opencv_java THEN YES ELSE NO) + status(" Java wrappers:" HAVE_opencv_java THEN "YES (${OPENCV_JAVA_SDK_BUILD_TYPE})" ELSE NO) status(" Java tests:" BUILD_TESTS AND opencv_test_java_BINARY_DIR THEN YES ELSE NO) endif() diff --git a/modules/core/misc/java/src/java/core+Mat.java b/modules/core/misc/java/src/java/core+Mat.java index 2d9ee314a3..8e98284dde 100644 --- a/modules/core/misc/java/src/java/core+Mat.java +++ b/modules/core/misc/java/src/java/core+Mat.java @@ -470,6 +470,7 @@ public class Mat { * Element-wise multiplication with scale factor * @param m operand with with which to perform element-wise multiplication * @param scale scale factor + * @return reference to a new Mat object */ public Mat mul(Mat m, double scale) { return new Mat(n_mul(nativeObj, m.nativeObj, scale)); @@ -478,6 +479,7 @@ public class Mat { /** * Element-wise multiplication * @param m operand with with which to perform element-wise multiplication + * @return reference to a new Mat object */ public Mat mul(Mat m) { return new Mat(n_mul(nativeObj, m.nativeObj)); @@ -487,6 +489,7 @@ public class Mat { * Matrix multiplication * @param m operand with with which to perform matrix multiplication * @see Core#gemm(Mat, Mat, double, Mat, double, Mat, int) + * @return reference to a new Mat object */ public Mat matMul(Mat m) { return new Mat(n_matMul(nativeObj, m.nativeObj)); diff --git a/modules/dnn/include/opencv2/dnn/dnn.hpp b/modules/dnn/include/opencv2/dnn/dnn.hpp index 60f68fce6e..d61f7191bc 100644 --- a/modules/dnn/include/opencv2/dnn/dnn.hpp +++ b/modules/dnn/include/opencv2/dnn/dnn.hpp @@ -894,7 +894,6 @@ CV__DNN_INLINE_NS_BEGIN * @param cfgFile path to the .cfg file with text description of the network architecture. * @param darknetModel path to the .weights file with learned network. * @returns Network object that ready to do forward, throw an exception in failure cases. - * @returns Net object. */ CV_EXPORTS_W Net readNetFromDarknet(const String &cfgFile, const String &darknetModel = String()); diff --git a/modules/java/CMakeLists.txt b/modules/java/CMakeLists.txt index 33eca05988..7fe90a0cb3 100644 --- a/modules/java/CMakeLists.txt +++ b/modules/java/CMakeLists.txt @@ -3,7 +3,9 @@ if(OPENCV_INITIAL_PASS) add_subdirectory(generator) endif() -if(APPLE_FRAMEWORK OR WINRT OR NOT PYTHON_DEFAULT_AVAILABLE OR NOT (ANT_EXECUTABLE OR ANDROID_PROJECTS_BUILD_TYPE STREQUAL "GRADLE") +if(APPLE_FRAMEWORK OR WINRT + OR NOT PYTHON_DEFAULT_AVAILABLE + OR NOT (ANT_EXECUTABLE OR Java_FOUND OR ANDROID_PROJECTS_BUILD_TYPE STREQUAL "GRADLE") OR NOT (JNI_FOUND OR (ANDROID AND (NOT DEFINED ANDROID_NATIVE_API_LEVEL OR ANDROID_NATIVE_API_LEVEL GREATER 7))) OR BUILD_opencv_world ) diff --git a/modules/java/jar/CMakeLists.txt b/modules/java/jar/CMakeLists.txt index 33817bcc62..97533d0ee4 100644 --- a/modules/java/jar/CMakeLists.txt +++ b/modules/java/jar/CMakeLists.txt @@ -5,12 +5,13 @@ set(OPENCV_JAVA_DIR "${CMAKE_CURRENT_BINARY_DIR}/opencv" CACHE INTERNAL "") file(REMOVE_RECURSE "${OPENCV_JAVA_DIR}") file(REMOVE "${OPENCV_DEPHELPER}/${the_module}_jar_source_copy") -file(MAKE_DIRECTORY "${OPENCV_JAVA_DIR}/build/classes") set(java_src_dir "${OPENCV_JAVA_DIR}/java") file(MAKE_DIRECTORY "${java_src_dir}") -set(JAR_NAME opencv-${OPENCV_JAVA_LIB_NAME_SUFFIX}.jar) -set(OPENCV_JAR_FILE "${OpenCV_BINARY_DIR}/bin/${JAR_NAME}" CACHE INTERNAL "") +set(JAR_NAME_WE opencv-${OPENCV_JAVA_LIB_NAME_SUFFIX}) +set(JAR_NAME ${JAR_NAME_WE}.jar) +set(OPENCV_JAR_DIR "${OpenCV_BINARY_DIR}/bin/" CACHE INTERNAL "") +set(OPENCV_JAR_FILE "${OPENCV_JAR_DIR}${JAR_NAME}" CACHE INTERNAL "") ocv_copyfiles_append_dir(JAVA_SRC_COPY "${OPENCV_JAVA_BINDINGS_DIR}/gen/java" "${java_src_dir}") @@ -34,38 +35,98 @@ if(OPENCV_JAVADOC_LINK_URL) set(CMAKE_CONFIG_OPENCV_JAVADOC_LINK "link=\"${OPENCV_JAVADOC_LINK_URL}\"") endif() -configure_file("${CMAKE_CURRENT_SOURCE_DIR}/build.xml.in" "${OPENCV_JAVA_DIR}/build.xml" @ONLY) -list(APPEND depends "${OPENCV_JAVA_DIR}/build.xml") +if(OPENCV_JAVA_SDK_BUILD_TYPE STREQUAL "ANT") + file(MAKE_DIRECTORY "${OPENCV_JAVA_DIR}/build/classes") -ocv_cmake_byproducts(__byproducts BYPRODUCTS "${OPENCV_JAR_FILE}") -add_custom_command(OUTPUT "${OPENCV_DEPHELPER}/${the_module}_jar" - ${__byproducts} # required for add_custom_target() by ninja - COMMAND ${ANT_EXECUTABLE} -noinput -k jar - COMMAND ${CMAKE_COMMAND} -E touch "${OPENCV_DEPHELPER}/${the_module}_jar" - WORKING_DIRECTORY "${OPENCV_JAVA_DIR}" - DEPENDS ${depends} - COMMENT "Generating ${JAR_NAME}" -) -add_custom_target(${the_module}_jar DEPENDS "${OPENCV_DEPHELPER}/${the_module}_jar") + configure_file("${CMAKE_CURRENT_SOURCE_DIR}/build.xml.in" "${OPENCV_JAVA_DIR}/build.xml" @ONLY) + list(APPEND depends "${OPENCV_JAVA_DIR}/build.xml") + + ocv_cmake_byproducts(__byproducts BYPRODUCTS "${OPENCV_JAR_FILE}") + add_custom_command(OUTPUT "${OPENCV_DEPHELPER}/${the_module}_jar" + ${__byproducts} # required for add_custom_target() by ninja + COMMAND ${ANT_EXECUTABLE} -noinput -k jar + COMMAND ${CMAKE_COMMAND} -E touch "${OPENCV_DEPHELPER}/${the_module}_jar" + WORKING_DIRECTORY "${OPENCV_JAVA_DIR}" + DEPENDS ${depends} + COMMENT "Generating ${JAR_NAME}" + ) + add_custom_target(${the_module}_jar DEPENDS "${OPENCV_DEPHELPER}/${the_module}_jar") +elseif(OPENCV_JAVA_SDK_BUILD_TYPE STREQUAL "JAVA") + configure_file("${CMAKE_CURRENT_SOURCE_DIR}/MANIFEST.MF.in" "${OPENCV_JAVA_DIR}/MANIFEST.MF" @ONLY) + list(APPEND depends "${OPENCV_JAVA_DIR}/MANIFEST.MF") + + ocv_cmake_byproducts(__byproducts BYPRODUCTS "${OPENCV_JAVA_DIR}/java_sources") + add_custom_command(OUTPUT "${OPENCV_DEPHELPER}/${the_module}_jar" + BYPRODUCTS ${__byproducts} # required for add_custom_target() by ninja + DEPENDS ${depends} + COMMAND ${CMAKE_COMMAND} -E touch "${OPENCV_DEPHELPER}/${the_module}_jar" + COMMAND ${CMAKE_COMMAND} + -D OPENCV_JAVA_DIR="${OPENCV_JAVA_DIR}/java" + -D OUTPUT="${OPENCV_JAVA_DIR}/java_sources" + -P "${CMAKE_CURRENT_SOURCE_DIR}/list_java_sources.cmake" + ) + + add_custom_target(${the_module}_jar_sources + DEPENDS "${OPENCV_DEPHELPER}/${the_module}_jar" + ) + + list(APPEND CMAKE_JAVA_COMPILE_FLAGS -encoding utf-8 ${OPENCV_EXTRA_JAVA_COMPILE_FLAGS}) + + add_jar(${the_module}_jar + SOURCES "@${OPENCV_JAVA_DIR}/java_sources" + MANIFEST "${OPENCV_JAVA_DIR}/MANIFEST.MF" + OUTPUT_NAME "${JAR_NAME_WE}" + OUTPUT_DIR "${OPENCV_JAR_DIR}") + + add_dependencies(${the_module}_jar ${the_module}_jar_sources) +else() + ocv_assert(0) +endif() install(FILES ${OPENCV_JAR_FILE} OPTIONAL DESTINATION ${OPENCV_JAR_INSTALL_PATH} COMPONENT java) add_dependencies(${the_module} ${the_module}_jar) if(BUILD_DOCS) - add_custom_command(OUTPUT "${OPENCV_DEPHELPER}/${the_module}doc" - COMMAND ${ANT_EXECUTABLE} -noinput -k javadoc - COMMAND ${CMAKE_COMMAND} -E touch "${OPENCV_DEPHELPER}/${the_module}doc" - WORKING_DIRECTORY "${OPENCV_JAVA_DIR}" - DEPENDS ${depends} - COMMENT "Generating Javadoc" - ) - add_custom_target(${the_module}doc DEPENDS "${OPENCV_DEPHELPER}/${the_module}doc") - install(DIRECTORY ${OpenCV_BINARY_DIR}/doc/doxygen/html/javadoc - DESTINATION "${OPENCV_DOC_INSTALL_PATH}/html" - COMPONENT "docs" OPTIONAL - ${compatible_MESSAGE_NEVER} - ) + if(OPENCV_JAVA_SDK_BUILD_TYPE STREQUAL "ANT") + add_custom_command(OUTPUT "${OPENCV_DEPHELPER}/${the_module}doc" + COMMAND ${ANT_EXECUTABLE} -noinput -k javadoc + COMMAND ${CMAKE_COMMAND} -E touch "${OPENCV_DEPHELPER}/${the_module}doc" + WORKING_DIRECTORY "${OPENCV_JAVA_DIR}" + DEPENDS ${depends} + COMMENT "Generating Javadoc" + ) + add_custom_target(${the_module}doc DEPENDS "${OPENCV_DEPHELPER}/${the_module}doc") + + install(DIRECTORY ${OpenCV_BINARY_DIR}/doc/doxygen/html/javadoc + DESTINATION "${OPENCV_DOC_INSTALL_PATH}/html" + COMPONENT "docs" OPTIONAL + ${compatible_MESSAGE_NEVER} + ) + elseif(OPENCV_JAVA_SDK_BUILD_TYPE STREQUAL "JAVA") + set(Java_JAVADOC_EXECUTABLE ${Java_JAVADOC_EXECUTABLE} -encoding utf-8) + + # create_javadoc produces target ${_target}_javadoc + create_javadoc(${the_module} + FILES "@${OPENCV_JAVA_DIR}/java_sources" + SOURCEPATH "${OPENCV_JAVA_DIR}/java" + INSTALLPATH "${OPENCV_JAVADOC_DESTINATION}" + WINDOWTITLE "OpenCV ${OPENCV_VERSION_PLAIN} Java documentation" + DOCTITLE "OpenCV Java documentation (${OPENCV_VERSION})" + VERSION TRUE + ) + add_dependencies(${the_module}_javadoc ${the_module}_jar_sources) + add_custom_target(${the_module}doc DEPENDS ${the_module}_javadoc) + + install(DIRECTORY ${OpenCV_BINARY_DIR}/doc/doxygen/html/javadoc/${the_module}/ + DESTINATION "${OPENCV_DOC_INSTALL_PATH}/html/javadoc" + COMPONENT "docs" OPTIONAL + ${compatible_MESSAGE_NEVER} + ) + else() + ocv_assert(0) + endif() + set(CMAKE_DOXYGEN_JAVADOC_NODE "" CACHE INTERNAL "Link to the Java documentation") # set to the cache to make it global diff --git a/modules/java/jar/MANIFEST.MF.in b/modules/java/jar/MANIFEST.MF.in new file mode 100644 index 0000000000..07d2fda79b --- /dev/null +++ b/modules/java/jar/MANIFEST.MF.in @@ -0,0 +1,5 @@ +Specification-Title: OpenCV +Specification-Version: @OPENCV_VERSION@ +Implementation-Title: OpenCV +Implementation-Version: @OPENCV_VCSVERSION@ +Implementation-Date: @OPENCV_TIMESTAMP@ diff --git a/modules/java/jar/list_java_sources.cmake b/modules/java/jar/list_java_sources.cmake new file mode 100644 index 0000000000..e39a630e18 --- /dev/null +++ b/modules/java/jar/list_java_sources.cmake @@ -0,0 +1,19 @@ +file(GLOB_RECURSE java_sources "${OPENCV_JAVA_DIR}/*.java") + +set(__sources "") + +foreach(dst ${java_sources}) + set(__sources "${__sources}${dst}\n") +endforeach() + +function(ocv_update_file filepath content) + if(EXISTS "${filepath}") + file(READ "${filepath}" actual_content) + else() + set(actual_content "") + endif() + if(NOT ("${actual_content}" STREQUAL "${content}")) + file(WRITE "${filepath}" "${content}") + endif() +endfunction() +ocv_update_file("${OUTPUT}" "${__sources}")