Zulip Chat Archive
Stream: lean4
Topic: Building shared library with lake
Tomas Skrivan (Jan 17 2022 at 21:25):
How do I properly build and use shared library with lake? I have set defaultFacet := PackageFacet.sharedLib
this creates Package.so
.
I then try to load Package.so
using dlopen
in another program, but I'm getting undefined symbol: l_Lean_instInhabitedExpr
. Clearly it does not load libleanshared.so
properly where this symbol is. Is Package.so
linked against libleanshared.so
by default or do I have to specify that?
My LD_LIBRARY_PATH
points to the directory where libleanshared.so
is, so it should not be a problem that the program can't find it.
Sebastian Ullrich (Jan 17 2022 at 21:36):
If ldd Package.so
doesn't list libleanshared.so, you can try adding -lleanshared
as a linker flag.
Tomas Skrivan (Jan 17 2022 at 21:47):
Yes, adding
moreLinkArgs := #["-L~/.elan/toolchains/leanprover--lean4---nightly-2022-01-12/lib/lean", "-lleanshared"],
solved the problem.
Tomas Skrivan (Jan 17 2022 at 21:49):
Now I'm facing different error:
uncaught exception: invalid environment extension, 'ext' has already been used
Tomas Skrivan (Jan 17 2022 at 22:05):
The problem seems to be that I'm loading and executing the shared library in a loop.
On the first run the library gets loaded and executed correctly. However, on the second load, running:
initialize_Package(lean_io_mk_world());
fails. I'm probably not correctly cleaning up after the first run. How do I do that?
Sebastian Ullrich (Jan 17 2022 at 22:06):
Module initializers should be idempotent. But... why are you loading the same library in a loop?
Tomas Skrivan (Jan 17 2022 at 22:08):
I want to use Lean as a scripting language in a different program. I should reload the library only when to code changes, but for now I reload it on every execution.
Tomas Skrivan (Jan 17 2022 at 22:10):
Also I'm confused about lean_initialize()
and lean_initialize_runtime_module()
the first one does not work, the second one does.
Sebastian Ullrich (Jan 17 2022 at 22:14):
It sounds like you didn't unload libleanshared.so
Tomas Skrivan (Jan 17 2022 at 22:14):
Ohh how do I do that?
Tomas Skrivan (Jan 17 2022 at 22:15):
I'm not loading it manually.
Tomas Skrivan (Jan 17 2022 at 22:16):
I should be calling dlclose
...
Tomas Skrivan (Jan 17 2022 at 22:52):
The problem might be that I'm writing a plugin Plugin.so
to one program that loads Package.so
. Both Plugin.so
and Package.so
needs libleanshared.so
as the plugin calls initalization of lean, lean_io_mk_world, etc.
Thus when I unload Package.so
it does not unload libleanshared.so
as it is still needed by Plugin.so
.
Tomas Skrivan (Jan 17 2022 at 23:02):
Yes it was indeed the problem. Unfortunately, to create Plugin.so
I can't link against lean static libraries because they are not compiled with -fPIC
, so when I want to use any function from lean.h
I have to dynamically load it.
Tomas Skrivan (Jan 17 2022 at 23:58):
Dynamically loaded lean_dec_ref
causes crash, so I can't clean up any lean_object and my program leaks memory :/
Sebastian Ullrich (Jan 18 2022 at 08:32):
Tomas Skrivan said:
The problem might be that I'm writing a plugin
Plugin.so
to one program that loadsPackage.so
. BothPlugin.so
andPackage.so
needslibleanshared.so
as the plugin calls initalization of lean, lean_io_mk_world, etc.Thus when I unload
Package.so
it does not unloadlibleanshared.so
as it is still needed byPlugin.so
.
Then I think you're stuck. There is no way to undo the mutable changes loading Package.so did to the data in libleanshared.so if you cannot unload them both. You should never link the same library both dynamically and statically.
Sebastian Ullrich (Jan 18 2022 at 08:34):
But I still don't know where the error actually stems from. Do you initialize an environment extension in Package.so?
Tomas Skrivan (Jan 18 2022 at 09:28):
What does "initialize environment extension" mean? Is it the call initialize_Package
?
Sebastian Ullrich (Jan 18 2022 at 09:59):
No, it would need to be a call to register*EnvExtension
. I hope we don't actually have one named ext
(and if we did, it shouldn't be loaded twice if it's part of libleanshared.so).
Gabriel Ebner (Jan 18 2022 at 10:01):
Note that mathlib4 has an ext
extension.
Sebastian Ullrich (Jan 18 2022 at 10:03):
Ah yes, a different meaning of "ext" :) . Disabling I guess it's not a builtin then.builtin_initialize
via https://github.com/leanprover/lean4/pull/959 might be of interest then.
Sebastian Ullrich (Jan 18 2022 at 10:06):
Then a better answer is that the attribute registration should only happen in a "compile time" phase while you are only interested in running the plugin in a "run time" phase. Some day I hope Lean will be able to express that...
Tomas Skrivan (Jan 18 2022 at 10:34):
I have made a mock up of my situation, unfortunately I was unable to recreate the invalid environment extension
error. But I still have problems with memory leaks:
https://github.com/lecopivo/leanPluginTest
Build and run instructions are in the readme.
This example has a main application main
that loads a plugin plugin
and the plugin loads package
made with Lean. The main function of the package is called over and over in an infinite loop.
There are two versions, main
and main2
main
is whereplugin
does not linklibleanshared
to avoid the problems I had. However, I have problems callinglean_dec_ref
to clean up memory. Running./main
causes segmentation fault after a moment.main2
is whereplugin2
linkslibleanshared
. This should be the case where I had the problem with environment extension. However, I'm unable to reproduce it here, as Gabriel pointed out it might be a problem with Mathlib(I will test that). This version does not cause segmentation fault but leaks memory.
Tomas Skrivan (Jan 18 2022 at 10:40):
And yes I'm using mathlib4 in my real code. The environment extension error might be connected to that.
Tomas Skrivan (Jan 18 2022 at 10:46):
A simple inclusion of mathlib4, https://github.com/lecopivo/leanPluginTest/tree/mathlib . I'm getting ../lib/Package.so: undefined symbol: initialize_Mathlib_Data_UInt
not sure what is going wrong. Definitely not reproducing the old error.
Sebastian Ullrich (Jan 18 2022 at 11:26):
Tomas Skrivan said:
A simple inclusion of mathlib4, https://github.com/lecopivo/leanPluginTest/tree/mathlib . I'm getting
../lib/Package.so: undefined symbol: initialize_Mathlib_Data_UInt
not sure what is going wrong. Definitely not reproducing the old error.
That sounds like a bug in Lake
Sebastian Ullrich (Jan 18 2022 at 11:29):
Tomas Skrivan said:
This version does not cause segmentation fault but leaks memory.
Hmm yes, I probably should have thought of this sooner. Lean shared libraries are simply not made to ever be unloaded. Perhaps they could be, but right now they aren't.
Tomas Skrivan (Jan 18 2022 at 11:51):
I would really love to use Lean as a scripting language in an another program. I can probably load each new version of a script as a different library, not ideal but should work. Maybe I can use Lean's interpreter, but then I'm not sure how could I wrap the program's C++ API into Lean functions.
Tomas Skrivan (Jan 18 2022 at 12:03):
Ok I'm not sure what is going on but now I can reproduce the invalid environment extension
error
git clone --branch mathlib https://github.com/lecopivo/leanPluginTest.git
cd leanPluginTest
lake build
export LD_LIBRARY_PATH=~/.elan/toolchains/leanprover--lean4---nightly/lib/lean
cd build; mkdir debug; cd debug
cmake ../..
make -j
./main2
Running ./main
works fine until it seg faults.
Tomas Skrivan (Jan 18 2022 at 12:06):
And when you remove import Mathlib
from Package.lean
then main2
works 'fine'(well it leaks memory)
Sebastian Ullrich (Jan 18 2022 at 12:07):
Yes, if you load mathlib twice without unloading libleanshared, that is expected
Tomas Skrivan (Jan 18 2022 at 12:15):
How important is it to run lean_io_mark_end_initialization
, lean_init_task_manager
or lean_finalize_task_manager
I have no clue what any one of these is doing.
Tomas Skrivan (Jan 18 2022 at 12:16):
As I have to load every function from lean.h
dynamically, the only way to get lean_dec_ref
was to dynamically load lean_dec_ref_cold
then then defined my lean_dec_ref
with:
auto lean_dec_ref = [&](lean_object * o) {
if (LEAN_LIKELY(o->m_rc > 1)) {
o->m_rc--;
} else if (o->m_rc != 0) {
lean_dec_ref_cold(o);
}
};
Tomas Skrivan (Jan 18 2022 at 12:27):
I have updated the repository with working lean_dec_ref
, this way I have more or less reproduced main function that gets generated by lean. However running main
still segfaults after a while, I have no clue what to do now to fix that.
Tomas Skrivan (Jan 18 2022 at 12:40):
And it segfaults after 1024 iterations what a coincidence :D
Last updated: Dec 20 2023 at 11:08 UTC