membrane

Omer ZAK 2024-03-14T19:31:19.028609Z

Hi @smith.adriane I made some progress and now I have a -main function which recognizes pod mode and starts the pod. The current struggle is to get GraalVM to build the executable. Your terminal-todo-mvc/compile_native.sh invokes native-image with the compile-time option --initialize-at-build-time and while I did not invoke this option, I get error messages like:

Error: Classes that should be initialized at run time got initialized during image building:
 java.awt.Toolkit was unintentionally initialized at build time. To see why java.awt.Toolkit got initialized use --trace-class-initialization=java.awt.Toolkit
Other classes which are initialized during image building time instead of run time are: sun.swing.SwingAccessor, java.awt.Component, java.awt.event.ComponentEvent, ..., java.awt.AWTEvent. So: do you know anything about this and can advise me how to proceed? Thanks!

Omer ZAK 2024-03-17T07:19:14.373459Z

More hints: https://www.graalvm.org/latest/reference-manual/native-image/native-code-interoperability/JNIInvocationAPI/#load-the-native-library Since LD_LIBRARY_PATH did not work for me, need to find how to set Java property java.library.path

Omer ZAK 2024-03-17T07:45:11.196669Z

I added to hello_world.clj's -main the following code at beginning:

(println "Trying to print something")
(println "java.library.path =" (java.lang.System/getProperty "java.library.path"))
(java.lang.System/setProperty "java.library.path" (str "/path/to/membrane-native-image:" (java.lang.System/getProperty "java.library.path")))
(println "java.library.path =" (java.lang.System/getProperty "java.library.path"))
Did not help. ☹️ The println forms worked, but the java2d/run form following them aborted as before.

phronmophobic 2024-03-17T07:55:37.360169Z

I think I've made a little progress. Based on https://www.praj.in/posts/2021/compiling-swing-apps-ahead-of-time/. I think the problem is config related. Their example for generating the config does seem generate config, but I think it also generates a bunch of incorrect config for clojure based code. I ran it with a subset of the config and it crashed on a java exception instead of a heap dump, which seems like progress.

phronmophobic 2024-03-17T08:02:38.642949Z

ok, I actually got it to run

phronmophobic 2024-03-17T08:03:32.006969Z

but a simpler version since it's an ec2 instance and I haven't setup a way to see if a window pops up

phronmophobic 2024-03-17T08:07:51.943209Z

ok, it's getting late here. just pushed a new commit that seems to work locally. currently, you have to run it and pass in java.home, but it should be possible to work around that. For now, it should be run with:

./hello-world -Djava.home=/home/ubuntu/graalvm
where java.home is set to wherever java home is for graalvm.

Omer ZAK 2024-03-17T08:09:16.191869Z

Do I need to update the following in deps.edn?

:git/sha "b04bbe291658d8883ef9741f517c7b6ddf756b75"
:git/url ""

phronmophobic 2024-03-17T08:09:48.017779Z

the changes are • there's a new flag for native-image, -H:ConfigurationFileDirectories=config • the main function just prints the size of the app since I don't have a linux setup to see if a window opens. you'll likely need to regenerate config if you do more than that • there's now a config directory

phronmophobic 2024-03-17T08:10:04.693909Z

the membrane commit hasn't changed.

phronmophobic 2024-03-17T08:10:41.618459Z

so there will likely be more work to get it working in the general case, but hopefully we're on the right track

phronmophobic 2024-03-17T08:11:13.142589Z

hopefully, it's just a matter of generating the right config

phronmophobic 2024-03-17T08:11:27.140259Z

which can be done using the agent while exercising all of the relevant code

Omer ZAK 2024-03-17T08:11:41.785209Z

I see no new commit when trying to sync my fork with your membrane-native-image.

Omer ZAK 2024-03-17T08:12:51.480099Z

Did you push your new commit to your GitHub repository?

phronmophobic 2024-03-17T08:13:06.105579Z

let me double check

Omer ZAK 2024-03-17T08:14:10.369739Z

Now I see it, and have pulled to my repository. Good night (your time).

😄 1
Omer ZAK 2024-03-17T08:35:45.230299Z

A big progress but no dice, yet. Now hello-world complains about Exception in thread "main" java.lang.NoClassDefFoundError: sun/awt/SunToolkit rather than about Fatal error reported via JNI: Could not allocate library name. I invoked it using: ./hello-world -Djava.home=../../graal-21/graalvm-jdk-21.0.2+13.1 (it is is where my GraalVM is) and it still has the java.lang.System/setProperty "java.library.path" code (I did not remove it).

phronmophobic 2024-03-17T19:56:04.677799Z

I think it's just a matter of getting the right config for graalvm. However, I tried it with liberica and it seems to just work™. You can try using liberica or try to follow the steps from https://github.com/phronmophobic/membrane-native-image?tab=readme-ov-file#resources to figure out the right config for graalvm. I updated the ./config.sh script to hopefully make that easier if you go that route.

Omer ZAK 2024-03-17T20:29:02.981599Z

1. I need to use GraalVM, at least in the sense that our work is not done until it works with GraalVM. 2. What is the job of config.sh? When (if at all) should I run it? 3. What can you tell me about sun/awt/SunToolkit?

phronmophobic 2024-03-17T20:30:48.849359Z

> I need to use GraalVM, at least in the sense that our work is not done until it works with GraalVM. why?

phronmophobic 2024-03-17T20:31:57.727569Z

3. I think this can be fixed by adding the right config 2. It helps create the right config For more info about configs, see the links I sent you.

Omer ZAK 2024-03-17T20:42:38.964999Z

I ran JAVA_HOME=../../graal-21/graalvm-jdk-21.0.2+13.1 ./config.sh and it failed:

+ clojure -T:build compile
WARNING: compile already refers to: #'clojure.core/compile in namespace: build, being replaced by: #'build/compile
Execution error (ClassNotFoundException) at jdk.internal.loader.BuiltinClassLoader/loadClass (BuiltinClassLoader.java:641).
org.graalvm.nativeimage.ImageInfo

phronmophobic 2024-03-17T20:43:33.376059Z

for whatever reason, it's not using graalvm when running

phronmophobic 2024-03-17T20:43:52.023839Z

you need to make sure which java uses graalvm

Omer ZAK 2024-03-17T20:44:48.241319Z

hmmm. I set JAVA_HOME, forgot to set also PATH.

phronmophobic 2024-03-17T20:45:50.154799Z

I have the following in my bashrc. Maybe you'll find it useful:

function graalvm() {
     export JAVA_HOME=/Library/Java/JavaVirtualMachines/graalvm-community-openjdk-21.0.2+13.1/Contents/Home
     export GRAALVM_HOME="$JAVA_HOME"
     export PATH=$JAVA_HOME/bin:$PATH

    java -version
}
# export PATH=$GRAALVM_HOME/bin:$PATH

function liberica() {
     export JAVA_HOME=/Library/Java/JavaVirtualMachines/bellsoft-liberica-vm-core-openjdk21-23.1.2/Contents/Home
     export GRAALVM_HOME="$JAVA_HOME"
     export PATH=$JAVA_HOME/bin:$PATH

    java -version
}

phronmophobic 2024-03-17T20:46:07.053719Z

I then just do:

$ graalvm
to activate graavm

Omer ZAK 2024-03-17T20:54:56.115069Z

Weird. I fixed config.sh to set JAVA_HOME,`PATH` and when running it, I saw a membrane window (seems to be your todo demo app). However, when I later ran compile.sh, I got:

Error: Class initialization of clojure.core.reducers__init failed. Use the option 

    '--initialize-at-run-time=clojure.core.reducers__init'

 to explicitly request initialization of this class at run time.
A rabbit hole has just opened ahead of me. Attached please see a screenshot of the membrane window (after I manually resized it a bit).

phronmophobic 2024-03-17T20:56:30.614629Z

yes. If you read the link I sent you, you generate the config by running the program with the agent running, which records all the runtime info needed.

phronmophobic 2024-03-17T20:57:14.018439Z

Not sure if you're using the latest commit, but there should be a fix-config step which should fix the clojure.core.reducers__init error.

Omer ZAK 2024-03-17T20:59:51.469819Z

I am using commit 4db0ce69112347bd84f1303ba39d4bb57971f5a4 of yours (my own commits are rebased following it).

Omer ZAK 2024-03-17T21:01:52.292859Z

hmmm... I saw you pushed another commit, which GitHub neglected to inform me about. I am fixing now.

phronmophobic 2024-03-17T21:03:06.723299Z

actually, that commit probably won't help as it is meant to test liberica

phronmophobic 2024-03-17T21:03:32.289159Z

you need to have -H:ConfigurationFileDirectories=config in the compile script

phronmophobic 2024-03-17T21:05:30.326749Z

Is there a particular reason you require graalvm over liberica?

Omer ZAK 2024-03-17T21:07:17.626759Z

Babashka uses GraalVM. On second thought, actually, Babashka pods do not need to use the same JVM, they do not even need to use a JVM at all (there is a pod which is a Python script).

phronmophobic 2024-03-17T21:08:11.914539Z

Yes, I don't think it should matter as far as creating a pod goes.

phronmophobic 2024-03-17T21:09:22.890149Z

or if you wanted to distribute your own bb+ui binary

phronmophobic 2024-03-17T21:09:31.483229Z

it shouldn't matter for that either.

Omer ZAK 2024-03-17T21:10:00.670219Z

I should ask borkdude (Babashka's BDFL) if he ever tried to build Babashka with liberica.

phronmophobic 2024-03-17T21:10:42.278299Z

I would worry about relying on any implementation details specific to liberica, but that doesn't seem to be the case. It seems like someone will eventually upstream awt support into graalvm.

Omer ZAK 2024-03-17T21:11:13.541379Z

Anyway, this time compile.sh ran to completion, but hello_world aborted with a familiar error message:

Fatal error reported via JNI: Could not allocate library name
🙁

phronmophobic 2024-03-17T21:11:41.440729Z

does your compile.sh include H:ConfigurationFileDirectories=config?

Omer ZAK 2024-03-17T21:14:14.580929Z

My bad, the line was included but commented out. ##########################################

Omer ZAK 2024-03-17T21:15:07.308479Z

Now it failed with:

Error: Class initialization of clojure.core.reducers__init failed. Use the option 

    '--initialize-at-run-time=clojure.core.reducers__init'

phronmophobic 2024-03-17T21:15:44.279379Z

what does you config script look like? did you update the config before compiling?

Omer ZAK 2024-03-17T21:18:47.873469Z

Attached please find my config.sh, and I run it with

GRAALVM_HOME=../../graal-21/graalvm-jdk-21.0.2+13.1 ./config.sh
(morally equivalent to your bashrc functions)

phronmophobic 2024-03-17T21:19:49.969389Z

I thought the fix-config script would fix the clojure.core.reducers__init problem

Omer ZAK 2024-03-17T21:21:28.931609Z

I don't have fix-config.sh neither does your repository have it (at least in root directory).

phronmophobic 2024-03-17T21:21:42.815219Z

it's in build.clj

phronmophobic 2024-03-17T21:21:55.353829Z

clojure -T:build fix-config

Omer ZAK 2024-03-17T21:23:47.218649Z

This command is at end of config.sh. So it did get execute. How long should I keep the todo demo window active for fix-config to finish its work?

phronmophobic 2024-03-17T21:24:58.479149Z

I don't think it matters just for testing. Eventually, you'll need a demo that exercises all the code paths you'll be interested in the pod to get the right config.

Omer ZAK 2024-03-17T21:28:12.029389Z

Your hello_world uses the following:

(java2d/run
    (membrane.component/make-app
     #'td/todo-app
     td/todo-state)))
Which of those classes is NOT used in your Todo-app? What do I need to modify to include hello_world.clj rather than Todo-app?

phronmophobic 2024-03-17T21:28:59.099709Z

?

phronmophobic 2024-03-17T21:29:55.091039Z

My version doesn't open a window since my linux doesn't have a screen.

phronmophobic 2024-03-17T21:30:15.988679Z

If you do want to try that as your hello world, you'll probably need something like:

(defn -main [& _args]
  (java2d/run-sync
      (membrane.component/make-app
       #'td/todo-app
       td/todo-state))
  (shutdown-agents))

Omer ZAK 2024-03-17T21:30:23.964259Z

I notice that config.sh somehow runs Todo app, but grepping all files failed to yield anything pointing at it (especially not deps.edn).

phronmophobic 2024-03-17T21:30:28.805699Z

so that the app exists when you close the window

Omer ZAK 2024-03-17T21:33:42.087779Z

So config.sh runs membrane.example.todo under Clojure and it works. Then when compile.sh is successful, membrane.example.todo tries to run under GraalVM, and it aborts. Is this what is happening?

Omer ZAK 2024-03-17T21:35:04.750709Z

I hope you have patience with me - it is the first time I am trying to build a Babashka pod, my first contact with native-image, and I knew no Clojure at all three months ago.

phronmophobic 2024-03-17T21:36:04.390439Z

native image + clojure is kind of tricky and native image + clojure + AWT is very bleeding edge

phronmophobic 2024-03-17T21:37:46.179079Z

clojure is very dynamic and native image needs runtime information to know which dynamic features are necessary. ./config.sh runs the app and collects a list of dynamic usage which is recorded as config in the config dir. ./compile.sh compiles the app and uses the config info

Omer ZAK 2024-03-17T21:38:46.641309Z

I see there are some *.json files in ./config/ Is it necessary to clean the directory, or does config.sh regenerate from 0 all of them?

phronmophobic 2024-03-17T21:38:57.173879Z

I think ./config.sh followed by ./compile.sh should work, but there are enough differences between the working setup and your setup.

phronmophobic 2024-03-17T21:39:39.578889Z

> Is it necessary to clean the directory, or does config.sh regenerate from 0 all of them? I'm not actually sure. It probably wouldn't hurt to clean before recreating the config.

Omer ZAK 2024-03-17T21:41:51.793409Z

The config directory in your repository has jni-config.json,reflect-config.json Are those files regenerated?

phronmophobic 2024-03-17T21:43:10.822309Z

they should be regenerated when you run ./config.sh

Omer ZAK 2024-03-17T21:43:42.890319Z

So they should not be under version control (however this does not harm - seems they are unchanged when regenerated).

phronmophobic 2024-03-17T21:44:12.222919Z

the ones in the repo were generated by running a different main function, so they won't contain the right config since your main function is different.

phronmophobic 2024-03-17T21:44:41.675209Z

> So they should not be under version control (however this does not harm - seems they are unchanged when regenerated). (edited) if you were using the same main function, then it would allow you to skip the config step.

phronmophobic 2024-03-17T21:46:10.121789Z

Eventually, you'll need a demo that exercises all the code paths you'll be interested in the pod to get the right config. That config can be saved for reproducible builds without having to go through the config step again.

phronmophobic 2024-03-17T21:46:36.712979Z

I've found the config step isn't needed for liberica. It's likely they automatically include the right config to support AWT.

phronmophobic 2024-03-17T21:46:56.930419Z

Hopefully, graalvm will also have better AWT support in the future

Omer ZAK 2024-03-17T21:47:57.470819Z

OK, I'll try liberica. Can I use the same compile.sh script (by using a different GRAALVM_HOME)?

phronmophobic 2024-03-17T21:48:36.422279Z

Yes. It should work for either.

phronmophobic 2024-03-17T21:48:56.371189Z

I've been switching back and forth for the github action.

Omer ZAK 2024-03-17T21:50:34.224799Z

GitHub actions are another spell, with which I am not currently familiar.

Omer ZAK 2024-03-17T21:55:07.455849Z

Reading the Liberica installation instructions, it mentions "language plugins". Do I need any language plugin for our undertaking?

phronmophobic 2024-03-17T21:56:24.095069Z

Nope

👍 1
phronmophobic 2024-03-17T21:57:53.831929Z

you can see how I install it in the github action, https://github.com/phronmophobic/membrane-native-image/blob/6aba2262238dd148b0fef1e19811cc47b5c88005/linux-install.sh#L9

phronmophobic 2024-03-17T21:58:33.522849Z

It just downloads the tarball, put it's somewhere, and then adds it to the path

phronmophobic 2024-03-17T21:58:48.222809Z

I think there are some extra dependencies that are recommended which you may already have

phronmophobic 2024-03-17T21:59:52.976569Z

I don't point to that script in the docs since it would modify files outside of the membrane-native-image repo.

phronmophobic 2024-03-17T22:00:14.398479Z

but hopefully it gives you an idea of what's necessary and you can tweak for your desired setup

Omer ZAK 2024-03-17T22:05:49.150229Z

Thanks. By the way, wget did not work for me due to invalid certificate for http://download.bell-sw.com So I downloaded using the Google Chrome browser which apparently has root certificates that wget does not have.

phronmophobic 2024-03-14T19:51:30.268189Z

is the code you're using available somewhere?

Omer ZAK 2024-03-14T19:58:26.514779Z

Not an answer to your question: I am now experimenting with --initialize-at-build-time, and find all kinds of sun.awt.* classes which insist that they must be initialized at run time. I override by --initialize-at-run-time=sun.awt.X11 and such and each time I try to compile, GraalVM complains about another class. An answer to your question: My code is not available, yet, but if you want to deep dive into it, I'll create a GitHub repository by cloning your repository.

phronmophobic 2024-03-14T20:03:30.692379Z

You may have to find some graalvm+swing specific docs to figure out the right configuration. Generally, you want clojure classes to be initialized at build time (I recommend clj-easy/graal-build-time, https://github.com/clj-easy/graal-docs?tab=readme-ov-file#class-initialization) and you want java classes to be initialized at runtime. If your clojure uses a java class, you'll need to make sure it defers instantiating classes until runtime.

Omer ZAK 2024-03-14T20:08:00.519139Z

"If your clojure uses a java class" - it seems to be YOUR code that is using all those problematic Java classes. 🥳 I am now officially stuck. I'll let you know when my code is ready for your experimentation.

phronmophobic 2024-03-14T20:13:18.948879Z

I haven't used graalvm with the java2d backend. It's not clear which backend(s) you're trying to use, but the java2d backend will likely require some changes to support native image (which I'm happy to help support).

Omer ZAK 2024-03-14T20:42:19.639429Z

Actually my script tries to access all backends (see src/pod/tddpirate/membrane.clj lookup function). You may want to comment out some of the backends. The pull request (#77) with my pod related stuff is waiting now for you. Enjoy!

👍 1
phronmophobic 2024-03-14T20:47:50.390959Z

it looks like it's only using the java2d backend. the other namespaces are backend independent

Omer ZAK 2024-03-14T20:50:25.969429Z

Please let me know when the GraalVM build succeeds, so that I can start debugging the Babashka pod code itself.

phronmophobic 2024-03-14T21:06:32.433739Z

I've been in this position before where someone wants a feature that sounds reasonable. I do the work to help add the feature, and then I never hear back to find out if the feature was used or solved a real problem. I try to prioritize features that solve useful problems so it would be helpful for me to hear a bit more about the intended use case and the problem you are trying to solve.

Omer ZAK 2024-03-14T21:29:12.959209Z

Fair enough. Actually, it is an excellent idea to verify that a feature request is based upon a real need! I am building miscellaneous scripts, which will replace my bash scripts, and which will use the power of Clojure. Hence, Babashka. Some of those scripts have an UI, currently implemented using whiptail. I would like to get them to display Clojure-driven GUI. I looked into humble-ui and liked more the philosophy of membrane. By the way, as an alternative to creation of a membrane Babashka pod, it is possible to create a custom version of Babashka which has the membrane library already built into it. I'll look into it. It'll probably have the same problem as the membrane Babashka pod work I have been doing. But who knows?

1
🙏 1
phronmophobic 2024-03-14T21:31:20.677389Z

I'm not familiar with whiptail. I'll have to check it out.

phronmophobic 2024-03-14T21:33:55.698989Z

I do think integration with babashka would be neat for various use cases. One worry I had with compiling membrane with native image is that binary size might be too big for some uses. I'm actually not sure what size binary to expect, but my guess is that it should be fine for a dev tool that gets used repeatedly. Binary size would be a bigger concern if you wanted to distribute an app that only gets used once or twice.

phronmophobic 2024-03-14T21:34:47.041469Z

> it is possible to create a custom version of Babashka which has the membrane library already built into it. Yes, that's another alternative, but it would still require the same changes that building a pod would require.

Omer ZAK 2024-03-14T21:46:22.653579Z

I suggest that for now, let's not worry about binary size of membrane with native image. Current sizes are: membrane-0.11.111-beta-standalone.jar (0.11.111 is the version which includes my Babashka pod stuff): 10MB bb (Babashka executable): 65MB So I guess that adding membrane to Babashka executable will not get the custom version to be longer than 100MB. It may be possible to reduce the size by removing libraries not likely to be needed by people who need GUI. OK, please let me know how are things going, especially if there is anything in my code which is problematic for you.

phronmophobic 2024-03-14T21:47:35.502949Z

I don't think membrane's code will bloat the binary by much, it's pulling in all the swing and AWT dependencies that I'm worried about.

phronmophobic 2024-03-14T21:48:04.399469Z

it's probably not too bad, but it will be something to look out for

👍 1
phronmophobic 2024-03-16T19:44:13.729629Z

Making progress...

phronmophobic 2024-03-16T19:49:39.115169Z

The hello world was ~60MB and I tried a todo app which was 80MB. I think there are also some optimizations that help. Anyway, seems promising.

👋 1
Omer ZAK 2024-03-16T20:24:14.217889Z

Where in GitHub can I find what you did to accomplish this? I think I can live, for now, with 60MB hello world & Co. while we work on optimizing the stuff. I would like to be able to start developing my GUI-enhanced scripts right away.

phronmophobic 2024-03-16T20:25:26.535699Z

It required some minor changes to membrane to work. I'm still checking in the changes and documenting things.

phronmophobic 2024-03-16T20:25:45.694349Z

I'll let you know when it's ready. Hopefully later today!

🫰 1
Omer ZAK 2024-03-16T20:26:21.155299Z

Did you need to fix anything in my script (which was not debugged before making it available to you)?

phronmophobic 2024-03-16T20:26:51.675399Z

I ended up creating a fresh project so that I could test things in isolation

phronmophobic 2024-03-16T20:27:02.646699Z

so I haven't tried with your code yet

Omer ZAK 2024-03-16T20:29:05.721809Z

OK, once membrane compiles and works under GraalVM, I'll be happy to start debugging my Babashka pod script, if still needed.

1
phronmophobic 2024-03-16T21:51:40.274059Z

https://github.com/phronmophobic/membrane-native-image

phronmophobic 2024-03-16T21:52:18.065099Z

I haven't tested running the app on linux, but the build successfully compiles, https://github.com/phronmophobic/membrane-native-image/actions/runs/8310661320/job/22743413655

phronmophobic 2024-03-16T21:52:30.272879Z

Let me know if you have any questions or run into any issues.

Omer ZAK 2024-03-16T23:19:46.779919Z

1. For my curiosity: what use case/s are satisfied by liberica (I understand, from Google, that liberica implements yet another JVM)? 2. Do I work from your membrane's master branch or from its native-image branch?

phronmophobic 2024-03-16T23:41:02.762909Z

It doesn't really make sense to include the pod inside the membrane repo. I suggest either creating a separate project based off of https://github.com/phronmophobic/membrane-native-image or just forking it. You can either use the git dep referenced in that repo or use a local repo repo from a checkout of the native-image branch of membrane.

phronmophobic 2024-03-16T23:41:51.044089Z

It might be useful to start with reproducing the steps from the membrane-native-image repo.

phronmophobic 2024-03-16T23:42:49.388009Z

I think liberica is just a fork of graalvm that has already added better support for AWT. I assume that AWT support will get upstreamed back to graalvm at some point.

phronmophobic 2024-03-17T04:04:45.610789Z

I found liberica based on a comment on this issue https://github.com/oracle/graal/issues/4124

✅ 1
Omer ZAK 2024-03-17T05:45:05.754269Z

Good morning @smith.adriane (here it is 07:30 AM), I tried building and running your membrane-native-image. The fatal error that I got was:

Error: Main entry point class 'com.phronemophobic.membrane.hello_world' neither found on
followed by few monstrous classpath and modulepath recitations. I tried to change all references of hello-world in hello_world.clj and in compile.sh but this did not help. I did not follow exactly your recipe: 1. I used an existing GraalVM native-image binary rather than run clojure -T:build:native-image compile 2. I used graalvm-jdk-21.0.2+13.1 rather than liberica. 3. native-image got the option -H:+UnlockExperimentalVMOptions to get rid of a warning. 4. Another warning was eliminated by manually doing mkdir -p target/classes

phronmophobic 2024-03-17T05:46:36.800349Z

> I used an existing GraalVM native-image binary rather than run clojure -T:build:native-image compile Skipping clojure -T:build:native-image compile sounds suspicious. It creates class files which you need during native image

Omer ZAK 2024-03-17T05:47:19.592409Z

(cont'd) I have some questions: 1. When you ran your compile.sh, what output did you see for java -version? 2. What is the exact effect of clojure -T:build:native-image compile (I commented out without understanding exactly what it does)?

phronmophobic 2024-03-17T05:47:26.909269Z

There's almost no way you'll have a class file with main at com.phronemophobic.membrane.hello_world unless you do clojure -T:build:native-image compile

phronmophobic 2024-03-17T05:47:57.169419Z

if you look at the compile function in build.clj , it compiles the clojure to a jvm class file.

phronmophobic 2024-03-17T05:48:33.858549Z

It essentially the equivalent of $ clojure -M -e "(compile 'hello-world.main)" in https://github.com/clj-easy/graal-docs/blob/master/doc/hello-world.adoc#step-2-compile-project-sources-to-class-files

phronmophobic 2024-03-17T05:49:57.059009Z

I tried compiling with graalvm instead of liberica on linux and it did successfully compile, but I haven't tried running the executable which should hopefully work, but might not.

phronmophobic 2024-03-17T05:50:32.442739Z

not sure if you can see the logs in https://github.com/phronmophobic/membrane-native-image/actions/runs/8310704846

phronmophobic 2024-03-17T05:51:05.696389Z

here's the output of java -version for that run:

+ java -version
openjdk version "21.0.2" 2024-01-16
OpenJDK Runtime Environment GraalVM CE 21.0.2+13.1 (build 21.0.2+13-jvmci-23.1-b30)
OpenJDK 64-Bit Server VM GraalVM CE 21.0.2+13.1 (build 21.0.2+13-jvmci-23.1-b30, mixed mode, sharing)

phronmophobic 2024-03-17T05:52:44.157019Z

it's important that the clojure -T:build:native-image compile is run with graalvm rather than some other jvm

phronmophobic 2024-03-17T05:55:54.441639Z

the class files from clojure -T:build:native-image compile end up in the target/classes folder

phronmophobic 2024-03-17T05:56:29.087539Z

the basic work flow is 1. compile clojure to .class files 2. use native-image to compile .class files to native code

Omer ZAK 2024-03-17T05:57:36.558439Z

Thanks, the clojure -T:build:native-image looked to me like rebuilding a custom version of native-image. 😂😂😂 Anyway, after performing the above clojure -T, hello-world executable was successfully built. However, when it ran, it aborted with the error message:

Fatal error reported via JNI: Could not allocate library name
followed by stack traces and dumps which I did not review (will review if necessary). I noticed that there are additional files:
libawt_headless.so  libfontmanager.so  libjvm.so
libawt.so           libjavajpeg.so     liblcms.so
libawt_xawt.so      libjava.so         libmlib_image.so
Do I need to do anything special to get hello-world to access those libraries?

phronmophobic 2024-03-17T05:58:29.367299Z

oh interesting. I saw something about that mentioned on github. where do those files end up?

phronmophobic 2024-03-17T05:59:14.169879Z

I can try to find the issue on github, but they said something about those needing to be in the same place as the executable

Omer ZAK 2024-03-17T05:59:39.142379Z

Those library files end up in the same directory as hello-world i.e. main directory of membrane-native-image.

phronmophobic 2024-03-17T06:01:40.788519Z

oh, I think I remember, you somehow need to set a javapath because it doesn't include the current directory. one sec

phronmophobic 2024-03-17T06:11:37.973569Z

I'm having trouble finding it. can you run ldd hello-world? It should print the libraries it depends on and the path it expects them to be

Omer ZAK 2024-03-17T06:13:11.116769Z

$ ldd hello-world 
	linux-vdso.so.1 (0x00007ffe79322000)
	libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f8fd0c15000)
	libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f8fd0c0f000)
	libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f8fd0bed000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f8fcb82c000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f8fd0c76000)

Omer ZAK 2024-03-17T06:15:47.964389Z

My system has all five libraries (linux-vdso.so.1 is a pseudo-library or something).

phronmophobic 2024-03-17T06:17:26.013069Z

yea, so my guess is that it's trying to load those other libraries at runtime from java.library.path, but I have no idea how to set it

phronmophobic 2024-03-17T06:17:54.676909Z

is there something in the error dump about java.library.path?

Omer ZAK 2024-03-17T06:18:35.783589Z

No.

phronmophobic 2024-03-17T06:19:03.553759Z

ok. I'll see if I can reproduce on an aws instance

Omer ZAK 2024-03-17T06:20:17.479079Z

My PC runs on Debian Linux 11.9 and my "regular" clojure is Clojure CLI version 1.11.1.1429.

phronmophobic 2024-03-17T06:22:08.546689Z

I'll also be able to try with liberica

Omer ZAK 2024-03-17T06:22:15.239909Z

My modified compile.sh script has the following at its beginning:

if [ -z "$GRAALVM_HOME" ]; then
    echo "Please set GRAALVM_HOME"
    exit 1
fi

if [ ! -e "${GRAALVM_HOME}/bin/native-image" ]; then
    echo "Your ${GRAALVM_HOME} does not have native-image, aborting."
    exit 1
fi

export JAVA_HOME=$GRAALVM_HOME
export PATH=$GRAALVM_HOME/bin:$PATH

which java
java -version
and I run it as follows:
GRAALVM_HOME=../../graal-21/graalvm-jdk-21.0.2+13.1 ./compile.sh

phronmophobic 2024-03-17T06:23:03.110629Z

It's gotta be something wrong with the script

phronmophobic 2024-03-17T06:23:34.477739Z

either some missing flag for native-image or some missing post step

Omer ZAK 2024-03-17T06:23:34.867399Z

By the way, hello-world aborts also with the above setting and when setting JAVA_HOME to the same.

phronmophobic 2024-03-17T06:24:33.011069Z

hopefully, it works on linux. I thought I saw some indications that it worked on linux, but I'm having trouble finding the ticket on github that I'm thinking of

Omer ZAK 2024-03-17T06:24:43.545829Z

... or some extraneous flag (I added the flag H:+UnlockExperimentalVMOptions, should try also without this flag).

phronmophobic 2024-03-17T06:34:51.866599Z

ok, I have a linux instance setup which is hopefully enough to try to test things out myself on linux

phronmophobic 2024-03-17T06:36:15.102319Z

I've only done basic native-image compilation for linux. There's probably some linux specific options that might help.

phronmophobic 2024-03-17T06:37:07.240129Z

I was able to reproduce the error.

Omer ZAK 2024-03-17T06:43:25.604249Z

I tried to set LD_LIBRARY_PATH before running hello-world. Did not help.

Omer ZAK 2024-03-17T06:47:09.062189Z

Another thing to try? The option addBuiltinPkgNativePrefix according to https://github.com/oracle/graal/issues/3359

👀 1
phronmophobic 2024-03-17T06:55:27.463049Z

well, I tried liberica and now the server isn't responding 😐