unofficial mirror of guile-user@gnu.org 
 help / color / mirror / Atom feed
From: Dimitris Papavasiliou <dpapavas@protonmail.ch>
To: "guile-user@gnu.org" <guile-user@gnu.org>
Subject: Need help embedding Guile
Date: Tue, 21 Dec 2021 11:12:54 +0000	[thread overview]
Message-ID: <B06KtohfOgQJEKiyjWFF902QowT8UGx6Nqmj7JFZsUjsVUlu0N6AwZ3fRP3pwSkmmm4eo22sa2cm8jx7Ye_4j-QsW2YSnYMM3Jilu00Piv4=@protonmail.ch> (raw)

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




             reply	other threads:[~2021-12-21 11:12 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-12-21 11:12 Dimitris Papavasiliou [this message]
2021-12-21 11:37 ` Need help embedding Guile 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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/guile/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='B06KtohfOgQJEKiyjWFF902QowT8UGx6Nqmj7JFZsUjsVUlu0N6AwZ3fRP3pwSkmmm4eo22sa2cm8jx7Ye_4j-QsW2YSnYMM3Jilu00Piv4=@protonmail.ch' \
    --to=dpapavas@protonmail.ch \
    --cc=guile-user@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).