Zulip Chat Archive

Stream: lean4

Topic: Running lean function from c++


Tomas Skrivan (Sep 17 2021 at 16:26):

I would like to generate some C code with Lean and then call it from C++. Here is an attempt in a minimal example, but running it causes segmentation fault.

// main.cpp

#include <iostream>
#include <lean/lean.h>

#include "main.h"

int main(){

  auto obj = test_string(42.0);
  auto str = lean_to_string(obj);

  std::cout << str->m_data << std::endl;

  lean_dec(obj);

  return 0;
}
// main.lean

@[export test_string]
def test_string : Float  String := λ x => "Hello World " ++ x.toString

I compile and run this with lean -c main.h main.lean && leanc -x c++ main.cpp -o main && ./main Unfortunately, this causes segmentation fault.

When generating main function from lean, the C code looks like:

  int main(int argc, char ** argv) {

    lean_object* in; lean_object* res;
    lean_initialize_runtime_module();
    res = initialize_main(lean_io_mk_world());
    lean_io_mark_end_initialization();
    if (lean_io_result_is_ok(res)) {
      lean_dec_ref(res);
      lean_init_task_manager();
      res = _lean_main(lean_io_mk_world());
    }
    if (lean_io_result_is_ok(res)) {
      int ret = lean_unbox(lean_io_result_get_value(res));
      lean_dec_ref(res);
      return ret;
    } else {
      lean_io_result_show_error(res);
      lean_dec_ref(res);
      return 1;
    }
  }

The crucial part seems to be lean_initialize_runtime_module() the rest seems to be error handling and IO monad. After some digging I have found lean/init_module.h containing lean::initialize_runtime_module and lean::finalize_runtime_module but running these does not fix the problem.

Sebastian Ullrich (Sep 17 2021 at 16:30):

You have to call initialize_main as well. There is no header for that, but you can copy the signature from the generated code and declare it as extern "C".

Tomas Skrivan (Sep 17 2021 at 16:35):

But what object am I supposed to pass to initialize_main ? There is lean_io_mk_world() in the generated code, but what if I'm not interested in IO?

Tomas Skrivan (Sep 17 2021 at 16:37):

Ok I did extern "C" lean_object* initialize_main(lean_object* w) and then initialize_main(nullptr). It works but looks sketchy.

Sebastian Ullrich (Sep 17 2021 at 16:38):

Initializing a Lean module is inherently IO. The actual value of the parameter doesn't matter, but please just use lean_io_mk_world.

Tomas Skrivan (Sep 17 2021 at 16:40):

Cool, it works :)

Sebastian Ullrich (Sep 17 2021 at 16:47):

Technically you should also check the result (though in this case, initialization cannot fail) and free it

    lean_io_mark_end_initialization();
    if (lean_io_result_is_ok(res)) {
      lean_dec_ref(res);
      lean_init_task_manager();
    } else {
      lean_io_result_show_error(res);
      lean_dec_ref(res);
      throw ...;
    }

We might want to supply a helper function for doing that at some point.


Last updated: Dec 20 2023 at 11:08 UTC