Zulip Chat Archive

Stream: lean4

Topic: how to use Frontend.processCommand when command uses FFI?


David Renshaw (Apr 16 2024 at 13:17):

I want to use tryAtEachStep to run LeanCopilot's search_proof tactic at every tactic step in a Lean file.

When I attempt to do so, I get this error:

.libc++abi: terminating due to uncaught exception of type lean::exception: Could not find native implementation of external declaration 'LeanCopilot.FFI.isGeneratorInitialized' (symbols 'l_LeanCopilot_FFI_isGeneratorInitialized___boxed' or 'l_LeanCopilot_FFI_isGeneratorInitialized').
For declarations from `Init` or `Lean`, you need to set `supportInterpreter := true` in the relevant `lean_exe` statement in your `lakefile.lean`.

I believe that I'm already setting supportInterpreted := true in every place that I can.

tryAtEachStep works by calling Frontend.processCommand on each command in the input Lean file, to re-elaborate everything. How can i make that work in the presence of FFI?

David Renshaw (Apr 16 2024 at 13:22):

My code is at compfiles/lean-copilot.

$ lake exe cache get
$ lake exe LeanCopilot/download
$ lake build
$ lake exe tryAtEachStep --imports LeanCopilot search_proof Compfiles/Imo1992P2.lean

info: [1/4] Building tryAtEachStep
info: [3/4] Compiling tryAtEachStep
info: [4/4] Linking tryAtEachStep
.libc++abi: terminating due to uncaught exception of type lean::exception: Could not find native implementation of external declaration 'LeanCopilot.FFI.isGeneratorInitialized' (symbols 'l_LeanCopilot_FFI_isGeneratorInitialized___boxed' or 'l_LeanCopilot_FFI_isGeneratorInitialized').
For declarations from `Init` or `Lean`, you need to set `supportInterpreter := true` in the relevant `lean_exe` statement in your `lakefile.lean`.

Mario Carneiro (Apr 16 2024 at 13:38):

I assume you tested that it works in the editor?

David Renshaw (Apr 16 2024 at 13:38):

Yes, it works interactively in emacs.

David Renshaw (Apr 16 2024 at 13:39):

If I manually type in search_proof, it successfully executes the tactic.

Mario Carneiro (Apr 16 2024 at 13:39):

I notice that you have some funny link args

Mario Carneiro (Apr 16 2024 at 13:39):

you may need to pass those link args to the executable (i.e. tryAtEachStep)

David Renshaw (Apr 16 2024 at 13:40):

linker args

David Renshaw (Apr 16 2024 at 13:40):

^ this are what LeanCopilot's README instructs me to add

Mario Carneiro (Apr 16 2024 at 13:41):

right, that makes lean able to find the necessary function

Mario Carneiro (Apr 16 2024 at 13:41):

but now you need to make tryAtEachStep also find the function

Mario Carneiro (Apr 16 2024 at 13:41):

so you need to link tryAtEachStep with those arguments

Mario Carneiro (Apr 16 2024 at 13:43):

(I'm aware this is a layering violation but try it anyway to see if this is the issue)

David Renshaw (Apr 16 2024 at 13:44):

I don't know how to pass in such information

David Renshaw (Apr 16 2024 at 13:44):

setting LD_LIBRARY_PATH does not seem to help

Mario Carneiro (Apr 16 2024 at 13:45):

try adding moreLinkArgs to the lakefile of tryAtEachStep

David Renshaw (Apr 16 2024 at 13:45):

ah, okay. Yeah, layering violation indeed...

David Renshaw (Apr 16 2024 at 13:50):

I vendored tryEachStepLean into compfiles/scripts and then added this to the compfiles lakefile.lean:

@[default_target]
lean_exe tryAtEachStepVendored where
  root := `scripts.tryAtEachStep
  supportInterpreter := true
  moreLinkArgs := #[
    "-L./.lake/packages/LeanCopilot/.lake/build/lib",
    "-lctranslate2"
  ]

David Renshaw (Apr 16 2024 at 13:50):

... and got the same error when running lake exe tryAtEachStepVendored ...

David Renshaw (Apr 16 2024 at 13:55):

hm... actually it seems that the error is not coming from Frontend.processCommand

David Renshaw (Apr 16 2024 at 13:55):

it's coming from here: https://github.com/dwrensha/tryAtEachStep/blob/6d1dcdf8c28c005fa3e1795cbac773870109d80d/tryAtEachStep.lean#L75-L78

David Renshaw (Apr 16 2024 at 13:56):

where I try to run the search_proof tactic, using the snapshotted MetaM state that I extracted from Frontend.processCommand.

Sebastian Ullrich (Apr 16 2024 at 13:56):

Does ldd list the shared lib in question on your new executable?

Sebastian Ullrich (Apr 16 2024 at 13:57):

LD_PRELOAD not LD_LIBRARY_PATH is the correct env var to smuggle a solib into an executable that does not require the lib btw

David Renshaw (Apr 16 2024 at 14:06):

$ ldd .lake/build/bin/tryAtEachStepVendored
    linux-vdso.so.1 (0x00007ffd59f7c000)
    libctranslate2.so.4 => not found
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007ee817319000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007ee81b37d000)
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007ee81b378000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ee817000000)
    librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007ee81b371000)
    /lib64/ld-linux-x86-64.so.2 (0x00007ee81b3a0000)

David Renshaw (Apr 16 2024 at 14:11):

David Renshaw said:

hm... actually it seems that the error is not coming from Frontend.processCommand

Indeed, when I add search_proof to a proof in the Lean file and then try tryAtEachStep exact?, it succeeds. So Frontend.processCommand is able to run the search_proof tactic. The problem is that my later injected tactic execution is not able to run the search_proof tactic.

David Renshaw (Apr 16 2024 at 14:12):

So now I'm trying to figure out where Frontend.processCommand is getting its linker state, and how I can make sure to pass that on to my own TermElabM...

Mario Carneiro (Apr 16 2024 at 15:29):

well "linker state" isn't really a thing, the linking state (such as it is) is global and is not passed around

David Renshaw (Apr 16 2024 at 19:20):

Oops -- I was using an invocation of search_proof that succeeded before it needed to run FFI code.
So, correction : Frontend.processCommand does fail, and with the same error "Could not find native implementation of external declaration"

David Renshaw (Apr 16 2024 at 19:26):

So my question is: why does the LSP FileWorker process succeed at linking (it successfully executes the search_proof tactic) while my tryAtEachStep program fails?

Eric Wieser (Apr 16 2024 at 19:40):

The fileworker isn't linking, I don't think? It's perhaps using the lean -dynlib flag to load the search_proof library into the lean runtime, but it's not linking anything against it

David Renshaw (Apr 16 2024 at 19:48):

Aha! This seems to be working (with my vendored tryAtEachStep):

$ LD_LIBRARY_PATH=./.lake/packages/std/.lake/build/lib:./.lake/packages/aesop/.lake/build/lib:./.lake/packages/mathlib/.lake/build/lib:./.lake/packages/LeanCopilot/.lake/build/lib:./.lake/build/lib:/home/dwrensha/.elan/toolchains/leanprover--lean4---v4.7.0/lib/lean:/home/dwrensha/.elan/toolchains/leanprover--lean4---v4.7.0/lib  LD_PRELOAD=.lake/packages/LeanCopilot/.lake/build/lib/libLeanCopilot-Tactics-1.so  lake exe tryAtEachStepVendored --imports LeanCopilot search_proof Compfiles/Imo1992P2.lean

David Renshaw (Apr 16 2024 at 19:48):

That LD_LIBRARY_PATH was stolen from a fileworker.

David Renshaw (Apr 16 2024 at 19:49):

And then I just started trying random things with LD_PRELOAD.

David Renshaw (Apr 16 2024 at 20:06):

Here's where FileWorker loads dynlibs: https://github.com/leanprover/lean4/blob/75e68e7565708361e117c5f56b66fdbe013de667/src/Lean/Server/FileWorker/SetupFile.lean#L125

David Renshaw (Apr 16 2024 at 20:06):

lake setup-file seems relevant...


Last updated: May 02 2025 at 03:31 UTC