[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Difficulty integrating with Swift/Objective-C

From: Chris Vine
Subject: Re: Difficulty integrating with Swift/Objective-C
Date: Sun, 5 Sep 2021 11:56:46 +0100

On Sun, 05 Sep 2021 16:03:24 +1000
paul <> wrote:
> Good day,
> I have an existing app which is written in Swift and runs on macOS 
> 10.15.  I would like to provide users a way of customising the app 
> (initially just simple things like modifying keybindings for 
> example, later hopefully more) and as a keen Emacs user, i'm 
> inspired by the idea of providing a Schemey/Lispy interface for 
> such extensions.  Guile looks like it'd be great for this.  If i 
> understand correctly, it'd be best if i could bundle the Guile 
> runtime as a static library with the app, and call out to it to 
> evaluate user-provided code.  I haven't thought deeply about this 
> interface yet; i thought i'd get a proof-of-concept working first. 
> I wonder if i might humbly ask for some guidance on how to get it 
> working, because after a couple of days i seem to have failed. 
> I'm no C/threads/low-level guru, so my apologies if i'm doing 
> something very dumb.
> I had some difficulty getting my app to compile against Guile, but 
> i eventually managed to link against a version of Guile installed 
> with Homebrew (guile: stable 3.0.7 (bottled)), however when trying 
> to boot it up i seemed to run into the same issue described by 
> Jeffrey Walton [1].  My app would boot, and as soon as it hit the 
> Guile initialisation calls, it would error with "allocating JIT 
> code buffer failed: Permission denied, jit.c:5804: fatal: 
> assertion failed".  While that person seems to imply the problem 
> is with Apple's M1 silicon, i'm actually running an older machine 
> (2.9 GHz Dual-Core Intel Core i5, macOS 11.5.2).  I then managed 
> to get further by downloading the Guile release tarball version 
> 3.0.7 and and building with `./configure --enable-jit=no`; this 
> got me a bit further, however it still didn't work: i think it is 
> because some assumption Guile has about the thread it runs on, or 
> when it's invoked, is violated.. but i'm unsure how to find out.
> What i currently have, is this snippet.  It's being called from 
> Swift land, in the `applicationDidFinishLaunching(_ aNotification: 
> Notification)` function.  As far as i can tell, that _is_ the main 
> thread.
> ```
> #include "libguile.h"
> static void* register_functions (void* data)
> {
>     SCM test = scm_c_eval_string("(+ 3 5)");
>     int foo = scm_to_int(test);
>     printf("foo = %d\n", foo);
>     return NULL;
> }
> void run_guile() {
>     printf("hello from C, before Guile\n");
>     scm_init_guile();
>     //scm_with_guile(&register_functions, NULL); // i've tried 
>     only having this line uncommented, too, but that also causes 
>     immediate crashes
>     //scm_shell(0, NULL);
> }
> ```
> This compiles fine, and i see the "hello from C" line printed, but 
> then it crashes.  The error seems to vary, here are some i've 
> seen:
> 1. "Thread 1: EXC_BAD_ACCESS (code=1, address=0x0)" at line 182 of 
> pairs.h,
> 2. "Pre-boot error; key: misc-error, args: ("%search-path" "path 
> is not a proper list: ~a" (("/usr/local/share/guile/3.0" 
> "/usr/local/share/guile/site/3.0" "/usr/local/share/guile/site" 
> . #<program 12503b140 124fc10fc>)) #f)", "Thread 1: signal 
> SIGABRT", line 260 of throw.c
> 3. "Thread 1: EXC_BAD_ACCESS (code=1, address=0x9)", at line 585 
> of weak-set.c.
> 4. I've also sometimes seen this one, 
> although perhaps that's indeed related to closed stdout.
> Because these errors are different all the time i guess it's some 
> race condition or threading issue?  I wonder if someone knows an 
> avenue i can attempt to use to debug what's going on? 🙏

You appear to want to run scheme code as an extension language, via the
guile VM, in a program written for MacOS in the Swift language.  I know
nothing about the Swift language and whether it has a sufficient C-like
FFI to achieve this, but you may get some inspiration from the
following, which enables scheme code to be run as an extension language
within a C++ program:

However there are various issues.  First, guile's exceptions
(based on C's longjmp()/setjmp() and cognates) are almost certainly
not implemented in the same way as Swift's exceptions (assuming Swift
has exceptions), which means amongst other things that, if Swift has
something akin to destructors/deinitialization, you should not allow
guile exceptions to leave Swift objects undestroyed were guile to
jump out of local scope on raising an exception (scm_dynwind_begin(),
scm_dynwind_end and scm_dynwind_unwind_handler can be useful here if
you are able to manage your Swift objects manually in C).  Nor more
generally should you allow Swift exceptions (if Swift has them) to
escape out of a guile scm_dynwind_begin()/scm_dynwind_end() pair, or
you will stop guile's resource management working correctly.

Secondly, there are some issues relating to the fact that guile's
'make-fresh-user-module' and 'load' procedures leak memory, which can
be problematic if all tasks run as scheme code are not to share the
same top level.

Thirdly you will need to cater for translating guile return values such
as lists or vectors into containers that Swift can work with, and vice

This is all pretty well documented in the C++ code mentioned above, but
it is not for the faint hearted.


reply via email to

[Prev in Thread] Current Thread [Next in Thread]