[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Need help embedding Guile
From: |
Dimitris Papavasiliou |
Subject: |
Need help embedding Guile |
Date: |
Tue, 21 Dec 2021 11:12:54 +0000 |
Hi all,
I'm in the process of embedding Guile in an application and although I seem to
have the essentials working, I'd appreciate some confirmation of the validity of
my approach and also some tips on a couple of loose ends.
I won't bore you with the specifics of my application; for the purposes of the
discussion, its most important characteristic, is that it uses Guile as a
frontend of sorts. By this, I mean that a Scheme program is executed, which
creates objects in the C (well actually, and out of necessity, C++) domain.
These objects represent geometric operations, in the form of a graph and are
evaluated once the Scheme program has terminated. Since the evaluation can take
a long time and the Scheme code itself, in simply creating nodes in the graph,
is expected to run to completion quite quickly, even though it can be
conceptually complex, the emphasis on the Scheme side is on debugability instead
of efficiency.
My aim, is to be able to load a Scheme program from a file, run it to have the
graph created and then clean up. On error, I'd like to print out diagnostic
information in the form of an error message with as accurate as possible source
location and a stack trace. (I'd also like to print the latter with my own
formatting to match rest of the output of the application.)
Although perhaps other approaches are possible, I have, for now, chosen to leave
memory management to the C++ side, so that my foreign objects need custom
finalization. The basic layout of my current implementation, with uninteresting
portions left out, is the following (where `run_scheme' is called by the main
program to run a Scheme script):
struct context {
char *input, **first, **last;
};
int run_scheme(const char *input, char **first, char **last)
{
struct context context = {const_cast<char *>(input), first, last};
scm_with_guile(&run_scheme_from_guile, &context);
return 0;
}
static void *run_scheme_from_guile(void *data)
{
struct context *context = static_cast<struct context *>(data);
scm_set_automatic_finalization_enabled(0);
// Define some foreign objects types and subroutines.
// [...]
scm_set_program_arguments(
context->last - context->first, context->first, context->input);
scm_c_catch(SCM_BOOL_T,
run_body, reinterpret_cast<void *>(context),
post_handler, nullptr,
pre_handler, nullptr);
scm_gc();
scm_run_finalizers();
return nullptr;
}
static SCM run_body(void *data)
{
struct context *context = static_cast<struct context *>(data);
scm_primitive_eval(
scm_list_2(
scm_from_latin1_symbol("load"),
scm_from_latin1_string(context->input)));
return SCM_UNSPECIFIED;
}
static SCM pre_handler(void *data, SCM key, SCM args)
{
SCM s = scm_make_stack(SCM_BOOL_T, SCM_EOL);
SCM p = scm_current_error_port();
scm_print_exception(p, SCM_BOOL_F, key, args);
scm_display_backtrace(s, p, SCM_BOOL_F, SCM_BOOL_F);
return SCM_BOOL_T;
}
static SCM post_handler(void *data, SCM key, SCM args)
{
return SCM_BOOL_T;
}
Actually, my code in `pre_handler' is not quite what is shown above, as I print
the stack with my own formatting, but let's leave that for later. As I said,
this seems to be working, but certain points are unclear to me after reading all
the documentation I could find and snooping around in Guile's source code:
1. The manual is not very specific about how and when finalizers are run. The
approach above seems to correctly finalize all objects created as the Scheme
code executes, but if references are kept, say via (define), they are not
finalized and I get memory leaks. Is there some way to arrange for the
complete deinitialization of Guile after I've finished evaluating Scheme code
and making sure that all finalizers are run?
2. If, in `run_body', I simply do
scm_c_primitive_load(context->input);
then the code is evaluated, but on error I get no locations in the stack
trace. The error is said to have occurred "in an unknown file" with no line
numbers. Evaluating `load' as shown above, seems to produce proper source
locations in the stack trace. Is there something else I should be preferably
doing?
3. More generally, is there a preferable way to go about embedding Guile for my
use case?
Thanks in advance for any pointers,
Dimitris
- Need help embedding Guile,
Dimitris Papavasiliou <=
- Re: Need help embedding Guile, Maxime Devos, 2021/12/21
- Re: Need help embedding Guile, Maxime Devos, 2021/12/21
- Re: Need help embedding Guile, Maxime Devos, 2021/12/21
- Re: Need help embedding Guile, Dimitris Papavasiliou, 2021/12/21
- Re: Need help embedding Guile, Olivier Dion, 2021/12/22
- Re: Need help embedding Guile, Maxime Devos, 2021/12/22