<!DOCTYPE html><html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  </head>
  <body>
    <p>On 2024-04-02 21:16, Jiangli Zhou wrote:</p>
    <blockquote type="cite" cite="mid:CALrW1jx9h-nhKNV9EYnnzahPZAhYLjKtTwEaLjhjEoN7AWhicg@mail.gmail.com">
      
      <div dir="ltr">
        <div dir="ltr">Hi Magnus,
          <div><br>
          </div>
          <div>In today's zoom meeting with Alan, Ron, Liam and Chuck,
            we (briefly) discussed how to move forward contributing the
            static Java related changes (additional runtime
            fixes/enhancements on top of the existing static support in
            JDK) from <a href="https://github.com/openjdk/leyden/tree/hermetic-java-runtime" moz-do-not-send="true" class="moz-txt-link-freetext">https://github.com/openjdk/leyden/tree/hermetic-java-runtime</a>
            to JDK mainline.</div>
          <div><br>
          </div>
          <div>Just a bit more details/context below, which may be
            useful for others reading this thread.</div>
          <div><br>
          </div>
          <div>The <a href="https://github.com/openjdk/leyden/tree/hermetic-java-runtime" moz-do-not-send="true" class="moz-txt-link-freetext">https://github.com/openjdk/leyden/tree/hermetic-java-runtime</a>
            branch currently contains following for supporting hermetic
            Java (without the launcher work for runtime support):</div>
          <div><br>
          </div>
          <div>1. Build change for linking the Java launcher (as
            bin/javastatic) with JDK/hotspot static libraries (.a),
            mainly in <a href="https://github.com/openjdk/leyden/blob/hermetic-java-runtime/make/StaticLink.gmk" moz-do-not-send="true" class="moz-txt-link-freetext">https://github.com/openjdk/leyden/blob/hermetic-java-runtime/make/StaticLink.gmk</a>.
            The part for creating the complete sets of static libraries
            (including libjvm.a) has already been included in the
            mainline since last year. <a href="https://github.com/openjdk/leyden/blob/hermetic-java-runtime/make/StaticLink.gmk" moz-do-not-send="true" class="moz-txt-link-freetext">https://github.com/openjdk/leyden/blob/hermetic-java-runtime/make/StaticLink.gmk</a>
            is in a very raw state and is intended to demonstrate the
            capability of building a static Java launcher.</div>
        </div>
      </div>
    </blockquote>
    Indeed. It is nowhere near being able to be integrated.<br>
    <blockquote type="cite" cite="mid:CALrW1jx9h-nhKNV9EYnnzahPZAhYLjKtTwEaLjhjEoN7AWhicg@mail.gmail.com">
      <div dir="ltr">
        <div dir="ltr">
          <div><br>
          </div>
          <div>2. Additional runtime fixes/enhancements on top of the
            existing static support in JDK, e.g. support further lookup
            dynamic native library if the built-in native library cannot
            be found.</div>
          <div><br>
          </div>
          <div>3. Some initial (prototype) work on supporting hermetic
            JDK resource files in the jimage (JDK modules image). </div>
          <div><br>
          </div>
          <div>To move forward, one of the earliest items needed is to
            add the capability of building the fully statically linked
            Java launcher in JDK mainline. The other static Java runtime
            changes can be followed up after the launcher linking part,
            so they can be built and tested as individual PRs created
            for the JDK mainline. Magnus, you have expressed interest in
            helping get the launcher linking part (refactor from <a href="https://github.com/openjdk/leyden/blob/hermetic-java-runtime/make/StaticLink.gmk" moz-do-not-send="true" class="moz-txt-link-freetext">https://github.com/openjdk/leyden/blob/hermetic-java-runtime/make/StaticLink.gmk</a>)
            into JDK mainline. What's your thought on prioritizing the
            launcher static linking part before other makefile clean ups
            for static libraries?</div>
        </div>
      </div>
    </blockquote>
    <p>Trust me, my absolute top priority now is working on getting the
      proper build support needed for Hermetic Java. I can't prioritize
      it any higher. <br>
    </p>
    <p>I am not sure what you are asking for. We can't just merge
      StaticLink.gmk from your prototype. And even if we did, what good
      will it do you? <br>
    </p>
    <p>The problem you are running into is that the build system has not
      been designed to properly support static linking. There are
      already 3-4 hacks in place to get something sort-of useful out,
      but they are prone to breaking. I assume that we agree that for
      Hermetic Java to become a success, we need to have a stable
      foundation for static builds.</p>
    <p>The core problem of all static linking hacks is that they are not
      integrated in the right place. They need to be a core part of what
      NativeCompilation delivers, not something done in a separate file.
      To put it in other words, StaticLink.gmk from your branch do not
      need cleanup -- it needs to go away, and the functionality moved
      to the proper place.</p>
    <p>My approach is that NativeCompilation should support doing either
      only dynamic linking (as today), or static linking (as today with
      STATIC_LIBS or STATIC_BUILD), or both. The assumption is that the
      latter will be default, or at least should be tested by default in
      GHA. For this to work, we need to compile the source code to .o
      files only once, and then link these .o files either into a
      dynamic or a static library (or both). <br>
    </p>
    <p>This, in turn, require several changes:</p>
    <p>1) The linking code needs to be cleaned up, and all technical
      debt needs to be resolved. This is what I have been doing since I
      started working on static builds for Hermetic Java. JDK-8329704
      (which was integrated yesterday) was the first major milestone of
      this cleanup. Now, the path were to find a library created by the
      JDK (static or dynamic) is encapsulated in ResolveLibPath. This is
      currently a monster, but at least all knowledge is collected in a
      single location, instead of spread over the code base. Getting
      this simplified is the next step.<br>
    </p>
    <p>2) We need to stop passing the STATIC_BUILD define when
      compiling. This is partially addressed in your PR, where you have
      replaced #ifdef STATIC_BUILD with a dynamic lookup. But there is
      also the problem of JNI/JVMTI entry points. I have been pondering
      how we can compile the code in a way so we support both dynamic
      and static name resolution, and I think I have a solution. </p>
    <p>This is unfortunately quite complex, and I have started a
      discussion with Alan if it is possible to update the JNI spec so
      that both static and dynamic entry points can have the form
      "JNI_OnLoad_<library-name>". Ideally, I'd like to see us
      push for this with as much effort as possible. If we got this in
      place, static builds would be much easier, and the changes
      required for Hermetic Java even smaller.<br>
    </p>
    <p>And finally, on top of all of this, is the question of widening
      the platform support. To support linux/gcc with objcopy is
      trivial, but the question about Windows still remain. I have two
      possible ways forward, one is to check if there is alternative
      tooling to use (the prime candidate is the clang-ldd), and the
      other is to try to "fake" a partial linking by concatenating all
      source code before compiling. This is not ideal, though, for many
      reasons, and I am not keen on implementing it, not even for
      testing. And at this point, I have not had time to investigate any
      of these options much further, since I have been focusing on 1)
      above.<br>
    </p>
    <p>A third option is of course to just say that due to toolchain
      limitations, static linking is not available on Windows. <br>
    </p>
    <p>My recommendation is that you keep on working to resolve the
      (much more thorny) issues of resource access in Hermetic Java in
      your branch, where you have a prototype static build that works
      for you. In the meantime, I will make sure that there will be a
      functioning, stable and robust way of creating static builds in
      the mainline, that can be regularly tested and not bit-rot, like
      the static build hacks that has gone in before.</p>
    <p>/Magnus<br>
    </p>
    <p><br>
    </p>
    <blockquote type="cite" cite="mid:CALrW1jx9h-nhKNV9EYnnzahPZAhYLjKtTwEaLjhjEoN7AWhicg@mail.gmail.com">
      <div dir="ltr">
        <div dir="ltr">
          <div><br>
          </div>
          <div>Thanks!</div>
          <div>Jiangli</div>
        </div>
        <br>
        <div class="gmail_quote">
          <div dir="ltr" class="gmail_attr">On Thu, Feb 15, 2024 at
            12:01 PM Jiangli Zhou <<a href="mailto:jianglizhou@google.com" moz-do-not-send="true" class="moz-txt-link-freetext">jianglizhou@google.com</a>>
            wrote:<br>
          </div>
          <blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">On
            Wed, Feb 14, 2024 at 5:07 PM Jiangli Zhou <<a href="mailto:jianglizhou@google.com" target="_blank" moz-do-not-send="true" class="moz-txt-link-freetext">jianglizhou@google.com</a>>
            wrote:<br>
            ><br>
            > Hi Magnus,<br>
            ><br>
            > Thanks for looking into this from the build
            perspective.<br>
            ><br>
            > On Wed, Feb 14, 2024 at 1:00 AM Magnus Ihse Bursie<br>
            > <<a href="mailto:magnus.ihse.bursie@oracle.com" target="_blank" moz-do-not-send="true" class="moz-txt-link-freetext">magnus.ihse.bursie@oracle.com</a>>
            wrote:<br>
            > ><br>
            > > First some background for build-dev: I have spent
            some time looking at<br>
            > > the build implications of the Hermetic Java
            effort, which is part of<br>
            > > Project Leyden. A high-level overview is available
            here:<br>
            > > <a href="https://cr.openjdk.org/~jiangli/hermetic_java.pdf" rel="noreferrer" target="_blank" moz-do-not-send="true" class="moz-txt-link-freetext">https://cr.openjdk.org/~jiangli/hermetic_java.pdf</a>
            and the current source<br>
            > > code is here: <a href="https://github.com/openjdk/leyden/tree/hermetic-java-runtime" rel="noreferrer" target="_blank" moz-do-not-send="true" class="moz-txt-link-freetext">https://github.com/openjdk/leyden/tree/hermetic-java-runtime</a>.<br>
            ><br>
            > Some additional hermetic Java related references that
            are also useful:<br>
            ><br>
            > - <a href="https://bugs.openjdk.org/browse/JDK-8303796" rel="noreferrer" target="_blank" moz-do-not-send="true" class="moz-txt-link-freetext">https://bugs.openjdk.org/browse/JDK-8303796</a>
            is an umbrella bug that<br>
            > links to the issues for resolving static linking issues
            so far<br>
            > - <a href="https://github.com/openjdk/jdk21/pull/26" rel="noreferrer" target="_blank" moz-do-not-send="true" class="moz-txt-link-freetext">https://github.com/openjdk/jdk21/pull/26</a>
            is the enhancement for<br>
            > building the complete set of static libraries in
            JDK/VM, particularly<br>
            > including libjvm.a<br>
            ><br>
            > ><br>
            > > Hermetic Java faces several challenges, but the
            part that is relevant<br>
            > > for the build system is the ability to create
            static libraries. We've<br>
            > > had this functionality (in three different
            ways...) for some time, but<br>
            > > it is rather badly implemented.<br>
            > ><br>
            > > As a result of my investigations, I have a bunch
            of questions. :-) I<br>
            > > have gotten some answers in private discussion,
            but for the sake of<br>
            > > transparency I will repeat them here, to foster an
            open dialogue.<br>
            > ><br>
            > > 1. Am I correct in understanding that the ultimate
            goal of this exercise<br>
            > > is to be able to have jmods which include static
            libraries (*.a) of the<br>
            > > native code which the module uses, and that the
            user can then run a<br>
            > > special jlink command to have this linked into a
            single executable<br>
            > > binary (which also bundles the *.class files and
            any additional<br>
            > > resources needed)?<br>
            > ><br>
            > > 2. If so, is the idea to create special kinds of
            static jmods, like<br>
            > > java.base-static.jmod, that contains *.a files
            instead of lib*.so files?<br>
            > > Or is the idea that the normal jmod should contain
            both?<br>
            > ><br>
            > > 3. Linking .o and .a files into an executable is a
            formidable task. Is<br>
            > > the intention to have jlink call a system-provided
            ld, or to bundle ld<br>
            > > with jlink, or to reimplement this functionality
            in Java?<br>
            ><br>
            > I have a similar view as Alan responded in your other
            email thread.<br>
            > Things are still in the early stage for the general
            solution.<br>
            ><br>
            > In the <a href="https://github.com/openjdk/leyden/tree/hermetic-java-runtime" rel="noreferrer" target="_blank" moz-do-not-send="true" class="moz-txt-link-freetext">https://github.com/openjdk/leyden/tree/hermetic-java-runtime</a><br>
            > branch, when configuring JDK with
            --with-static-java=yes, the JDK<br>
            > binary contains the following extra artifacts:<br>
            ><br>
            > - static-libs/*.a: The complete set of JDK/VM static
            libraries<br>
            > - jdk/bin/javastatic: A demo Java launcher fully
            statically linked<br>
            > with the selected JDK .a libraries (e.g. it currently
            statically link<br>
            > with the headless) and libjvm.a. It's the standard Java
            launcher<br>
            > without additional work for hermetic Java.<br>
            ><br>
            > In our prototype for hermetic Java, we build the
            hermetic executable<br>
            > image (a single image) from the following input (see
            description on<br>
            > singlejar packaging tool in<br>
            > <a href="https://cr.openjdk.org/~jiangli/hermetic_java.pdf" rel="noreferrer" target="_blank" moz-do-not-send="true" class="moz-txt-link-freetext">https://cr.openjdk.org/~jiangli/hermetic_java.pdf</a>):<br>
            ><br>
            > - A customized launcher (with additional work for
            hermetic) executable<br>
            > fully statically linked with JDK/VM static libraries
            (.a files),<br>
            > application natives and dependencies (e.g. in .a static
            libraries)<br>
            > - JDK lib/modules, JDK resource files<br>
            > - Application classes and resource files<br>
            ><br>
            > Including a JDK library .a into the corresponding .jmod
            would require<br>
            > extracting the .a for linking with the executable. In
            some systems<br>
            > that may cause memory overhead due to the extracted
            copy of the .a<br>
            > files. I think we should consider the memory overhead
            issue.<br>
            ><br>
            > One possibility (as Alan described in his response) is
            for jlink to<br>
            > invoke the ld on the build system. jlink could pass the
            needed JDK<br>
            > static libraries and libjvm.a (provided as part of the
            JDK binary) to<br>
            > ld based on the modules required for the application.<br>
            ><br>
            <br>
            I gave a bit more thoughts on this one. For jlink to trigger
            ld, it<br>
            would need to know the complete linker options and inputs.
            Those<br>
            include options and inputs related to the application part
            as well. In<br>
            some usages, it might be easier to handle native linking
            separately<br>
            and pass the linker output, the executable to jlink
            directly. Maybe we<br>
            could consider supporting different modes for various usages<br>
            requirements, from static libraries and native linking point
            of view:<br>
            <br>
            Mode #1<br>
            Support .jmod packaged natives static libraries, for both
            JDK/VM .a<br>
            and application natives and dependencies. If the inputs to
            jlink<br>
            include .jmods, jlink can extract the .a libraries and pass
            the<br>
            information to ld to link the executable.<br>
            <br>
            Mode #2<br>
            Support separate .a as jlink input. Jlink could pass the
            path<br>
            information to the .a libraries and other linker options to
            ld to<br>
            create the executable.<br>
            <br>
            For both mode #1 and #2, jlink would then use the linker
            output<br>
            executable to create the final hermetic image.<br>
            <br>
            Mode #3<br>
            Support a fully linked executable as a jlink input. When a
            linked<br>
            executable is given to jlink, it can process it directly
            with other<br>
            JDK data/files to create the final image, without native
            linking step.<br>
            <br>
            Any other thoughts and considerations?<br>
            <br>
            Best,<br>
            Jiangli<br>
            <br>
            > ><br>
            > > 4. Is the intention is to allow users to create
            their own jmods with<br>
            > > static libraries, and have these linked in as
            well? This seems to be the<br>
            > > case.<br>
            ><br>
            > An alternative with less memory overhead could be using
            application<br>
            > modular JAR and separate .a as the input for jlink.<br>
            ><br>
            > > If that is so, then there will always be the risk
            for name<br>
            > > collisions, and we can only minimize the risk by
            making sure any global<br>
            > > names are as unique as possible.<br>
            ><br>
            > Part of the current effort includes resolving the
            discovered symbol<br>
            > collision issues with static linking. Will respond to
            your other email<br>
            > on the symbol issue separately later.<br>
            ><br>
            > ><br>
            > > 5. The original implementation of static builds in
            the JDK, created for<br>
            > > the Mobile project, used a configure flag,
            --enable-static-builds, to<br>
            > > change the entire behavior of the build system to
            only produce *.a files<br>
            > > instead of lib*.so. In contrast, the current
            system is using a special<br>
            > > target instead.<br>
            ><br>
            > I think we would need both configure flag and special
            target for the<br>
            > static builds.<br>
            ><br>
            > > In my eyes, this is a much worse solution. Apart
            from<br>
            > > the conceptual principle (if the build should
            generate static or dynamic<br>
            > > libraries is definitely a property of what a
            "configuration" means),<br>
            > > this makes it much harder to implement
            efficiently, since we cannot make<br>
            > > changes in NativeCompilation.gmk, where they are
            needed.<br>
            ><br>
            > For the potential objcopy work to resolve symbol
            issues, we can add<br>
            > that conditionally in NativeCompilation.gmk if
            STATIC_LIBS is true. We<br>
            > have an internal prototype (not included in<br>
            > <a href="https://github.com/openjdk/leyden/tree/hermetic-java-runtime" rel="noreferrer" target="_blank" moz-do-not-send="true" class="moz-txt-link-freetext">https://github.com/openjdk/leyden/tree/hermetic-java-runtime</a>
            yet) done<br>
            > by one of colleagues for localizing symbols in
            libfreetype using<br>
            > objcopy.<br>
            ><br>
            > ><br>
            > > That was not as much a question as a statement. 🙂
            But here is the<br>
            > > question: Do you think it would be reasonable to
            restore the old<br>
            > > behavior but with the new methods, so that we
            don't use special targets,<br>
            > > but instead tells configure to generate static
            libraries? I'm thinking<br>
            > > we should have a flag like "--with-library-type="
            that can have values<br>
            > > "dynamic" (which is default), "static" or "both".<br>
            ><br>
            > If we want to also build a fully statically linked
            launcher, maybe<br>
            > --with-static-java? Being able to configure either
            dynamic, static or<br>
            > both as you suggested also seems to be a good idea.<br>
            ><br>
            > > I am not sure if "both" are needed, but if we want
            to bundle both lib*.so and *.a files<br>
            > > into a single jmod file (see question 2 above),
            then it definitely is.<br>
            > > In general, the cost of producing two kinds of
            libraries are quite<br>
            > > small, compared to the cost of compiling the
            source code to object files.<br>
            ><br>
            > Completely agree. It would be good to avoid recompiling
            the .o file<br>
            > for static and dynamic builds. As proposed in<br>
            > <a href="https://bugs.openjdk.org/browse/JDK-8303796" rel="noreferrer" target="_blank" moz-do-not-send="true" class="moz-txt-link-freetext">https://bugs.openjdk.org/browse/JDK-8303796</a>:<br>
            ><br>
            > It's beneficial to be able to build both .so and .a
            from the same set<br>
            > of .o files. That would involve some changes to handle
            the dynamic JDK<br>
            > and static JDK difference at runtime, instead of
            relying on the<br>
            > STATIC_BUILD macro.<br>
            ><br>
            > ><br>
            > > Finally, I have looked at how to manipulate symbol
            visibility. There<br>
            > > seems many ways forward, so I feel confident that
            we can find a good<br>
            > > solution.<br>
            > ><br>
            > > One way forward is to use objcopy to manipulate
            symbol status<br>
            > > (global/local). There is an option
            --localize-symbol in objcopy, that<br>
            > > has been available in objcopy since at least 2.15,
            which was released<br>
            > > 2004, so it should be safe to use. But ideally we
            should avoid using<br>
            > > objcopy and do this as part of the linking
            process. This should be<br>
            > > possible to do, given that we make changes in
            NativeCompilation.gmk --<br>
            > > see question 5 above.<br>
            > ><br>
            > > As a fallback, it is also possible to rename
            symbols, either piecewise<br>
            > > or wholesale, using objcopy. There are many ways
            to do this, using<br>
            > > --prefix-symbols, --redefine-sym or
            --redefine-syms (note the -s, this<br>
            > > takes a file with a list of symbols). Thus we can
            always introduce a<br>
            > > "post factum namespace" by renaming symbols.<br>
            ><br>
            > Renaming or redefining the symbol at build time could
            cause confusions<br>
            > with debugging. That's a concern raised in<br>
            > <a href="https://github.com/openjdk/jdk/pull/17456" rel="noreferrer" target="_blank" moz-do-not-send="true" class="moz-txt-link-freetext">https://github.com/openjdk/jdk/pull/17456</a>
            discussions.<br>
            ><br>
            > Additionally, redefining symbols using tools like
            objcopy may not<br>
            > handle member names referenced in string literals. For
            example, in<br>
            > <a href="https://github.com/openjdk/jdk/pull/17456" rel="noreferrer" target="_blank" moz-do-not-send="true" class="moz-txt-link-freetext">https://github.com/openjdk/jdk/pull/17456</a>
            additional changes are<br>
            > needed in assembling and SA to reflect the symbol
            change.<br>
            ><br>
            > ><br>
            > > So in the end, I think it will be fully possible
            to produce .a files<br>
            > > that only has global symbols for the functions
            that are part of the API<br>
            > > exposed by that library, and have all other
            symbols local, and make this<br>
            > > is in a way that is consistent with the rest of
            the build system.<br>
            > ><br>
            > > Finally, a note on Hotspot. Due to debugging
            reasons, we export<br>
            > > basically all symbols in hotspot as global. This
            is not reasonable to do<br>
            > > for a static build. The effect of not exporting
            those symbols will be<br>
            > > that SA will not function to 100%. On the other
            hand, I have no idea if<br>
            > > SA works at all with a static build. Have you
            tested this? Is this part<br>
            > > of the plan to support, or will it be officially
            dropped for Hermetic Java?<br>
            ><br>
            > We have done some testing with jtreg SA related tests
            for the fully<br>
            > statically linked `javastatic`.<br>
            ><br>
            > If we use objcopy to localize symbols in hotspot, it's
            not yet clear<br>
            > what's the impact on SA. We could do some tests. The
            other question<br>
            > that I raised is the supported gcc versions (for
            partial linking)<br>
            > related to the solution.<br>
            ><br>
            > Best,<br>
            > Jiangli<br>
            ><br>
            > ><br>
            > > /Magnus<br>
            > ><br>
          </blockquote>
        </div>
      </div>
    </blockquote>
  </body>
</html>