Fork me on GitHub
#graalvm
<
2023-05-25
>
Colin (fosskers)01:05:35

Now I'm on a quest to get static linking working.

Colin (fosskers)01:05:11

Currently this far. It required a manual specification of --native-compiler-path on my particular OS.

Colin (fosskers)01:05:05

Unfortunately...

/bin/ld: cannot find -lz: No such file or directory
collect2: error: ld returned 1 exit status
And https://docs.oracle.com/en/graalvm/enterprise/22/docs/reference-manual/native-image/guides/build-static-executables/ says I need the latest zlib, but I do indeed have that installed (via my system package manager) so I'm not sure what the problem is.

Colin (fosskers)02:05:17

Definitely exists:

zlib /usr/
zlib /usr/include/
zlib /usr/include/zconf.h
zlib /usr/include/zlib.h
zlib /usr/lib/
zlib /usr/lib/libz.a
zlib /usr/lib/libz.so
zlib /usr/lib/libz.so.1
zlib /usr/lib/libz.so.1.2.13

Colin (fosskers)02:05:07

LIBRARY_PATH looks good...

LIBRARY_PATH=/usr/lib/gcc/x86_64-pc-linux-gnu/13.1.1/:/usr/lib/gcc/x86_64-pc-linux-gnu/13.1.1/../../../../lib/:/lib/../lib/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-pc-linux-gnu/13.1.1/../../../:/lib/:/usr/lib/

Colin (fosskers)02:05:06

--static              build statically linked executable (requires static libc and zlib)
but /usr/lib/libz.a is static think_beret

phronmophobic03:05:04

You want libz to be static. I'm not sure if graalvm picks up LIBRARY_PATH. You can try explicitly putting libz on the path with an arg like:

--native-compiler-options='/usr/lib/libz.a'

phronmophobic03:05:55

another try would be:

--native-compiler-options='-L' --native-compiler-options='/usr/lib/'

Colin (fosskers)03:05:56

The LIBRARY_PATH I outputted above was from Graal's own output

phronmophobic03:05:59

Did you try those compiler args?

Colin (fosskers)03:05:13

Yes, they unfortunately didn't work

Colin (fosskers)03:05:56

Cute

# Install libz.a in the correct place so ldd can find it
install -Dm644 "/usr/local/lib/libz.a" "/usr/lib/$arch-linux-musl/libz.a"

Colin (fosskers)03:05:12

That did it!

🎉 2
Colin (fosskers)03:05:21

The binary is actually smaller than before :thinking_face:

Colin (fosskers)03:05:25

In my case, it required symlinking a new /usr/lib/musl/lib/libz.a to the original /usr/lib/libz.a

Colin (fosskers)03:05:16

12mb statically linked binary of a Clojure program

Colin (fosskers)05:05:02

Having some issues with bigger programs. Has anyone ever seen:

Exception in thread "main" java.lang.IllegalArgumentException: No matching ctor found for class org.eclipse.jetty.server.Server
when trying to run a statically linked binary that uses ring?

phronmophobic06:05:13

Are you setting (set! *warn-on-reflection* true) and making sure you're not making any reflective calls? What library are you using? One tip is to use babashka libraries so you don't have to worry if they're graalvm compatible.

phronmophobic06:05:39

Any java interop from clojure in graalvm will require either type hints or some config that tells graalvm to include reflection info for the classes you're interested in.

Colin (fosskers)06:05:42

It was a very simple program; just a basic Ring server with a single handler.

Colin (fosskers)06:05:10

It used ring-jetty-adapter as well

phronmophobic06:05:55

Assuming it works under regular java17, I would check to see if any clojure code makes interop calls that require reflection

Colin (fosskers)06:05:48

The stack trace was indeed showing a Reflector call

Colin (fosskers)06:05:23

deeper down mind you, not in code I wrote

phronmophobic06:05:36

I see ring/jetty under https://github.com/clj-easy/graalvm-clojure, but not sure if anyone has tried new versions.

phronmophobic06:05:16

Not all clojure libraries are native-image compatible so if a library makes interop calls that require reflection, you either need to patch them or include extra config.

2
Colin (fosskers)06:05:03

That example you just posted looks basically exactly the same as what I had

Colin (fosskers)06:05:14

Perhaps something is just different in newer versions? that one was from 3 years ago

phronmophobic06:05:27

Yea, I wouldn't be surprised. Having a bit of reflection used in java interop isn't a big deal for most clojure code, so it's easy to let them sneak in if you don't have an explicit check.

Colin (fosskers)07:05:18

Thanks for your help

👍 2