Re: Difficulty integrating with Swift/Objective-C
On 05.09.2021 08:03, 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(®ister_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" . # 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, > https://lists.gnu.org/archive/html/emacs-bug-tracker/2020-01/msg00365.html, > 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? 🙏 > > All the best, > paul > > 1. https://mail.gnu.org/archive/html/bug-guile/2021-03/msg00012.html > Hi Paul, To narrow down the issue, I'd attempt a few things, in order: 1. Compile only the C code, adding a main() function, just to make sure the OS and the chosen Guile version and such are working fine with each other. 2. Compile pure Objective-C code, calling that run_guile() function firstly directly from the main() function in main.m of the Objective-C program, and commenting out the NSApplicationMain() call that would initialize Apple's application framework. 3. See if reactivating the NSApplicationMain() call causes problems. (It should be called *after* the Guile initialization.) 4. See if you can use Guile's C functions from -applicationDidFinishLaunching: e.g. by doing: scm_c_eval_string("(begin (display 'HelloWorld) (newline))") If that works, we now have an Objective-C + Guile application, and want to move to using Swift instead. This is where my Apple knowledge hits its limits because I never used Swift. :-) But I guess Swift should have something equivalent to the main() function of C and Objective-C, and calling Guile initialization from there might do the trick. If you hit a problem in step 3 or 4, then it could mean that Guile and Cocoa are somehow incompatible as they both want to apply some
Re: Difficulty integrating with Swift/Objective-C
Hey Taylan, Thank you for your reply! On 2021-09-05 at 18:26 AEST, quoth Taylan Kammer : To narrow down the issue, I'd attempt a few things, in order: 1. Compile only the C code, adding a main() function, just to make sure the OS and the chosen Guile version and such are working fine with each other. 2. Compile pure Objective-C code, calling that run_guile() function firstly directly from the main() function in main.m of the Objective-C program, and commenting out the NSApplicationMain() call that would initialize Apple's application framework. 3. See if reactivating the NSApplicationMain() call causes problems. (It should be called *after* the Guile initialization.) 4. See if you can use Guile's C functions from -applicationDidFinishLaunching: e.g. by doing: scm_c_eval_string("(begin (display 'HelloWorld) (newline))") If that works, we now have an Objective-C + Guile application, and want to move to using Swift instead. This is where my Apple knowledge hits its limits because I never used Swift. :-) But I guess Swift should have something equivalent to the main() function of C and Objective-C, and calling Guile initialization from there might do the trick. If you hit a problem in step 3 or 4, then it could mean that Guile and Cocoa are somehow incompatible as they both want to apply some magic to the C program while initializing themselves. I wouldn't know how to approach that issue. Actually, in my case there is no Objective-C code, only Swift, but these suggestions definitely give me some inspiration for things to try. I'll see if i can figure out how the NSApplication is bootstrapped so that i can hook in before that, because indeed, the way i tried, i was attempting to initialise Guile from deep within Application Kit code, which could be doomed to fail :). Anyway i am heading away from my computer now, but will definitely give this angle a try — thanks for taking the time to reply! Kind regards, p.
Re: Difficulty integrating with Swift/Objective-C
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(®ister_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" > . #)) #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, > https://lists.gnu.org/archive/html/emacs-bug-tracker/2020-01/msg00365.html, > 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: https://sourceforge.net/p/cxx-gtk-utils/git/ci/master/tree/c++-gtk-utils/extension.h 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
[ANN] nyacc 1.05.0 released
NYACC, for Not Yet Another Compiler Compiler, is set of guile modules for generating parsers and lexical analyzers. It also provides sample parsers and pretty-printers using SXML trees as an intermediate representation. It provides a decent C parser and a `FFI Helper' tool to help create Guile Scheme bindings for C-based libraries. It provides (partially implemented) compilers based on above mentioned parsers to allow execution with Guile as extension languages. NEWS for V1.05.0 * remove dependence on srfi-43, vector operations; this was causing issues with some Guile versions 2.0.X * cleaned up c99-error exception messages in compile-ffi * examples/ffi/termios.ffi: added def-keepers * in following, $ENL = examples/nyacc/lang * removed $ENL/ecmascript * $ENL/javascript: merged body.scm into parser.scm * install/uninstall read-line-code now returns # * $ENL/tcl/parser.scm: fixed reading array index as number; (1,2,3) was read as number, now as string * scripts/compile-ffi: add option -s to show includes being read * c99 parser def-help now adds apple dependencies * worked on ffi-helper per-decl usage (i.e. C-decl syntax) * updated "make check" to provide overall sucess/fail message Example using FFI helper w/o define-ffi-module: mwette$ guile ... scheme@(guile-user)> ,use (nyacc lang c99 ffi-help) scheme@(guile-user)> ,pp (C-decl->scm "struct foo { int x; double y; };") $1 = (bs:struct (list `(x ,int) `(y ,double))) scheme@(guile-user)> scheme@(guile-user)> ,use (bytestructures guile) scheme@(guile-user)> ,use (system ffi-help-rt) scheme@(guile-user)> (use-modules ((system foreign) #:prefix ffi:)) scheme@(guile-user)> scheme@(guile-user)> (define struct-foo-desc (C-decl "struct foo { int x; double y; };")) scheme@(guile-user)> (define-fh-compound-type struct-foo struct-foo-desc struct-foo? make-struct-foo) scheme@(guile-user)> (make-struct-foo) $2 = # scheme@(guile-user)> scheme@(guile-user)> (define my-sqrt (C-decl "double sqrt(double);")) scheme@(guile-user)> (my-sqrt 4.0) $3 = 2.0 scheme@(guile-user)> mwette$ guile ... scheme@(guile-user)> ,use (nyacc lang c99 ffi-help) scheme@(guile-user)> ,d load-include-file - Procedure: load-include-file filename [#:pkg-config pkg] This is the functionality that Ludo was asking for: to be at guile prompt and be able to issue (use-modules (nyacc lang c99 ffi-help)) (load-include-file "cairo.h" #:pkg-config "cairo") scheme@(guile-user)> (load-include-file "cairo.h" #:pkg-config "cairo") ... NYACC maturity is production/stable level. NYACC is free software; the full source distribution is available through * the tarball repository: https://download.savannah.gnu.org/releases/nyacc/ * the git repository: git://git.savannah.nongnu.org/nyacc.git home page, project page and user's guides: * https://www.nongnu.org/nyacc * https://savannah.nongnu.org/projects/nyacc * https://www.nongnu.org/nyacc/nyacc-ug.html * https://www.nongnu.org/nyacc/ffi-help.html Report bugs: * https://savannah.nongnu.org/bugs/?group=nyacc Get support: * https://savannah.nongnu.org/support/?group=nyacc