This is an automated email from the ASF dual-hosted git repository.

leginee pushed a commit to branch bazel-migration
in repository https://gitbox.apache.org/repos/asf/openoffice.git

commit af1706569a19941eadb9310a9601ba48bb02867c
Author: Peter Kovacs <[email protected]>
AuthorDate: Wed Aug 5 08:03:26 2026 +0200

    build(stoc): build javaloader.uno + javavm.uno — the Java2 loader was 
missing
    
    First step of the Java bucket, and it turned out not to be javamaker 
(already
    built) but the fact that com.sun.star.loader.Java2 had no implementation at 
all.
    
    javaloader.uno.dll (com.sun.star.comp.stoc.JavaComponentLoader — builds a 
class
    loader over a component's jar and calls its RegistrationClassName) and
    javavm.uno.dll (com.sun.star.comp.stoc.JavaVirtualMachine — locates/starts 
the
    JVM via jvmfwk) were NEVER BUILT, while both were registered in services.rdb
    MAPPED TO bootstrap.uno.dll as a placeholder.  That could never work: 
neither
    implementation is in that DLL, so any Java UNO component would fail to
    instantiate however it was registered.  Both are now built, staged, and
    registered at their real DLLs.
    
    Upstream gates them behind SOLAR_JAVA; unconditional here, since the Bazel
    build always has a JDK toolchain (rules_java is a hard dep).
    
    Two landmines, both in the C++/JNI seam:
    
    SOLAR_JAVA IS LOAD-BEARING, not a feature switch.  
jvmaccess/virtualmachine.hxx
    #includes the real <jni.h> only under it, and otherwise declares stubs
    (struct JNIEnv;, typedef void * jobject;).  Without it every JNIEnv-> call 
is
    C2027 "use of undefined type" — even in javaloader.cxx, which #includes
    "jni.h" ITSELF, because the incomplete stub is already in scope by then.  
Same
    landmine as the java_uno JNI bridge in //main/bridges.
    
    javavm needs /Zc:wchar_t-, javaloader does not.  javavm.cxx passes 
sal_Unicode*
    straight into JNI calls (NewString, GetStringRegion).  On Windows 
sal_Unicode
    IS wchar_t (sal/types.h), and with native wchar_t that is a distinct type 
from
    jchar (unsigned short), so every such call is C2664 "types pointed to are
    unrelated".  /Zc:wchar_t- makes wchar_t == unsigned short == jchar.  
javaloader
    escapes it by only ever handing JNI plain UTF-8 (NewStringUTF).
    
    NOT yet sufficient to RUN a Java component — the DLLs are necessary, not
    sufficient.  Remaining chain, in the order javavm.cxx::getJavaVM walks it:
      1. URE_INTERNAL_JAVA_DIR must be expandable by theMacroExpander, which
         resolves against the URE_BOOTSTRAP file — program/fundamental.ini, NOT
         uno.ini.  staging/uno.ini already sets it (and
         URE_INTERNAL_JAVA_CLASSPATH); fundamental.ini does not, and that is the
         one that counts — the same trap the extension-path macros already hit.
      2. program/classes/ staging does not exist.  getJavaVM bootstraps from
         $URE_INTERNAL_JAVA_DIR/unoloader.jar → URLClassLoader → UnoClassLoader,
         which then builds the real classpath.  Every jar target already exists
         (ridljar:unoloader, jurt, juh_jar, bridges:java_uno_jar, unoil) but
         stage_install.bzl has no classes/ destination.
      3. jvmfwk needs a JRE to find (javavendors.xml + jvmfwk3 config), not 
staged.
    
    So the next step is staging, not compilation.  See main/stoc/readme.md.
    
    Verified: both DLLs compile and link; //main/staging:install and
    //main/postprocess:services_rdb still analyse clean.
    
    Co-Authored-By: Claude Opus 5 <[email protected]>
---
 main/postprocess/BUILD.bazel |  12 ++++--
 main/staging/BUILD.bazel     |   9 ++++
 main/stoc/BUILD.bazel        | 100 +++++++++++++++++++++++++++++++++++++++++++
 main/stoc/readme.md          |  91 ++++++++++++++++++++++++++++++++++++++-
 4 files changed, 207 insertions(+), 5 deletions(-)

diff --git a/main/postprocess/BUILD.bazel b/main/postprocess/BUILD.bazel
index 2355f7c8b9..639e1d8426 100644
--- a/main/postprocess/BUILD.bazel
+++ b/main/postprocess/BUILD.bazel
@@ -47,12 +47,16 @@ _SERVICES_COMPONENTS = {
         basis_native("invocadapt.uno.dll"),
     "//main/stoc:source/invocation/invocation.component":
         basis_native("invocation.uno.dll"),
-    # javaloader/javavm: Java components (deferred) — still mapped to
-    # bootstrap.uno.dll (not built; only loaded if Java is used).
+    # javaloader/javavm — the two halves of com.sun.star.loader.Java2, i.e.
+    # what makes loading a UNO component written in Java possible at all.
+    # They used to be mapped to bootstrap.uno.dll as a PLACEHOLDER, which could
+    # never work: neither implementation is in that DLL, so any Java component
+    # would fail to instantiate no matter how it was registered.  Both are now
+    # built (//main/stoc) and staged, so point at them for real.
     "//main/stoc:source/javaloader/javaloader.component":
-        basis_native("bootstrap.uno.dll"),
+        basis_native("javaloader.uno.dll"),
     "//main/stoc:source/javavm/javavm.component":
-        basis_native("bootstrap.uno.dll"),
+        basis_native("javavm.uno.dll"),
     "//main/stoc:source/namingservice/namingservice.component":
         basis_native("namingservice.uno.dll"),
     "//main/stoc:source/proxy_factory/proxyfac.component":
diff --git a/main/staging/BUILD.bazel b/main/staging/BUILD.bazel
index 79f05f2099..02fb4fa870 100644
--- a/main/staging/BUILD.bazel
+++ b/main/staging/BUILD.bazel
@@ -83,6 +83,15 @@ collect_outputs(
         # (java_uno.jar) needs the program/classes/ classpath staging, which 
does
         # not exist yet — see readme.md "jni_uno" notes.
         "//main/bridges:java_uno",
+        # com.sun.star.loader.Java2, in two halves: javavm starts/locates the
+        # JVM through jvmfwk, javaloader is the loader that builds a class
+        # loader over a component's jar.  Registered in services.rdb by
+        # //main/postprocess.  NOTE these being present is necessary but NOT
+        # sufficient to run a Java component — program/classes/ staging and the
+        # URE_INTERNAL_JAVA_DIR bootstrap variable are still missing; see
+        # main/stoc/readme.md.
+        "//main/stoc:javaloader.uno",
+        "//main/stoc:javavm.uno",
         "//main/io:streams",
         "//main/io:acceptor",
         "//main/io:connector",
diff --git a/main/stoc/BUILD.bazel b/main/stoc/BUILD.bazel
index 14998bc85e..83209aef5a 100644
--- a/main/stoc/BUILD.bazel
+++ b/main/stoc/BUILD.bazel
@@ -210,5 +210,105 @@ _REFL_COMPONENTS = {
     for _name, _srcs in _REFL_COMPONENTS.items()
 ]
 
+# ── Java UNO loader: javaloader.uno.dll + javavm.uno.dll ──────────
+# These two are what makes `com.sun.star.loader.Java2` real, i.e. what lets the
+# office load a UNO component written in Java at all.  Until now both were
+# registered in services.rdb but MAPPED TO bootstrap.uno.dll as a placeholder
+# (postprocess/BUILD.bazel), which cannot work — neither implementation is in
+# that DLL, so any Java component would fail to instantiate.
+#   * javavm.uno.dll     — com.sun.star.comp.stoc.JavaVirtualMachine: starts /
+#     locates the JVM through jvmfwk and hands out a jvmaccess::VirtualMachine.
+#   * javaloader.uno.dll — com.sun.star.comp.stoc.JavaComponentLoader: the
+#     Java2 loader itself; builds a class loader over the component's jar and
+#     calls its RegistrationClassName.
+# Upstream gates both behind SOLAR_JAVA; here they are unconditional, because
+# the Bazel build always has a JDK toolchain (rules_java is a hard dep).
+#
+# They do not fit _REFL_COMPONENTS: both need jvmaccess, javavm additionally
+# needs jvmfwk, the JNI headers and advapi32 (it reads the registry to find an
+# installed JRE).
+# SOLAR_JAVA is LOAD-BEARING, not just a feature switch: jvmaccess/
+# virtualmachine.hxx #includes the real <jni.h> only under it, and otherwise
+# declares stubs (`struct JNIEnv;`, `typedef void * jobject;`).  Without it
+# every JNIEnv-> call is C2027 "use of undefined type", even though the file
+# #includes "jni.h" itself — the stub declaration is what the compiler already
+# has by then.  Same landmine as the java_uno JNI bridge (//main/bridges).
+_JAVA_LOADER_DEFINES = _DEFINES + ["SOLAR_JAVA"]
+
+_JAVA_LOADER_IMPLIBS = _REFL_IMPLIBS + [
+    "//main/jvmaccess:jvmaccess3MSC_implib",
+]
+
+_JAVA_LOADER_LINKOPTS = [
+    "$(execpath //main/sal:sal_implib)",
+    "$(execpath //main/salhelper:salhelper_implib)",
+    "$(execpath //main/cppu:cppu3_implib)",
+    "$(execpath //main/cppuhelper:cppuhelper_implib)",
+    "$(execpath //main/registry:reg_implib)",
+    "$(execpath //main/jvmaccess:jvmaccess3MSC_implib)",
+    "/MANIFEST:NO",
+]
+
+cc_binary(
+    name = "javaloader.uno",
+    srcs = ["source/javaloader/javaloader.cxx"],
+    copts = _COPTS,
+    defines = _JAVA_LOADER_DEFINES,
+    deps = _DEPS + [
+        "//main/jvmaccess:jvmaccess_headers",
+        # javaloader.cxx calls JNIEnv methods but never #includes <jni.h>: it
+        # gets only the forward declaration from jvmaccess/virtualmachine.hxx
+        # and relies on the build system's JAVAINCLUDES (dmake supplies those
+        # from settings.mk when SOLAR_JAVA=TRUE).  Without this the whole file
+        # is C2027 "use of undefined type 'JNIEnv'".
+        "@rules_java//toolchains:jni",
+    ],
+    additional_linker_inputs = _JAVA_LOADER_IMPLIBS,
+    linkshared = True,
+    win_def_file = "util/component.def",
+    linkopts = _JAVA_LOADER_LINKOPTS,
+    visibility = ["//visibility:public"],
+)
+
+cc_binary(
+    name = "javavm.uno",
+    srcs = [
+        "source/javavm/interact.cxx",
+        "source/javavm/interact.hxx",
+        "source/javavm/javavm.cxx",
+        "source/javavm/javavm.hxx",
+        "source/javavm/jvmargs.cxx",
+        "source/javavm/jvmargs.hxx",
+    ],
+    # /Zc:wchar_t- — javavm.cxx passes sal_Unicode* straight into JNI calls
+    # (NewString, GetStringRegion).  On Windows sal_Unicode IS wchar_t
+    # (sal/types.h), and with NATIVE wchar_t that is a distinct type from
+    # jchar (unsigned short), so every one of those calls is C2664 "types
+    # pointed to are unrelated".  /Zc:wchar_t- makes wchar_t == unsigned short
+    # == jchar and they line up.  Exactly the same reason //main/bridges builds
+    # the jni_uno sources this way; javaloader.uno needs no such thing because
+    # it only ever hands JNI plain UTF-8 (NewStringUTF).
+    copts = _COPTS + ["/Zc:wchar_t-"],
+    defines = _JAVA_LOADER_DEFINES,
+    deps = _DEPS + [
+        "//main/jvmaccess:jvmaccess_headers",
+        "//main/jvmfwk:jvmfwk_headers",
+        # jni.h / jni_md.h from the toolchain JDK — same dep the java_uno JNI
+        # bridge uses, so the two cannot disagree on JNI version.
+        "@rules_java//toolchains:jni",
+    ],
+    additional_linker_inputs = _JAVA_LOADER_IMPLIBS + [
+        "//main/jvmfwk:jvmfwk3_implib",
+    ],
+    linkshared = True,
+    win_def_file = "util/component.def",
+    linkopts = _JAVA_LOADER_LINKOPTS + [
+        "$(execpath //main/jvmfwk:jvmfwk3_implib)",
+        # javavm.cxx reads the JRE location out of the Windows registry.
+        "advapi32.lib",
+    ],
+    visibility = ["//visibility:public"],
+)
+
 exports_files(glob(["**/*.component"]))
 
diff --git a/main/stoc/readme.md b/main/stoc/readme.md
index be5d1c05f4..e52908376e 100644
--- a/main/stoc/readme.md
+++ b/main/stoc/readme.md
@@ -1,19 +1,108 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+-->
+
 # Notes for stoc (done)
 
-- javavm/javaloader/jvmfwk/jvmaccess skipped — only C++ URE components needed
+- javaloader + javavm now BUILT (see below).  jvmfwk/jvmaccess are their own
+  modules and were already migrated.
 
 ## bootstrap.uno.dll
+
 9 sub-components merged into one DLL:
 bootstrap, security, servicemanager, simpleregistry, defaultregistry,
 implementationregistration, loader, registry_tdprovider, tdmanager
 
 ## stocservices.uno.dll
+
 stocservices + typeconv + uriproc
 
 ## unistd.h stub
+
 `unistd.h` included unconditionally in implreg.cxx — satisfied by 
`main/soltools/winunistd/unistd.h` stub.
 Add `/Imain/soltools/winunistd` to copts wherever this pattern appears in 
other modules.
 
 ## DEF exports
+
 Standard UNO unloadable component pattern — same for all future component DLLs:
 `component_getImplementationEnvironment`, `component_getFactory`, 
`component_canUnload`
+
+## javaloader.uno.dll + javavm.uno.dll — enabling `com.sun.star.loader.Java2`
+
+These two are what makes loading a UNO component *written in Java* possible at
+all:
+
+- **`javavm.uno.dll`** — `com.sun.star.comp.stoc.JavaVirtualMachine`: locates
+  and starts the JVM through `jvmfwk`, hands out a `jvmaccess::VirtualMachine`.
+- **`javaloader.uno.dll`** — `com.sun.star.comp.stoc.JavaComponentLoader`: the
+  Java2 loader; builds a class loader over a component's jar and calls its
+  `RegistrationClassName`.
+
+Until now **neither was built**, while both were registered in `services.rdb`
+*mapped to `bootstrap.uno.dll`* as a placeholder. That could never work —
+neither implementation is in that DLL — so any Java component would have failed
+to instantiate however it was registered. Both are now built, staged, and
+registered at their real DLLs.
+
+Upstream gates both behind `SOLAR_JAVA`; here they are unconditional, because
+the Bazel build always has a JDK toolchain (`rules_java` is a hard dep).
+
+### Two landmines, both in the C++/JNI seam
+
+**`SOLAR_JAVA` is load-bearing, not a feature switch.**
+`jvmaccess/virtualmachine.hxx` `#include`s the real `<jni.h>` *only* under it,
+and otherwise declares stubs (`struct JNIEnv;`, `typedef void * jobject;`).
+Without it every `JNIEnv->` call is `C2027 "use of undefined type 'JNIEnv'"` —
+even in `javaloader.cxx`, which `#include`s `"jni.h"` itself, because the
+incomplete stub is already in scope by then. Same landmine as the java_uno JNI
+bridge in `//main/bridges`.
+
+**`javavm` needs `/Zc:wchar_t-`; `javaloader` does not.** `javavm.cxx` passes
+`sal_Unicode*` straight into JNI calls (`NewString`, `GetStringRegion`). On
+Windows `sal_Unicode` *is* `wchar_t` (`sal/types.h`), and with native `wchar_t`
+that is a distinct type from `jchar` (`unsigned short`) — so every such call is
+`C2664 "types pointed to are unrelated"`. `/Zc:wchar_t-` makes
+`wchar_t == unsigned short == jchar`. `javaloader` escapes this because it only
+ever hands JNI plain UTF-8 (`NewStringUTF`).
+
+### NOT yet sufficient to run a Java component
+
+Having the DLLs is necessary but not enough. The remaining chain, in the order
+`javavm.cxx::getJavaVM` walks it:
+
+1. **`URE_INTERNAL_JAVA_DIR` must be expandable** by
+   `com.sun.star.util.theMacroExpander`, which resolves against the
+   `URE_BOOTSTRAP` file — i.e. `program/fundamental.ini`, **not** `uno.ini`.
+   `main/staging/uno.ini` already sets 
`URE_INTERNAL_JAVA_DIR=${ORIGIN}/classes`
+   and `URE_INTERNAL_JAVA_CLASSPATH=${URE_MORE_JAVA_CLASSPATH_URLS}`, but
+   `fundamental.ini` does not — and that is the one that counts. Same trap the
+   extension-path macros already hit; see the long comment in
+   `main/staging/fundamental.ini`. `URE_INTERNAL_JAVA_CLASSPATH` is allowed to
+   be unexpandable, `URE_INTERNAL_JAVA_DIR` is not.
+2. **`program/classes/` staging does not exist.** `getJavaVM` bootstraps from
+   `$URE_INTERNAL_JAVA_DIR/unoloader.jar` → `URLClassLoader` →
+   `com.sun.star.lib.unoloader.UnoClassLoader`, which then builds the real
+   classpath. Every jar target already exists — `//main/ridljar:unoloader`,
+   `//main/jurt:jurt`, `//main/javaunohelper:juh_jar`,
+   `//main/bridges:java_uno_jar`, `//main/unoil:unoil` — but
+   `stage_install.bzl` has no `classes/` destination for them.
+3. **`jvmfwk` needs a JRE to find.** `javavendors.xml` plus the `jvmfwk3`
+   config decide which JVM is selected; without them `jvmfwk` reports no JRE
+   and `javavm` throws. Not yet staged.
+
+So the next Java-bucket step is **staging, not compilation**.

Reply via email to