Hi there,
I want to extend a C++ program with Guile, mainly for configuration and
parameter scripting. For this, I need access class objects and
methods. I could not found simple examples so I started to experiment
with Smobs and only by chance find out that they are deprecated in
favour of foreign object. Unfortunately I am stuck very early. I just
want to implement the example from the documentation; I assembled the
snippets and compiled it. But it fails to run the simple test and
terminates with Segmentation Fault.
What have I done wrong?
My build and interaction:
-------------------------
$ gcc `guile-config compile` -c foreign.c
$ gcc foreign.o `guile-config link` -o foreign
$ ./foreign
GNU Guile 2.2.6
Copyright (C) 1995-2019 Free Software Foundation, Inc.
Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'.
This program is free software, and you are welcome to redistribute it
under certain conditions; type `,show c' for details.
Enter `,help' for help.
scheme@(guile-user)> make-image
$1 = #<procedure make-image (_ _ _)>
scheme@(guile-user)> (make-image "Whistler's Mother" 100 100)
Segmentation fault
foreign.c:
----------
#include <libguile.h>
static void main_prog (void *closure, int argc, char *argv[]);
struct image
{
int width, height;
char *pixels;
/* The name of this image */
SCM name;
/* A function to call when this image is
modified, e.g., to update the screen,
or SCM_BOOL_F if no action necessary */
SCM update_func;
};
static SCM image_type;
void
init_image_type (void)
{
SCM name, slots;
scm_t_struct_finalize finalizer;
name = scm_from_utf8_symbol ("image");
slots = scm_list_1 (scm_from_utf8_symbol ("data"));
finalizer = NULL;
image_type = scm_make_foreign_object_type (name, slots, finalizer);
}
SCM
make_image (SCM name, SCM s_width, SCM s_height)
{
struct image *image;
int width = scm_to_int (s_width);
int height = scm_to_int (s_height);
/* Allocate the `struct image'. Because we
use scm_gc_malloc, this memory block will
be automatically reclaimed when it becomes
inaccessible, and its members will be traced
by the garbage collector. */
image = (struct image *) scm_gc_malloc (sizeof (struct image), "image");
image->width = width;
image->height = height;
/* Allocating the pixels with
scm_gc_malloc_pointerless means that the
pixels data is collectable by GC, but
that GC shouldn't spend time tracing its
contents for nested pointers because there
aren't any. */
image->pixels = scm_gc_malloc_pointerless (width * height, "image pixels");
image->name = name;
image->update_func = SCM_BOOL_F;
/* Now wrap the struct image* in a new foreign
object, and return that object. */
return scm_make_foreign_object_1 (image_type, image);
}
SCM
clear_image (SCM image_obj)
{
int area;
struct image *image;
scm_assert_foreign_object_type (image_type, image_obj);
image = scm_foreign_object_ref (image_obj, 0);
area = image->width * image->height;
memset (image->pixels, 0, area);
/* Invoke the image's update function. */
if (scm_is_true (image->update_func))
scm_call_0 (image->update_func);
return SCM_UNSPECIFIED;
}
static void *
register_functions (void *data)
{
scm_c_define_gsubr ("make-image", 3, 0, 0, make_image);
scm_c_define_gsubr ("clear-image", 1, 0, 0, clear_image);
return NULL;
}
int
main (int argc, char *argv[])
{
scm_boot_guile (argc, argv, main_prog, 0);
return 0;
}
static void
main_prog (void *closure, int argc, char *argv[])
{
scm_with_guile (®ister_functions, NULL);
scm_shell (argc, argv);
}