unofficial mirror of guile-user@gnu.org 
 help / color / mirror / Atom feed
* Need help embedding Guile
@ 2021-12-21 11:12 Dimitris Papavasiliou
  2021-12-21 11:37 ` Maxime Devos
  0 siblings, 1 reply; 16+ messages in thread
From: Dimitris Papavasiliou @ 2021-12-21 11:12 UTC (permalink / raw)
  To: guile-user@gnu.org

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




^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2021-12-29 16:26 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-12-21 11:12 Need help embedding Guile Dimitris Papavasiliou
2021-12-21 11:37 ` Maxime Devos
2021-12-21 13:45   ` Maxime Devos
2021-12-21 13:48   ` Maxime Devos
2021-12-21 21:50   ` Dimitris Papavasiliou
2021-12-21 22:39     ` Olivier Dion via General Guile related discussions
2021-12-22 11:41       ` Dimitris Papavasiliou
2021-12-22 13:52         ` Thien-Thi Nguyen
2021-12-22 22:05           ` Dimitris Papavasiliou
2021-12-22 14:46         ` Olivier Dion via General Guile related discussions
2021-12-22 15:23           ` Maxime Devos
2021-12-22 15:29         ` Maxime Devos
2021-12-22 22:14           ` Dimitris Papavasiliou
2021-12-22 17:37         ` Mikael Djurfeldt
2021-12-23  9:40           ` Mikael Djurfeldt
2021-12-29 16:26           ` Olivier Dion via General Guile related discussions

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).