<!DOCTYPE html><html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  </head>
  <body>
    <p>Hi,<br>
      Note that here the problem is not the downcall method handle,
      which returns just a pointer, so that's portable.</p>
    <p>The problem is that the pointer points to a struct whose layout
      might vary depending on the platform.</p>
    <p>The way one might attack this could be to wrap a bunch of
      "shared" accessors for "passwd" inside a class, where the static
      initializer for the class determines which platforms we're in, and
      sets up the layout accordingly.</p>
    <p>For that, I agree that some form of [1] is needed. Note that we
      currently have this internal class:</p>
    <p><a class="moz-txt-link-freetext" href="https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/jdk/internal/util/Architecture.java">https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/jdk/internal/util/Architecture.java</a></p>
    <p>We have started using this internally more and more, and adding
      stuff we know the JDK needs. Ideally, this class will be added in
      some shape or form to the public API, because I think that it
      could be useful to regularize a lot of ad-hoc code that is written
      by 3rd parties (e.g. using system properties and what not). I
      think that, realistically, there will be small follow ups such as
      this: FFM is a relatively small API, but one that comes with a
      relatively big conceptual shift. As some layouts and method
      handles are now platform dependent, of course that now puts more
      pressure on ways in which to detect said platform differences (and
      adapt method/var handles as required).</p>
    <p>P.S.</p>
    <p>While what you say re. System::loadLibrary is true (e.g. it is
      not fully aware of dynamic linker paths), FFM provides a different
      "blessed" way of looking up libraries that is very well aware of
      what the dynamic linker does. In fact, it's nothing but a thin
      wrapper around dlopen:</p>
    <p><a class="moz-txt-link-freetext" href="https://download.java.net/java/early_access/jdk22/docs/api/java.base/java/lang/foreign/SymbolLookup.html#libraryLookup(java.lang.String,java.lang.foreign.Arena)">https://download.java.net/java/early_access/jdk22/docs/api/java.base/java/lang/foreign/SymbolLookup.html#libraryLookup(java.lang.String,java.lang.foreign.Arena)</a></p>
    <p>On Linux, you can do `loaderLookup("libc.so.6")` and that works
      fine - no custom logic is needed. The problem of shipping native
      libraries into maven modules, on the other hand, is one that still
      requires manual workarounds. But I believe that to be more a
      problem of the tool we're "forced" to work with (Maven/Gradle):
      there's _no sane way_ to load a shared library from a zip file (or
      from some random memory address). Meaning that, to do that, you
      need to copy the library _somewhere_ before loading, which can
      come with its own set of issues (e.g. no write access, not even to
      "/tmp"). A qualitatively better solution would be to use jmods and
      custom JDK images (with jlink) which can deal with native
      libraries just fine, but unfortunately these things are not
      supported by the build tools we have today. This is another of
      these follow-up activity that will likely fall out from the
      initial FFM addition.<br>
    </p>
    <p>Cheers<br>
      Maurizio<br>
    </p>
    <div class="moz-cite-prefix">On 17/02/2024 06:53, tison wrote:<br>
    </div>
    <blockquote type="cite" cite="mid:CALL9TYKhai6KdePs_TtAsk4WeoabQHvZ8Y97u3TYCMDdHFzXZQ@mail.gmail.com">
      
      <div dir="ltr">For example, getpwnam returns passwd struct, but
        the struct layout is various on different platform, making the
        code snippet below unportable:<br>
        <br>
                final Linker linker = Linker.nativeLinker();<br>
                final SymbolLookup lookup = linker.defaultLookup();<br>
                final MemorySegment getpwnam =
        lookup.find("getpwnam").orElseThrow();<br>
                final MethodHandle getpwnamFn =
        linker.downcallHandle(getpwnam,
        FunctionDescriptor.of(ValueLayout.ADDRESS,
        ValueLayout.ADDRESS));<br>
                final StructLayout passwdLayout =
        MemoryLayout.structLayout(<br>
                        ValueLayout.ADDRESS.withName("pw_name"),<br>
                        ValueLayout.ADDRESS.withName("pw_passwd"),<br>
                        ValueLayout.JAVA_INT.withName("pw_uid"),<br>
                        ValueLayout.JAVA_INT.withName("pw_gid"),<br>
                        ValueLayout.JAVA_LONG.withName("pw_change"),<br>
                        ValueLayout.ADDRESS.withName("pw_class"),<br>
                        ValueLayout.ADDRESS.withName("pw_gecos"),<br>
                        ValueLayout.ADDRESS.withName("pw_dir"),<br>
                        ValueLayout.ADDRESS.withName("pw_shell"),<br>
                        ValueLayout.JAVA_LONG.withName("pw_expire"),<br>
                        ValueLayout.JAVA_INT.withName("pw_fields"));<br>
                try (final Arena arena = Arena.ofConfined()) {<br>
                    final MemorySegment username =
        arena.allocateUtf8String(user);<br>
                    final MemorySegment passwd = ((MemorySegment)
        getpwnamFn.invoke(username)).reinterpret(Long.MAX_VALUE);<br>
                    final MemorySegment dir = passwd.get(<br>
                            ValueLayout.ADDRESS,<br>
                           
passwdLayout.byteOffset(MemoryLayout.PathElement.groupElement("pw_dir")));<br>
                   
        System.out.println(dir.reinterpret(Long.MAX_VALUE).getUtf8String(0));<br>
                }
        <div><br>
        </div>
        <div>This code snippet only works <span class="gmail_default" style="font-family:arial,sans-serif">on macOS because the
            layout differs on other platforms.</span></div>
        <div><font face="arial, sans-serif"><br>
          </font></div>
        <div><font face="arial, sans-serif"><span class="gmail_default" style="font-family:arial,sans-serif">In Rust, we can use
              #[target(os = ..)] to switch the manner, and in Java,
              perhaps we can use inheritance or interfaces, but it still
              lacks:</span></font></div>
        <div><font face="arial, sans-serif"><br>
          </font></div>
        <div><font face="arial, sans-serif"><span class="gmail_default" style="font-family:arial,sans-serif">* A unified way to
              determine current os, arch, toolchain, etc. I made [1]
              that can help but it's no more than another incomplete
              slang.</span></font></div>
        <div><font face="arial, sans-serif"><span class="gmail_default" style="font-family:arial,sans-serif">* A compile-time
              dispatch decision. Maybe with static initialization block
              it can helps by generating 'static final'
              MethodHandle/VarHandle. I don't know.</span><br>
          </font><br>
          Best,<br>
          tison.</div>
        <div><br>
        </div>
        <div>
          <div class="gmail_default" style="font-family:arial,sans-serif">[1] <a href="http://github.com/tisonspieces/os-detector" moz-do-not-send="true">github.com/tisonspieces/os-detector</a></div>
          <br>
        </div>
      </div>
    </blockquote>
  </body>
</html>