svn commit: r1936596 - in subversion/trunk: . .github/workflows build/generator build/generator/templates

[email protected] Sun, 26 Jul 2026 08:54:41 -0000
Newsgroups gmane.comp.version-control.subversion.svn
Message-ID <178505608157.2625135.9966848241509790267@svn03-he-fi>
Author: jun66j5
Date: Sun Jul 26 08:54:41 2026
New Revision: 1936596

Log:
cmake: Support compilation of JavaHL bindings with CMake.

* .github/workflows/cmake.yml
  (Cache junit.jar):
    Save and restore junit.jar from cache.

  (Download and verify junit.jar):
    Download junit-4.13.2.jar and verify sha256 hash of the file.

  (Configure CMake):
    Enable build JavaHL and JavaHL tests if build using shared libs.

* CMakeLists.txt
  (SVN_ENABLE_JAVAHL):
    Add the option to build JavaHL.

  (SVN_ENABLE_JAVAHL_TESTS):
    Add the option to build JavaHL tests.

  (SVN_JAVAHL_DIR):
    Add the variable for path to install JavaHL jar file.

  (testing):
    Enable testing if `SVN_ENABLE_JAVAHL_TESTS` is enabled.

  (javahl):
    Add build, test and install steps for JavaHL and JavaHL tests.

  (status):
    Add `Build JavaHL` to status messages.

* build/generator/gen_cmake.py
  (get_target_conditions):
    Add `SVN_ENABLE_JAVAHL` and `SVN_ENABLE_JAVAHL_TESTS` for libsvnjavahl and
    TargetJava.

  (Generator.write):
    Add `is_java_test` to the template variables.

  (Generator.check_ignore_target):
    Do not ignore `libsvnjavahl`, `__JAVAHL__` and `__JAVAHL_TESTS__`.

* build/generator/templates/targets.cmake.ezt
  (javahl):
    Collect sources of javahl to SVN_JAVAHL_SOURCES or
    SVN_JAVAHL_TESTS_SOURCES.

Modified:
   subversion/trunk/.github/workflows/cmake.yml
   subversion/trunk/CMakeLists.txt
   subversion/trunk/build/generator/gen_cmake.py
   subversion/trunk/build/generator/templates/targets.cmake.ezt

Modified: subversion/trunk/.github/workflows/cmake.yml
==============================================================================
--- subversion/trunk/.github/workflows/cmake.yml	Sun Jul 26 08:30:50 2026	(r1936595)
+++ subversion/trunk/.github/workflows/cmake.yml	Sun Jul 26 08:54:41 2026	(r1936596)
@@ -223,6 +223,33 @@ jobs:
           ref: v1.4
           path: py3c
 
+      - name: Cache junit.jar
+        uses: actions/cache@v5
+        with:
+          path: junit.jar
+          key: junit-4.13.2.jar
+          enableCrossOsArchive: true
+
+      - name: Download and verify junit.jar
+        run: |
+          $ver = '4.13.2'
+          $url = "https://repo1.maven.org/maven2/junit/junit/$ver/junit-$ver.jar"
+          $file = Join-Path $env:GITHUB_WORKSPACE "junit.jar"
+          $hash = "8E495B634469D64FB8ACFA3495A065CBACC8A0FFF55CE1E31007BE4C16DC57D3"
+          if ((Test-Path -Path $file) -and
+              ((Get-FileHash $file -Algorithm SHA256).Hash -ne $hash)
+          ) {
+            Write-Warning "Remove the restored file due to hash mismatch"
+            Remove-Item -Path $file -Force
+          }
+          if (-not (Test-Path -Path $file)) {
+            Invoke-WebRequest $url -OutFile $file
+            if ((Get-FileHash $file -Algorithm SHA256).Hash -ne $hash) {
+              throw "Downloaded file verification failed."
+            }
+          }
+          Get-Item -Path $file | Format-List
+
       - name: gen-make
         run: python ./gen-make.py -t cmake
 
@@ -239,6 +266,8 @@ jobs:
           -DSVN_ENABLE_SWIG_PERL_MAN_PAGES=${{ runner.os != 'Windows' && 'ON' || 'OFF' }}
           -DSVN_ENABLE_SWIG_PYTHON=${{ runner.os != 'Windows' && 'ON' || 'OFF' }}
           -DSVN_ENABLE_SWIG_RUBY=${{ runner.os != 'Windows' && 'ON' || 'OFF' }}
+          -DSVN_ENABLE_JAVAHL=${{ matrix.build_shared }}
+          -DSVN_ENABLE_JAVAHL_TESTS=${{ matrix.build_shared }}
           -DCMAKE_INSTALL_PREFIX=${{ github.workspace }}/installdir
           -DVCPKG_TARGET_TRIPLET=${{ matrix.vcpkg_triplet }}
           -DSVN_TEST_CONFIGURE_FOR_PARALLEL=ON
@@ -248,6 +277,7 @@ jobs:
           -DPython3_FIND_STRATEGY=LOCATION
           -DPython3_FIND_UNVERSIONED_NAMES=FIRST
           -DPY3C_INCLUDE_DIR=${{ github.workspace }}/py3c/include
+          -DJUNIT_JAR="${{ github.workspace }}/junit.jar"
           ${{ matrix.extra_config_opts }}
 
       - name: Build CMake

Modified: subversion/trunk/CMakeLists.txt
==============================================================================
--- subversion/trunk/CMakeLists.txt	Sun Jul 26 08:30:50 2026	(r1936595)
+++ subversion/trunk/CMakeLists.txt	Sun Jul 26 08:54:41 2026	(r1936596)
@@ -101,6 +101,8 @@ option(SVN_ENABLE_SWIG_PERL "Enable Subv
 option(SVN_ENABLE_SWIG_PERL_MAN_PAGES "Enable man pages for Subversion Perl bindings" OFF)
 option(SVN_ENABLE_SWIG_PYTHON "Enable Subversion Python bindings" OFF)
 option(SVN_ENABLE_SWIG_RUBY "Enable Subversion Ruby bindings" OFF)
+option(SVN_ENABLE_JAVAHL "Enable Subversion JavaHL bindings" OFF)
+option(SVN_ENABLE_JAVAHL_TESTS "Enable tests for Subversion JavaHL bindings" OFF)
 set(SVN_SWIG_PERL_SITEARCH "${CMAKE_INSTALL_LIBDIR}/svn-perl"
   CACHE PATH "Path to install Subversion Perl bindings for sitearch")
 set(SVN_SWIG_PERL_MAN3DIR "${CMAKE_INSTALL_MANDIR}/man3"
@@ -113,6 +115,8 @@ set(SVN_SWIG_RUBY_SITELIB "${CMAKE_INSTA
   CACHE PATH "Path to install Subversion Ruby bindings for sitelib")
 set(SVN_SWIG_RUBY_SITEARCH "${CMAKE_INSTALL_LIBDIR}/svn-ruby"
   CACHE PATH "Path to install Subversion Ruby bindings for sitearch")
+set(SVN_JAVAHL_DIR "${CMAKE_INSTALL_DATAROOTDIR}/java"
+  CACHE PATH "Path to install Subversion JavaHL bindings")
 
 # Enable modules and features
 option(SVN_ENABLE_RA_LOCAL "Enable Subversion Local Repository Access Library" ON)
@@ -154,9 +158,7 @@ option(SVN_SQLITE_USE_AMALGAMATION "Use
 set(SQLiteAmalgamation_ROOT "${CMAKE_SOURCE_DIR}/sqlite-amalgamation" CACHE STRING "Directory with sqlite amalgamation")
 
 # Require C++ compiler
-if (SVN_ENABLE_SVNXX OR SVN_ENABLE_AUTH_KWALLET)
-  # TODO: Also add SVN_ENABLE_JAVAHL to the conditions when they done.
-
+if (SVN_ENABLE_SVNXX OR SVN_ENABLE_AUTH_KWALLET OR SVN_ENABLE_JAVAHL)
   enable_language(CXX)
 endif()
 
@@ -242,7 +244,7 @@ add_private_config_definition(
 )
 
 if (SVN_ENABLE_TESTS OR SVN_ENABLE_SWIG_PERL OR SVN_ENABLE_SWIG_PYTHON OR
-    SVN_ENABLE_SWIG_RUBY)
+    SVN_ENABLE_SWIG_RUBY OR SVN_ENABLE_JAVAHL_TESTS)
   enable_testing()
 endif()
 
@@ -310,6 +312,40 @@ if (SVN_ENABLE_SWIG_PERL OR SVN_ENABLE_S
   endif()
 endif()
 
+if(SVN_ENABLE_JAVAHL)
+  find_package(Java REQUIRED)
+  if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.24")
+    find_package(JNI REQUIRED COMPONENTS JVM)
+  else()
+    find_package(JNI REQUIRED)
+  endif()
+  include(UseJava)
+
+  if(NOT TARGET JNI::JNI)
+    add_library(JNI::JNI IMPORTED INTERFACE)
+  endif()
+  set_property(TARGET JNI::JNI PROPERTY INTERFACE_INCLUDE_DIRECTORIES
+    ${JAVA_INCLUDE_PATH})
+
+  set(CMAKE_JAVA_COMPILE_FLAGS)
+  if(Java_VERSION VERSION_LESS "9")
+    list(APPEND CMAKE_JAVA_COMPILE_FLAGS
+      -target 1.8
+      -source 1.8
+    )
+  else()
+    list(APPEND CMAKE_JAVA_COMPILE_FLAGS
+      --release 8
+    )
+  endif()
+
+  set(SVN_JAVAHL_SOURCES)
+  if(SVN_ENABLE_JAVAHL_TESTS)
+    set(SVN_JAVAHL_TESTS_SOURCES)
+    find_jar(JUNIT_JAR NAMES junit.jar)
+  endif()
+endif()
+
 if (MSVC)
   # Setup warning level
   add_compile_options(/W4)
@@ -1088,6 +1124,90 @@ if(SVN_ENABLE_SWIG_RUBY)
   test_prepend_builddir_to_path(swig-ruby)
 endif()
 
+if(SVN_ENABLE_JAVAHL)
+  add_jar(svn-javahl SOURCES ${SVN_JAVAHL_SOURCES}
+    GENERATE_NATIVE_HEADERS svn-javahl.headers
+      DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/javahl/include"
+    OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/javahl/lib"
+  )
+  add_custom_command(TARGET libsvnjavahl PRE_BUILD
+    COMMAND ${CMAKE_COMMAND} -E make_directory
+      "${CMAKE_CURRENT_BINARY_DIR}/javahl/native"
+  )
+  target_link_libraries(libsvnjavahl PRIVATE svn-javahl.headers)
+  add_library(external-java-sdk INTERFACE)
+  target_link_libraries(external-java-sdk INTERFACE
+    JNI::JNI
+  )
+  target_include_directories(external-java-sdk INTERFACE
+    ${JNI_INCLUDE_DIRS}
+    ${CMAKE_CURRENT_SOURCE_DIR}/subversion/bindings/javahl/native
+    ${CMAKE_CURRENT_SOURCE_DIR}/subversion/bindings/javahl/native/jniwrapper
+    ${CMAKE_CURRENT_BINARY_DIR}/javahl/native
+  )
+  target_link_libraries(external-java-sdk INTERFACE
+    ${JNI_LIBRARIES}
+  )
+
+  if(SVN_ENABLE_JAVAHL_TESTS)
+    add_jar(svn-javahl-tests
+      SOURCES ${SVN_JAVAHL_TESTS_SOURCES}
+      INCLUDE_JARS
+        "${CMAKE_CURRENT_BINARY_DIR}/javahl/lib/svn-javahl.jar"
+        "${JUNIT_JAR}"
+      OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/javahl/lib"
+    )
+    add_dependencies(svn-javahl-tests svn-javahl)
+
+    function(add_javahl_tests target)
+      if(WIN32)
+        set(sep "\\;")
+      else()
+        set(sep ":")
+      endif()
+      string(JOIN ${sep} classpath
+        "${CMAKE_CURRENT_BINARY_DIR}/javahl/lib/svn-javahl-tests.jar"
+        "${CMAKE_CURRENT_BINARY_DIR}/javahl/lib/svn-javahl.jar"
+        "${JUNIT_JAR}"
+      )
+      set(rootdir "${CMAKE_CURRENT_BINARY_DIR}/Testing/${target}")
+      file(MAKE_DIRECTORY "${rootdir}")
+
+      set(test_args)
+      if(Java_VERSION VERSION_GREATER_EQUAL "24")
+        list(APPEND test_args
+          --enable-native-access=ALL-UNNAMED
+        )
+      endif()
+      add_test(NAME ${target}
+        COMMAND
+          ${Java_JAVA_EXECUTABLE}
+          -Xcheck:jni
+          -Djava.library.path=$<TARGET_FILE_DIR:libsvnjavahl>
+          -Dtest.rootdir=${rootdir}
+          -Dtest.srcdir=${CMAKE_CURRENT_SOURCE_DIR}/subversion/bindings/javahl
+          -classpath
+          "${classpath}"
+          ${test_args}
+          ${ARGN}
+        WORKING_DIRECTORY
+          "${rootdir}"
+      )
+      if(WIN32 OR CYGWIN)
+        test_prepend_builddir_to_path(${target})
+      endif()
+    endfunction()
+
+    add_javahl_tests(javahl-tests-apache org.apache.subversion.javahl.RunTests)
+    add_javahl_tests(javahl-tests-tigris org.tigris.subversion.javahl.RunTests)
+    add_javahl_tests(javahl-tests-deprecated-authn
+      "-Dtest.authn.deprecated=true" org.apache.subversion.javahl.RunTests
+    )
+  endif()
+
+  install_jar(svn-javahl DESTINATION "${SVN_JAVAHL_DIR}")
+endif()
+
 ### Checks
 
 include(CheckIncludeFiles)
@@ -1370,3 +1490,4 @@ message(STATUS "    Build SVNXX ........
 message(STATUS "    Build SWIG_PERL ............... : ${SVN_ENABLE_SWIG_PERL}")
 message(STATUS "    Build SWIG_PYTHON ............. : ${SVN_ENABLE_SWIG_PYTHON}")
 message(STATUS "    Build SWIG_RUBY ............... : ${SVN_ENABLE_SWIG_RUBY}")
+message(STATUS "    Build JavaHL .................. : ${SVN_ENABLE_JAVAHL}")

Modified: subversion/trunk/build/generator/gen_cmake.py
==============================================================================
--- subversion/trunk/build/generator/gen_cmake.py	Sun Jul 26 08:30:50 2026	(r1936595)
+++ subversion/trunk/build/generator/gen_cmake.py	Sun Jul 26 08:54:41 2026	(r1936596)
@@ -39,6 +39,8 @@ def get_target_type(target):
     return "swig"
   if isinstance(target, gen_base.TargetSWIGProject):
     return "swig-project"
+  if isinstance(target, gen_base.TargetJava):
+    return "java"
   if isinstance(target, gen_base.TargetLib):
     return "lib"
   else:
@@ -81,6 +83,8 @@ def get_target_conditions(target):
       enable_condition.append("SVN_ENABLE_AUTH_KWALLET")
     elif target.name == "libsvn_auth_gnome_keyring":
       enable_condition.append("SVN_ENABLE_AUTH_GNOME_KEYRING")
+    elif target.name == "libsvnjavahl":
+      enable_condition.append("SVN_ENABLE_JAVAHL")
 
   if isinstance(target, gen_base.TargetExe):
     if target.install == "test" or target.install == "sub-test":
@@ -97,6 +101,11 @@ def get_target_conditions(target):
      isinstance(target, gen_base.TargetSWIGLib):
     enable_condition.append("SVN_ENABLE_SWIG_" + target.lang.upper())
 
+  if isinstance(target, gen_base.TargetJava):
+    enable_condition.append("SVN_ENABLE_JAVAHL_TESTS"
+                            if target.name.endswith("-tests") else
+                            "SVN_ENABLE_JAVAHL")
+
   if isinstance(target, gen_base.TargetApacheMod):
     enable_condition.append("SVN_ENABLE_APACHE_MODULES")
 
@@ -127,6 +136,7 @@ class Generator(gen_base.GeneratorBase):
       build_type = None
       swig_lang = None
       is_apache_mod = None
+      is_java_test = None
 
       if isinstance(target, gen_base.TargetScript):
         # there is nothing to build
@@ -141,6 +151,9 @@ class Generator(gen_base.GeneratorBase):
         is_apache_mod = True
       elif isinstance(target, gen_base.TargetSWIG):
         swig_lang = target.lang
+      elif isinstance(target, gen_base.TargetJava):
+        if target.name.endswith("-tests"):
+          is_java_test = True
       elif isinstance(target, gen_base.TargetLib):
         if target.msvc_static:
           build_type = "STATIC"
@@ -198,7 +211,7 @@ class Generator(gen_base.GeneratorBase):
 
       target_type = get_target_type(target)
 
-      if target_type in ["exe", "lib", "test", "swig"]:
+      if target_type in ["exe", "lib", "test", "swig", "java"]:
         msvc_libs = []
         msvc_objects = []
 
@@ -239,6 +252,7 @@ class Generator(gen_base.GeneratorBase):
           srcdir = target.path,
           install_target = ezt.boolean(install_target),
           swig_lang = swig_lang,
+          is_java_test = is_java_test,
           is_apache_mod = is_apache_mod,
           namespace = os.path.basename(target.path),
         )
@@ -281,10 +295,6 @@ class Generator(gen_base.GeneratorBase):
   def check_ignore_target(self, target):
     ignore_names = [
       "svnxx-tests",
-
-      "libsvnjavahl",
-      "__JAVAHL__",
-      "__JAVAHL_TESTS__",
     ]
 
     for name in ignore_names:

Modified: subversion/trunk/build/generator/templates/targets.cmake.ezt
==============================================================================
--- subversion/trunk/build/generator/templates/targets.cmake.ezt	Sun Jul 26 08:30:50 2026	(r1936595)
+++ subversion/trunk/build/generator/templates/targets.cmake.ezt	Sun Jul 26 08:54:41 2026	(r1936596)
@@ -62,6 +62,9 @@ if ([targets.enable_condition])[is targe
     "${SVN_SWIG_PYTHON_SITEARCH}/libsvn"[end][is targets.swig_lang "perl"]
     "${SVN_SWIG_PERL_SITEARCH}/auto/SVN/[targets.output_name]"[end][is targets.swig_lang "ruby"]
     "${SVN_SWIG_RUBY_SITEARCH}/svn/ext"[end]
+  )[else][is targets.type "java"]
+  list(APPEND [if-any targets.is_java_test]SVN_JAVAHL_TESTS_SOURCES[else]SVN_JAVAHL_SOURCES[end][for targets.sources]
+    [targets.sources][end]
   )[else][is targets.type "lib"]
   add_library([targets.name][if-any targets.build_type] [targets.build_type][end][for targets.sources]
     [targets.sources][end]
@@ -117,6 +120,6 @@ if ([targets.enable_condition])[is targe
   endif()[if-any targets.install_target]
   install(TARGETS [targets.name][if-any targets.is_apache_mod]
     LIBRARY DESTINATION "${HTTPD_MODULES_DIR}"
-  [end])[end][end]
+  [end])[end][end][end]
 endif()
 [end]