Lisp HUG Maillist Archive

Building deliverables using CFFI libraries

Hi all,

This is a convoluted question, but to start, I'm wondering if folks have successfully used the lisp works delivery mechanism incorporating libraries that use the CFFI module (not the builtin ffi module that is part of lispworks).

I need to use freetype2 with my project, and as part of that, fixed up a few things [1] in cl-freetype2 so that it will run in 
lispworks.  As part of this, I've also compiled the underlying freetype2 library for macOS as "libfreetype.6.dylib".  

Now, when I ql:quickload/asdf:load-system cl-freetype2, I push the library folder location on to: cffi:*foreign-library-directories*.  When delivering this ends up being a different value than when the MacOS application is run, since that is calculated at runtime using: "(pathname-directory (lw:lisp-image-name))".

As you can imagine, I've gotten some invalid library handles and some segmentation faults, as the loaded library instance is different during delivery and actual application run.  I've tried a few things... fiddling around with CFFI:unload-xyzed and reloading.  I've also tried just asdf:compile-system for cl-freetype2 during the delivery stage and avoided using it at all in my code until the application is started up.

The easiest thing to do would likely be to include cl-freetype2 locally in the application bundle and just load it at application startup and avoid any dependencies on it during delivery, but the CFFI and groveling stuff requires compile-file which doesn't work in a delivered image (just tried this).

I'm sort of a mid-level lisp programmer (if that), so I'm not sure if there is some combination of CFFI [2] magic with lispworks delivery magic that should be obvious here.  But if anyone has experience using a library that's backed by CFFI where you're including the C dynamic library so that it's not required to be on the users system, and have figured out how to make this work with lispworks delivery, I would greatly appreciate any advice or tips.

Cheers!
Steve

[1] or at least am in the process of. Fixed one thing, and commented out another:
https://github.com/sgithens/cl-freetype2/tree/lispworks-fixup

[2] which this is likely the wrong email list for

Re: Building deliverables using CFFI libraries

I have no idea if https://github.com/Shinmera/deploy has been tried with LispWorks, but it attempts to copy all found foreign libraries into the directory of the deployed binary to avoiddeployment issues. It is based around CFFI + ASDF and should therefore work with LispWorks as long as ASDF works with LispWorks (which I suppose it does).

BR
~phoe

On 04.12.2020 22:02, Steven Githens wrote:
Hi all,

This is a convoluted question, but to start, I'm wondering if folks have successfully used the lisp works delivery mechanism incorporating libraries that use the CFFI module (not the builtin ffi module that is part of lispworks).

I need to use freetype2 with my project, and as part of that, fixed up a few things [1] in cl-freetype2 so that it will run in 
lispworks.  As part of this, I've also compiled the underlying freetype2 library for macOS as "libfreetype.6.dylib".  

Now, when I ql:quickload/asdf:load-system cl-freetype2, I push the library folder location on to: cffi:*foreign-library-directories*.  When delivering this ends up being a different value than when the MacOS application is run, since that is calculated at runtime using: "(pathname-directory (lw:lisp-image-name))".

As you can imagine, I've gotten some invalid library handles and some segmentation faults, as the loaded library instance is different during delivery and actual application run.  I've tried a few things... fiddling around with CFFI:unload-xyzed and reloading.  I've also tried just asdf:compile-system for cl-freetype2 during the delivery stage and avoided using it at all in my code until the application is started up.

The easiest thing to do would likely be to include cl-freetype2 locally in the application bundle and just load it at application startup and avoid any dependencies on it during delivery, but the CFFI and groveling stuff requires compile-file which doesn't work in a delivered image (just tried this).

I'm sort of a mid-level lisp programmer (if that), so I'm not sure if there is some combination of CFFI [2] magic with lispworks delivery magic that should be obvious here.  But if anyone has experience using a library that's backed by CFFI where you're including the C dynamic library so that it's not required to be on the users system, and have figured out how to make this work with lispworks delivery, I would greatly appreciate any advice or tips.

Cheers!
Steve

[1] or at least am in the process of. Fixed one thing, and commented out another:
https://github.com/sgithens/cl-freetype2/tree/lispworks-fixup

[2] which this is likely the wrong email list for

Re: Building deliverables using CFFI libraries

Hi Steven,

About 2 years ago, we ran into the same kinds of problems, and solved them for ourselves in our Crypto libs for the Emotiq blockchain system. The source is publicly available here:

https://github.com/stegos/Chat/tree/dev/src/Crypto


and more specifically here,

https://github.com/stegos/Chat/blob/dev/src/Crypto/lib-loads.lisp

but the details of what we finally did elude me at the moment. We did make use of CFFI throughout to keep the source code maximally portable. Each major subcomponent calls an initialization routine when it becomes loaded, see example at end of source for PBC (Pairing Based Crypto)

https://github.com/stegos/Chat/blob/dev/src/Crypto/pbc-cffi.lisp


- David McClain
Refined Audiometrics Laboratory, LLC
refined-audiometrics.com



On Dec 4, 2020, at 2:02 PM, Steven Githens <steve@githens.org> wrote:

Hi all,

This is a convoluted question, but to start, I'm wondering if folks have successfully used the lisp works delivery mechanism incorporating libraries that use the CFFI module (not the builtin ffi module that is part of lispworks).

I need to use freetype2 with my project, and as part of that, fixed up a few things [1] in cl-freetype2 so that it will run in 
lispworks.  As part of this, I've also compiled the underlying freetype2 library for macOS as "libfreetype.6.dylib".  

Now, when I ql:quickload/asdf:load-system cl-freetype2, I push the library folder location on to: cffi:*foreign-library-directories*.  When delivering this ends up being a different value than when the MacOS application is run, since that is calculated at runtime using: "(pathname-directory (lw:lisp-image-name))".

As you can imagine, I've gotten some invalid library handles and some segmentation faults, as the loaded library instance is different during delivery and actual application run.  I've tried a few things... fiddling around with CFFI:unload-xyzed and reloading.  I've also tried just asdf:compile-system for cl-freetype2 during the delivery stage and avoided using it at all in my code until the application is started up.

The easiest thing to do would likely be to include cl-freetype2 locally in the application bundle and just load it at application startup and avoid any dependencies on it during delivery, but the CFFI and groveling stuff requires compile-file which doesn't work in a delivered image (just tried this).

I'm sort of a mid-level lisp programmer (if that), so I'm not sure if there is some combination of CFFI [2] magic with lispworks delivery magic that should be obvious here.  But if anyone has experience using a library that's backed by CFFI where you're including the C dynamic library so that it's not required to be on the users system, and have figured out how to make this work with lispworks delivery, I would greatly appreciate any advice or tips.

Cheers!
Steve

[1] or at least am in the process of. Fixed one thing, and commented out another:
https://github.com/sgithens/cl-freetype2/tree/lispworks-fixup

[2] which this is likely the wrong email list for

Re: Building deliverables using CFFI libraries

Hi again,

Thanks for the responses, it's been helpful to look through all the example code.  Also, thanks Arnold for pointing out that CFFI actually does use fli under the covers, it was helpful to clone the CFFI repo and look through how that actually works.

I think I'm starting to get close...  in my Delivery script I'm using:

(cffi:close-foreign-library 'FREETYPE2::FREETYPE2)

and I can see that it's returning T.

and in application start defun I'm using:

(pushnew
(make-pathname :directory
(append (butlast (pathname-directory (lw:lisp-image-name)))
'("Resources" "libs")))
cffi:*foreign-library-directories* :test #'equal)
(cffi:use-foreign-library freetype2::freetype2)

Which appears to be reloading it, although I reliably get a handful of different loading errors. (some of them below) The path in these errors IS the correct path to the library file though...

-Steve

sgithens load-foreign-library FREETYPE2 /Users/sgithens/code/boxer-sunrise2/data/boxersunrise.app/Contents/Resources/libs/libfreetype.6.dylib 


Error: Segmentation violation(11) [code 0] at 1006BF128

        Foreign code offset #x38 from symbol "FT_Stream_New"

        module "/Users/sgithens/code/boxer-sunrise2/data/boxersunrise.app/Contents/Resources/libs/libfreetype.6.dylib" [ #x1006B8000 ]

rax        1EC00 ; rbx    108164810 ; rcx 600000008600 ; rdx 70000101FB58

rsp 70000101FAE0 ; rbp 70000101FB10 ; rdi    1080F5570 ; rsi           50

r8             1 ; r9    40A03B6D3B ; r10   4040070C6B ; r11    1006C00A0

r12 70000101FBB0 ; r13 600000008680 ; r14 70000101FB58 ; r15    1080F5570

  1 (abort) Quit process.


or

sgithens load-foreign-library FREETYPE2 /Users/sgithens/code/boxer-sunrise2/data/boxersunrise.app/Contents/Resources/libs/libfreetype.6.dylib 


Error: FreeType error: INVALID-LIBRARY-HANDLE

  1 (abort) Quit process.




On Fri, Dec 4, 2020, at 2:11 PM, Arnold Noronha wrote:

On Fri, Dec 04, 2020 at 01:02:50PM -0800, Steven Githens wrote:
> Hi all,
>
> This is a convoluted question, but to start, I'm wondering if folks have successfully used the lisp works delivery mechanism incorporating libraries that use the CFFI module (not the builtin ffi module that is part of lispworks).

Since CFFI uses FLI under the hood you should still be able to use FLI
functions.

I used fli:disconnect-module just before delivery. (I am using my own
library though, so not 100% sure it's easy to do this from an external
library loaded with CFFI). Then use fli:get-embedded-module in your
app, and fli:install-embedded-module in your init function in the
delivered app.

--Arnold


Re: Building deliverables using CFFI libraries

I came upon a similar issue, and was able to find the solution in the LispWorks documentation.

You can work your way through the following list of solutions from top to bottom:

- LW 29.8, external libraries used with 64-bit LispWorks must be 64-bit libraries, with 32-bit LispWorks must be 32-bit libraries
- DV 4.4.5, be certain the calls to load the foreign libraries with CFFI, register-module (or the embedded-module interface mentioned below) are made within function bodies and not top-level. This ensures the dynamic library is loaded in full at runtime, when the wrapper function is called, and not during compilation or delivery.
- DV 10.6, there are some useful notes here on how the FLI converts between foreign and Lisp objects, and parts of the delivery process that might clobber your FLI; mostly missing templates, occasionally memory errors.
- FLI 5.5, how to correctly load and access both C and C++ dynamic libraries; there’s some extra work with C++. Haven’t used FREETYPE2 myself, so not immediately clear on its implementation.
- FLI 5.6, covers embedding dynamically-loaded foreign libraries inside the Lisp image, instead of relying separate libraries loaded at runtime. The embedded-module interface handles a lot of extra complexity, if it can be used with CFFI. Maybe try this on a new branch of your source control some other time.

That should cover all of the possible cases for the errors you’re getting. If not, see LW 11.4 for a review of memory management in 64-bit LispWorks, or LW 11.3 for 32-bit.

If you’re interested in why you’re getting those specific memory error patterns, LW 11.6 has a few notes on reducing image size and garbage collection of foreign-objects that explains most of it. For example, clean-down is called automatically before delivery, IIRC.


--

Colin J.E. Lupton
CEO, Founder, Principal Quantum Metamachinist
Black Brane Systems, Inc.
https://blackbrane.com/

phone: +1 (833) 227-2630 x700
fax: +1 (833) 227-2630
email: colin@blackbrane.com

Sent from Outlook for iOS

From: owner-lisp-hug@lispworks.com <owner-lisp-hug@lispworks.com> on behalf of Steven Githens <steve@githens.org>
Sent: Friday, December 4, 2020 7:48:39 PM
To: Arnold Noronha <arnold@tdrhq.com>
Cc: lisp-hug@lispworks.com <lisp-hug@lispworks.com>
Subject: Re: Building deliverables using CFFI libraries
 
Hi again,

Thanks for the responses, it's been helpful to look through all the example code.  Also, thanks Arnold for pointing out that CFFI actually does use fli under the covers, it was helpful to clone the CFFI repo and look through how that actually works.

I think I'm starting to get close...  in my Delivery script I'm using:

(cffi:close-foreign-library 'FREETYPE2::FREETYPE2)

and I can see that it's returning T.

and in application start defun I'm using:

(pushnew
(make-pathname :directory
(append (butlast (pathname-directory (lw:lisp-image-name)))
'("Resources" "libs")))
cffi:*foreign-library-directories* :test #'equal)
(cffi:use-foreign-library freetype2::freetype2)

Which appears to be reloading it, although I reliably get a handful of different loading errors. (some of them below) The path in these errors IS the correct path to the library file though...

-Steve

sgithens load-foreign-library FREETYPE2 /Users/sgithens/code/boxer-sunrise2/data/boxersunrise.app/Contents/Resources/libs/libfreetype.6.dylib 


Error: Segmentation violation(11) [code 0] at 1006BF128

        Foreign code offset #x38 from symbol "FT_Stream_New"

        module "/Users/sgithens/code/boxer-sunrise2/data/boxersunrise.app/Contents/Resources/libs/libfreetype.6.dylib" [ #x1006B8000 ]

rax        1EC00 ; rbx    108164810 ; rcx 600000008600 ; rdx 70000101FB58

rsp 70000101FAE0 ; rbp 70000101FB10 ; rdi    1080F5570 ; rsi           50

r8             1 ; r9    40A03B6D3B ; r10   4040070C6B ; r11    1006C00A0

r12 70000101FBB0 ; r13 600000008680 ; r14 70000101FB58 ; r15    1080F5570

  1 (abort) Quit process.


or

sgithens load-foreign-library FREETYPE2 /Users/sgithens/code/boxer-sunrise2/data/boxersunrise.app/Contents/Resources/libs/libfreetype.6.dylib 


Error: FreeType error: INVALID-LIBRARY-HANDLE

  1 (abort) Quit process.




On Fri, Dec 4, 2020, at 2:11 PM, Arnold Noronha wrote:

On Fri, Dec 04, 2020 at 01:02:50PM -0800, Steven Githens wrote:
> Hi all,
>
> This is a convoluted question, but to start, I'm wondering if folks have successfully used the lisp works delivery mechanism incorporating libraries that use the CFFI module (not the builtin ffi module that is part of lispworks).

Since CFFI uses FLI under the hood you should still be able to use FLI
functions.

I used fli:disconnect-module just before delivery. (I am using my own
library though, so not 100% sure it's easy to do this from an external
library loaded with CFFI). Then use fli:get-embedded-module in your
app, and fli:install-embedded-module in your init function in the
delivered app.

--Arnold


Re: Building deliverables using CFFI libraries

Hi Colin,

Thanks for this meticulously crafted set of references.  I'm on MacOS Catalina with Lispworks 7.1.2, so everything should be 64-bit since it doesn't support 32-bit apps.  I actually went ahead and hacked up cl-freetype2 quick to use embedded-modules since that would be great, but pretty much get the same errors.

I did try out the deliver option ":in-memory-delivery t" and of course it works fine, so it's definitely some particular issue with loading the lisp image back up.  

Also randomly, I just did some small testing in the REPL with unloading the dylib, and got results that surprised me, in that I was still able to use the library after unloading it... I don't think it's being aggressively reloaded, because when I unload it again I get `nil` which would be expected...

I have a transcript of it here:  https://gist.github.com/sgithens/1e6c68bb985e2cc31af0e8fcd19422a6

~Steve

On Fri, Dec 4, 2020, at 6:14 PM, Colin J.E. Lupton wrote:
I came upon a similar issue, and was able to find the solution in the LispWorks documentation.

You can work your way through the following list of solutions from top to bottom:

- LW 29.8, external libraries used with 64-bit LispWorks must be 64-bit libraries, with 32-bit LispWorks must be 32-bit libraries
- DV 4.4.5, be certain the calls to load the foreign libraries with CFFI, register-module (or the embedded-module interface mentioned below) are made within function bodies and not top-level. This ensures the dynamic library is loaded in full at runtime, when the wrapper function is called, and not during compilation or delivery.
- DV 10.6, there are some useful notes here on how the FLI converts between foreign and Lisp objects, and parts of the delivery process that might clobber your FLI; mostly missing templates, occasionally memory errors.
- FLI 5.5, how to correctly load and access both C and C++ dynamic libraries; there’s some extra work with C++. Haven’t used FREETYPE2 myself, so not immediately clear on its implementation.
- FLI 5.6, covers embedding dynamically-loaded foreign libraries inside the Lisp image, instead of relying separate libraries loaded at runtime. The embedded-module interface handles a lot of extra complexity, if it can be used with CFFI. Maybe try this on a new branch of your source control some other time.

That should cover all of the possible cases for the errors you’re getting. If not, see LW 11.4 for a review of memory management in 64-bit LispWorks, or LW 11.3 for 32-bit.

If you’re interested in why you’re getting those specific memory error patterns, LW 11.6 has a few notes on reducing image size and garbage collection of foreign-objects that explains most of it. For example, clean-down is called automatically before delivery, IIRC.


--

Colin J.E. Lupton
CEO, Founder, Principal Quantum Metamachinist
Black Brane Systems, Inc.
https://blackbrane.com/


phone: +1 (833) 227-2630 x700
fax: +1 (833) 227-2630
email: colin@blackbrane.com


Sent from Outlook for iOS


From: owner-lisp-hug@lispworks.com <owner-lisp-hug@lispworks.com> on behalf of Steven Githens <steve@githens.org>
Sent: Friday, December 4, 2020 7:48:39 PM
To: Arnold Noronha <arnold@tdrhq..com>
Cc: lisp-hug@lispworks.com <lisp-hug@lispworks.com>
Subject: Re: Building deliverables using CFFI libraries
 
Hi again,

Thanks for the responses, it's been helpful to look through all the example code.  Also, thanks Arnold for pointing out that CFFI actually does use fli under the covers, it was helpful to clone the CFFI repo and look through how that actually works.

I think I'm starting to get close...  in my Delivery script I'm using:

(cffi:close-foreign-library 'FREETYPE2::FREETYPE2)

and I can see that it's returning T.

and in application start defun I'm using:

(pushnew
(make-pathname :directory
(append (butlast (pathname-directory (lw:lisp-image-name)))
'("Resources" "libs")))
cffi:*foreign-library-directories* :test #'equal)
(cffi:use-foreign-library freetype2::freetype2)

Which appears to be reloading it, although I reliably get a handful of different loading errors. (some of them below) The path in these errors IS the correct path to the library file though...

-Steve

sgithens load-foreign-library FREETYPE2 /Users/sgithens/code/boxer-sunrise2/data/boxersunrise.app/Contents/Resources/libs/libfreetype.6.dylib 


Error: Segmentation violation(11) [code 0] at 1006BF128

        Foreign code offset #x38 from symbol "FT_Stream_New"

        module "/Users/sgithens/code/boxer-sunrise2/data/boxersunrise.app/Contents/Resources/libs/libfreetype.6.dylib" [ #x1006B8000 ]

rax        1EC00 ; rbx    108164810 ; rcx 600000008600 ; rdx 70000101FB58

rsp 70000101FAE0 ; rbp 70000101FB10 ; rdi    1080F5570 ; rsi           50

r8             1 ; r9    40A03B6D3B ; r10   4040070C6B ; r11    1006C00A0

r12 70000101FBB0 ; r13 600000008680 ; r14 70000101FB58 ; r15    1080F5570

  1 (abort) Quit process.


or

sgithens load-foreign-library FREETYPE2 /Users/sgithens/code/boxer-sunrise2/data/boxersunrise.app/Contents/Resources/libs/libfreetype.6.dylib 


Error: FreeType error: INVALID-LIBRARY-HANDLE

  1 (abort) Quit process.




On Fri, Dec 4, 2020, at 2:11 PM, Arnold Noronha wrote:

On Fri, Dec 04, 2020 at 01:02:50PM -0800, Steven Githens wrote:
> Hi all,
>
> This is a convoluted question, but to start, I'm wondering if folks have successfully used the lisp works delivery mechanism incorporating libraries that use the CFFI module (not the builtin ffi module that is part of lispworks).

Since CFFI uses FLI under the hood you should still be able to use FLI
functions.

I used fli:disconnect-module just before delivery. (I am using my own
library though, so not 100% sure it's easy to do this from an external
library loaded with CFFI). Then use fli:get-embedded-module in your
app, and fli:install-embedded-module in your init function in the
delivered app.

--Arnold



Re: Building deliverables using CFFI libraries

It was no trouble. To be honest, that was off the top of my head, other then double-checking section references.

I figured the 32 vs 64-bit issue was unlikely or impossible on any recent Mac, it was only there for the just-in-case.

In-memory delivery is a great feature. But that’s really interesting that it works delivered in memory, but not reloaded.

That last part isn’t unusual. Memory architectures are typically hierarchical and cached, and Lisp images operate under the closed-world assumption, so the effect is even more pronounced as a result. Unloading the module isn’t the actual action of wiping the addressed range of blocks, it’s tagging it for collection at the next run of the garbage collector.

Anything else left from the list?

I’ll check the transcript for any insights, as well.


--

Colin J.E. Lupton
CEO, Founder, Principal Quantum Metamachinist
Black Brane Systems, Inc.
https://blackbrane.com/

phone: +1 (833) 227-2630 x700
fax: +1 (833) 227-2630
email: colin@blackbrane.com

Sent from Outlook for iOS

From: owner-lisp-hug@lispworks.com <owner-lisp-hug@lispworks.com> on behalf of Steven Githens <steve@githens.org>
Sent: Friday, December 4, 2020 11:00:22 PM
To: lisp-hug@lispworks.com <lisp-hug@lispworks.com>
Subject: Re: Building deliverables using CFFI libraries
 
Hi Colin,

Thanks for this meticulously crafted set of references.  I'm on MacOS Catalina with Lispworks 7.1.2, so everything should be 64-bit since it doesn't support 32-bit apps.  I actually went ahead and hacked up cl-freetype2 quick to use embedded-modules since that would be great, but pretty much get the same errors.

I did try out the deliver option ":in-memory-delivery t" and of course it works fine, so it's definitely some particular issue with loading the lisp image back up.  

Also randomly, I just did some small testing in the REPL with unloading the dylib, and got results that surprised me, in that I was still able to use the library after unloading it... I don't think it's being aggressively reloaded, because when I unload it again I get `nil` which would be expected...

I have a transcript of it here:  https://gist.github.com/sgithens/1e6c68bb985e2cc31af0e8fcd19422a6

~Steve

On Fri, Dec 4, 2020, at 6:14 PM, Colin J.E. Lupton wrote:
I came upon a similar issue, and was able to find the solution in the LispWorks documentation.

You can work your way through the following list of solutions from top to bottom:

- LW 29.8, external libraries used with 64-bit LispWorks must be 64-bit libraries, with 32-bit LispWorks must be 32-bit libraries
- DV 4.4.5, be certain the calls to load the foreign libraries with CFFI, register-module (or the embedded-module interface mentioned below) are made within function bodies and not top-level. This ensures the dynamic library is loaded in full at runtime, when the wrapper function is called, and not during compilation or delivery.
- DV 10.6, there are some useful notes here on how the FLI converts between foreign and Lisp objects, and parts of the delivery process that might clobber your FLI; mostly missing templates, occasionally memory errors.
- FLI 5.5, how to correctly load and access both C and C++ dynamic libraries; there’s some extra work with C++. Haven’t used FREETYPE2 myself, so not immediately clear on its implementation.
- FLI 5.6, covers embedding dynamically-loaded foreign libraries inside the Lisp image, instead of relying separate libraries loaded at runtime. The embedded-module interface handles a lot of extra complexity, if it can be used with CFFI. Maybe try this on a new branch of your source control some other time.

That should cover all of the possible cases for the errors you’re getting. If not, see LW 11.4 for a review of memory management in 64-bit LispWorks, or LW 11.3 for 32-bit.

If you’re interested in why you’re getting those specific memory error patterns, LW 11.6 has a few notes on reducing image size and garbage collection of foreign-objects that explains most of it. For example, clean-down is called automatically before delivery, IIRC.


--

Colin J.E. Lupton
CEO, Founder, Principal Quantum Metamachinist
Black Brane Systems, Inc.
https://blackbrane.com/


phone: +1 (833) 227-2630 x700
fax: +1 (833) 227-2630
email: colin@blackbrane.com


Sent from Outlook for iOS


From: owner-lisp-hug@lispworks.com <owner-lisp-hug@lispworks.com> on behalf of Steven Githens <steve@githens.org>
Sent: Friday, December 4, 2020 7:48:39 PM
To: Arnold Noronha <arnold@tdrhq.com>
Cc: lisp-hug@lispworks.com <lisp-hug@lispworks.com>
Subject: Re: Building deliverables using CFFI libraries
 
Hi again,

Thanks for the responses, it's been helpful to look through all the example code.  Also, thanks Arnold for pointing out that CFFI actually does use fli under the covers, it was helpful to clone the CFFI repo and look through how that actually works.

I think I'm starting to get close...  in my Delivery script I'm using:

(cffi:close-foreign-library 'FREETYPE2::FREETYPE2)

and I can see that it's returning T.

and in application start defun I'm using:

(pushnew
(make-pathname :directory
(append (butlast (pathname-directory (lw:lisp-image-name)))
'("Resources" "libs")))
cffi:*foreign-library-directories* :test #'equal)
(cffi:use-foreign-library freetype2::freetype2)

Which appears to be reloading it, although I reliably get a handful of different loading errors. (some of them below) The path in these errors IS the correct path to the library file though...

-Steve

sgithens load-foreign-library FREETYPE2 /Users/sgithens/code/boxer-sunrise2/data/boxersunrise.app/Contents/Resources/libs/libfreetype.6.dylib 


Error: Segmentation violation(11) [code 0] at 1006BF128

        Foreign code offset #x38 from symbol "FT_Stream_New"

        module "/Users/sgithens/code/boxer-sunrise2/data/boxersunrise.app/Contents/Resources/libs/libfreetype.6.dylib" [ #x1006B8000 ]

rax        1EC00 ; rbx    108164810 ; rcx 600000008600 ; rdx 70000101FB58

rsp 70000101FAE0 ; rbp 70000101FB10 ; rdi    1080F5570 ; rsi           50

r8             1 ; r9    40A03B6D3B ; r10   4040070C6B ; r11    1006C00A0

r12 70000101FBB0 ; r13 600000008680 ; r14 70000101FB58 ; r15    1080F5570

  1 (abort) Quit process.


or

sgithens load-foreign-library FREETYPE2 /Users/sgithens/code/boxer-sunrise2/data/boxersunrise.app/Contents/Resources/libs/libfreetype.6.dylib 


Error: FreeType error: INVALID-LIBRARY-HANDLE

  1 (abort) Quit process.




On Fri, Dec 4, 2020, at 2:11 PM, Arnold Noronha wrote:

On Fri, Dec 04, 2020 at 01:02:50PM -0800, Steven Githens wrote:
> Hi all,
>
> This is a convoluted question, but to start, I'm wondering if folks have successfully used the lisp works delivery mechanism incorporating libraries that use the CFFI module (not the builtin ffi module that is part of lispworks).

Since CFFI uses FLI under the hood you should still be able to use FLI
functions.

I used fli:disconnect-module just before delivery. (I am using my own
library though, so not 100% sure it's easy to do this from an external
library loaded with CFFI). Then use fli:get-embedded-module in your
app, and fli:install-embedded-module in your init function in the
delivered app.

--Arnold



Re: Building deliverables using CFFI libraries

Well... I don’t love the implementation of cl-freetype2/src/ffi/ft2-lib.lisp.


--

Colin J.E. Lupton
CEO, Founder, Principal Quantum Metamachinist
Black Brane Systems, Inc.
https://blackbrane.com/

phone: +1 (833) 227-2630 x700
fax: +1 (833) 227-2630
email: colin@blackbrane.com

Sent from Outlook for iOS

From: owner-lisp-hug@lispworks.com <owner-lisp-hug@lispworks.com> on behalf of Colin J.E. Lupton <colin@blackbrane.com>
Sent: Saturday, December 5, 2020 12:22:17 AM
To: Steven Githens <steve@githens.org>; lisp-hug@lispworks.com <lisp-hug@lispworks.com>
Subject: Re: Building deliverables using CFFI libraries
 
It was no trouble. To be honest, that was off the top of my head, other then double-checking section references.

I figured the 32 vs 64-bit issue was unlikely or impossible on any recent Mac, it was only there for the just-in-case.

In-memory delivery is a great feature. But that’s really interesting that it works delivered in memory, but not reloaded.

That last part isn’t unusual. Memory architectures are typically hierarchical and cached, and Lisp images operate under the closed-world assumption, so the effect is even more pronounced as a result. Unloading the module isn’t the actual action of wiping the addressed range of blocks, it’s tagging it for collection at the next run of the garbage collector.

Anything else left from the list?

I’ll check the transcript for any insights, as well.


--

Colin J.E. Lupton
CEO, Founder, Principal Quantum Metamachinist
Black Brane Systems, Inc.
https://blackbrane.com/

phone: +1 (833) 227-2630 x700
fax: +1 (833) 227-2630
email: colin@blackbrane.com

Sent from Outlook for iOS

From: owner-lisp-hug@lispworks.com <owner-lisp-hug@lispworks.com> on behalf of Steven Githens <steve@githens.org>
Sent: Friday, December 4, 2020 11:00:22 PM
To: lisp-hug@lispworks.com <lisp-hug@lispworks.com>
Subject: Re: Building deliverables using CFFI libraries
 
Hi Colin,

Thanks for this meticulously crafted set of references.  I'm on MacOS Catalina with Lispworks 7.1.2, so everything should be 64-bit since it doesn't support 32-bit apps.  I actually went ahead and hacked up cl-freetype2 quick to use embedded-modules since that would be great, but pretty much get the same errors.

I did try out the deliver option ":in-memory-delivery t" and of course it works fine, so it's definitely some particular issue with loading the lisp image back up.  

Also randomly, I just did some small testing in the REPL with unloading the dylib, and got results that surprised me, in that I was still able to use the library after unloading it... I don't think it's being aggressively reloaded, because when I unload it again I get `nil` which would be expected...

I have a transcript of it here:  https://gist.github.com/sgithens/1e6c68bb985e2cc31af0e8fcd19422a6

~Steve

On Fri, Dec 4, 2020, at 6:14 PM, Colin J.E. Lupton wrote:
I came upon a similar issue, and was able to find the solution in the LispWorks documentation.

You can work your way through the following list of solutions from top to bottom:

- LW 29.8, external libraries used with 64-bit LispWorks must be 64-bit libraries, with 32-bit LispWorks must be 32-bit libraries
- DV 4.4.5, be certain the calls to load the foreign libraries with CFFI, register-module (or the embedded-module interface mentioned below) are made within function bodies and not top-level. This ensures the dynamic library is loaded in full at runtime, when the wrapper function is called, and not during compilation or delivery.
- DV 10.6, there are some useful notes here on how the FLI converts between foreign and Lisp objects, and parts of the delivery process that might clobber your FLI; mostly missing templates, occasionally memory errors.
- FLI 5.5, how to correctly load and access both C and C++ dynamic libraries; there’s some extra work with C++. Haven’t used FREETYPE2 myself, so not immediately clear on its implementation.
- FLI 5.6, covers embedding dynamically-loaded foreign libraries inside the Lisp image, instead of relying separate libraries loaded at runtime. The embedded-module interface handles a lot of extra complexity, if it can be used with CFFI. Maybe try this on a new branch of your source control some other time.

That should cover all of the possible cases for the errors you’re getting. If not, see LW 11.4 for a review of memory management in 64-bit LispWorks, or LW 11.3 for 32-bit.

If you’re interested in why you’re getting those specific memory error patterns, LW 11.6 has a few notes on reducing image size and garbage collection of foreign-objects that explains most of it. For example, clean-down is called automatically before delivery, IIRC.


--

Colin J.E. Lupton
CEO, Founder, Principal Quantum Metamachinist
Black Brane Systems, Inc.
https://blackbrane.com/


phone: +1 (833) 227-2630 x700
fax: +1 (833) 227-2630
email: colin@blackbrane.com


Sent from Outlook for iOS


From: owner-lisp-hug@lispworks.com <owner-lisp-hug@lispworks.com> on behalf of Steven Githens <steve@githens.org>
Sent: Friday, December 4, 2020 7:48:39 PM
To: Arnold Noronha <arnold@tdrhq.com>
Cc: lisp-hug@lispworks.com <lisp-hug@lispworks.com>
Subject: Re: Building deliverables using CFFI libraries
 
Hi again,

Thanks for the responses, it's been helpful to look through all the example code.  Also, thanks Arnold for pointing out that CFFI actually does use fli under the covers, it was helpful to clone the CFFI repo and look through how that actually works.

I think I'm starting to get close...  in my Delivery script I'm using:

(cffi:close-foreign-library 'FREETYPE2::FREETYPE2)

and I can see that it's returning T.

and in application start defun I'm using:

(pushnew
(make-pathname :directory
(append (butlast (pathname-directory (lw:lisp-image-name)))
'("Resources" "libs")))
cffi:*foreign-library-directories* :test #'equal)
(cffi:use-foreign-library freetype2::freetype2)

Which appears to be reloading it, although I reliably get a handful of different loading errors. (some of them below) The path in these errors IS the correct path to the library file though...

-Steve

sgithens load-foreign-library FREETYPE2 /Users/sgithens/code/boxer-sunrise2/data/boxersunrise.app/Contents/Resources/libs/libfreetype.6.dylib 


Error: Segmentation violation(11) [code 0] at 1006BF128

        Foreign code offset #x38 from symbol "FT_Stream_New"

        module "/Users/sgithens/code/boxer-sunrise2/data/boxersunrise.app/Contents/Resources/libs/libfreetype.6.dylib" [ #x1006B8000 ]

rax        1EC00 ; rbx    108164810 ; rcx 600000008600 ; rdx 70000101FB58

rsp 70000101FAE0 ; rbp 70000101FB10 ; rdi    1080F5570 ; rsi           50

r8             1 ; r9    40A03B6D3B ; r10   4040070C6B ; r11    1006C00A0

r12 70000101FBB0 ; r13 600000008680 ; r14 70000101FB58 ; r15    1080F5570

  1 (abort) Quit process.


or

sgithens load-foreign-library FREETYPE2 /Users/sgithens/code/boxer-sunrise2/data/boxersunrise.app/Contents/Resources/libs/libfreetype.6.dylib 


Error: FreeType error: INVALID-LIBRARY-HANDLE

  1 (abort) Quit process.




On Fri, Dec 4, 2020, at 2:11 PM, Arnold Noronha wrote:

On Fri, Dec 04, 2020 at 01:02:50PM -0800, Steven Githens wrote:
> Hi all,
>
> This is a convoluted question, but to start, I'm wondering if folks have successfully used the lisp works delivery mechanism incorporating libraries that use the CFFI module (not the builtin ffi module that is part of lispworks).

Since CFFI uses FLI under the hood you should still be able to use FLI
functions.

I used fli:disconnect-module just before delivery. (I am using my own
library though, so not 100% sure it's easy to do this from an external
library loaded with CFFI). Then use fli:get-embedded-module in your
app, and fli:install-embedded-module in your init function in the
delivered app.

--Arnold



Re: Building deliverables using CFFI libraries

MacOS doesn't support unloading unfortunately.  There is also a problem if you
close a module that has explicit references (such as the :library argument to
cffi:defcfun).

The recommended approach is to not load the library before creating the
deliverable (and then load it on startup as you mentioend below).

-- 
Martin Simmons
LispWorks Ltd
http://www.lispworks.com/



>>>>> On Fri, 04 Dec 2020 20:00:22 -0800, Steven Githens said:
> 
> Hi Colin,
> 
> Thanks for this meticulously crafted set of references.  I'm on MacOS Catalina with Lispworks 7.1.2, so everything should be 64-bit since it doesn't support 32-bit apps.  I actually went ahead and hacked up cl-freetype2 quick to use embedded-modules since that would be great, but pretty much get the same errors.
> 
> I did try out the deliver option ":in-memory-delivery t" and of course it works fine, so it's definitely some particular issue with loading the lisp image back up.  
> 
> Also randomly, I just did some small testing in the REPL with unloading the dylib, and got results that surprised me, in that I was still able to use the library after unloading it... I don't think it's being aggressively reloaded, because when I unload it again I get `nil` which would be expected...
> 
> I have a transcript of it here:  https://gist.github.com/sgithens/1e6c68bb985e2cc31af0e8fcd19422a6
> 
> ~Steve
> 
> On Fri, Dec 4, 2020, at 6:14 PM, Colin J.E. Lupton wrote:
> > I came upon a similar issue, and was able to find the solution in the LispWorks documentation.
> > 
> > You can work your way through the following list of solutions from top to bottom:
> > 
> > - LW 29.8, external libraries used with 64-bit LispWorks must be 64-bit libraries, with 32-bit LispWorks must be 32-bit libraries
> > - DV 4.4.5, be certain the calls to load the foreign libraries with CFFI, register-module (or the embedded-module interface mentioned below) are made within function bodies and not top-level. This ensures the dynamic library is loaded in full at runtime, when the wrapper function is called, and not during compilation or delivery.
> > - DV 10.6, there are some useful notes here on how the FLI converts between foreign and Lisp objects, and parts of the delivery process that might clobber your FLI; mostly missing templates, occasionally memory errors.
> > - FLI 5.5, how to correctly load and access both C and C++ dynamic libraries; there’s some extra work with C++. Haven’t used FREETYPE2 myself, so not immediately clear on its implementation.
> > - FLI 5.6, covers embedding dynamically-loaded foreign libraries inside the Lisp image, instead of relying separate libraries loaded at runtime. The embedded-module interface handles a lot of extra complexity, if it can be used with CFFI. Maybe try this on a new branch of your source control some other time.
> > 
> > That should cover all of the possible cases for the errors you’re getting. If not, see LW 11.4 for a review of memory management in 64-bit LispWorks, or LW 11.3 for 32-bit.
> > 
> > If you’re interested in why you’re getting those specific memory error patterns, LW 11.6 has a few notes on reducing image size and garbage collection of foreign-objects that explains most of it. For example, clean-down is called automatically before delivery, IIRC.
> > 
> > 
> > --
> > 
> > Colin J.E. Lupton
> > *CEO, Founder, Principal Quantum Metamachinist*
> > *Black Brane Systems, Inc.*
> > https://blackbrane.com/
> > 
> > phone: +1 (833) 227-2630 x700
> > fax: +1 (833) 227-2630
> > email: colin@blackbrane.com
> > 
> > Sent from Outlook <https://aka.ms/qtex0l> for iOS
> > 
> > *From:* owner-lisp-hug@lispworks.com <owner-lisp-hug@lispworks.com> on behalf of Steven Githens <steve@githens.org>
> > *Sent:* Friday, December 4, 2020 7:48:39 PM
> > *To:* Arnold Noronha <arnold@tdrhq.com>
> > *Cc:* lisp-hug@lispworks.com <lisp-hug@lispworks.com>
> > *Subject:* Re: Building deliverables using CFFI libraries 
> >  
> > Hi again,
> > 
> > Thanks for the responses, it's been helpful to look through all the example code.  Also, thanks Arnold for pointing out that CFFI actually does use fli under the covers, it was helpful to clone the CFFI repo and look through how that actually works.
> > 
> > I think I'm starting to get close...  in my Delivery script I'm using:
> > 
> > (cffi:close-foreign-library 'FREETYPE2::FREETYPE2)
> > 
> > and I can see that it's returning T.
> > 
> > and in application start defun I'm using:
> > 
> > (pushnew
> > (make-pathname :directory
> > (append (butlast (pathname-directory (lw:lisp-image-name)))
> > '("Resources" "libs")))
> > cffi:*foreign-library-directories* :test #'equal)
> > (cffi:use-foreign-library freetype2::freetype2)
> > 
> > Which appears to be reloading it, although I reliably get a handful of different loading errors. (some of them below) The path in these errors IS the correct path to the library file though...
> > 
> > -Steve
> > 
> > sgithens load-foreign-library FREETYPE2 /Users/sgithens/code/boxer-sunrise2/data/boxersunrise.app/Contents/Resources/libs/libfreetype.6.dylib 
> > 
> 
> > Error: Segmentation violation(11) [code 0] at 1006BF128
> 
> >         Foreign code offset #x38 from symbol "FT_Stream_New"
> 
> >         module "/Users/sgithens/code/boxer-sunrise2/data/boxersunrise.app/Contents/Resources/libs/libfreetype.6.dylib" [ #x1006B8000 ]
> 
> > rax        1EC00 ; rbx    108164810 ; rcx 600000008600 ; rdx 70000101FB58
> 
> > rsp 70000101FAE0 ; rbp 70000101FB10 ; rdi    1080F5570 ; rsi           50
> 
> > r8             1 ; r9    40A03B6D3B ; r10   4040070C6B ; r11    1006C00A0
> 
> > r12 70000101FBB0 ; r13 600000008680 ; r14 70000101FB58 ; r15    1080F5570
> 
> >   1 (abort) Quit process.
> 
> > 
> > or 
> > 
> > sgithens load-foreign-library FREETYPE2 /Users/sgithens/code/boxer-sunrise2/data/boxersunrise.app/Contents/Resources/libs/libfreetype.6.dylib 
> > 
> 
> > Error: FreeType error: INVALID-LIBRARY-HANDLE
> 
> >   1 (abort) Quit process.
> 
> > 
> > 
> > 
> > On Fri, Dec 4, 2020, at 2:11 PM, Arnold Noronha wrote:
> >> 
> >> On Fri, Dec 04, 2020 at 01:02:50PM -0800, Steven Githens wrote:
> >> > Hi all,
> >> >
> >> > This is a convoluted question, but to start, I'm wondering if folks have successfully used the lisp works delivery mechanism incorporating libraries that use the CFFI module (not the builtin ffi module that is part of lispworks).
> >> 
> >> Since CFFI uses FLI under the hood you should still be able to use FLI
> >> functions.
> >> 
> >> I used fli:disconnect-module just before delivery. (I am using my own
> >> library though, so not 100% sure it's easy to do this from an external
> >> library loaded with CFFI). Then use fli:get-embedded-module in your
> >> app, and fli:install-embedded-module in your init function in the
> >> delivered app.
> >> 
> >> --Arnold
> >> 
> > 
> 

_______________________________________________
Lisp Hug - the mailing list for LispWorks users
lisp-hug@lispworks.com
http://www.lispworks.com/support/lisp-hug.html

Re: Building deliverables using CFFI libraries

Aha, I think this is helpful.  So, if I'm correct, the cffi and groveling that's used requires the compiling procedures which are gone after delivering, so I think I need to:

- Separately asdf:compile-system :cl-freetype2
- Somehow add all the .64xfasl files to my projects directory/cache (as well as the actual *.dylib libraries used when generating it)
- lispworks -build my-delivery.lisp, making sure things are factored such that it doesn't load cl-freetype2 at all during this stage
- The delivered application can load cl-freetype2 during it's startup methods.

Cheers,
Steve


On Mon, Dec 7, 2020, at 11:19 AM, Martin Simmons wrote:
MacOS doesn't support unloading unfortunately.  There is also a problem if you
close a module that has explicit references (such as the :library argument to
cffi:defcfun).

The recommended approach is to not load the library before creating the
deliverable (and then load it on startup as you mentioend below).

-- 
Martin Simmons
LispWorks Ltd
http://www.lispworks.com/



>>>>> On Fri, 04 Dec 2020 20:00:22 -0800, Steven Githens said:
> 
> Hi Colin,
> 
> Thanks for this meticulously crafted set of references.  I'm on MacOS Catalina with Lispworks 7.1.2, so everything should be 64-bit since it doesn't support 32-bit apps.  I actually went ahead and hacked up cl-freetype2 quick to use embedded-modules since that would be great, but pretty much get the same errors.
> 
> I did try out the deliver option ":in-memory-delivery t" and of course it works fine, so it's definitely some particular issue with loading the lisp image back up.  
> 
> Also randomly, I just did some small testing in the REPL with unloading the dylib, and got results that surprised me, in that I was still able to use the library after unloading it... I don't think it's being aggressively reloaded, because when I unload it again I get `nil` which would be expected...
> 
> I have a transcript of it here:  https://gist.github.com/sgithens/1e6c68bb985e2cc31af0e8fcd19422a6
> 
> ~Steve
> 
> On Fri, Dec 4, 2020, at 6:14 PM, Colin J.E. Lupton wrote:
> > I came upon a similar issue, and was able to find the solution in the LispWorks documentation.
> > 
> > You can work your way through the following list of solutions from top to bottom:
> > 
> > - LW 29.8, external libraries used with 64-bit LispWorks must be 64-bit libraries, with 32-bit LispWorks must be 32-bit libraries
> > - DV 4.4.5, be certain the calls to load the foreign libraries with CFFI, register-module (or the embedded-module interface mentioned below) are made within function bodies and not top-level. This ensures the dynamic library is loaded in full at runtime, when the wrapper function is called, and not during compilation or delivery.
> > - DV 10.6, there are some useful notes here on how the FLI converts between foreign and Lisp objects, and parts of the delivery process that might clobber your FLI; mostly missing templates, occasionally memory errors.
> > - FLI 5.5, how to correctly load and access both C and C++ dynamic libraries; there’s some extra work with C++. Haven’t used FREETYPE2 myself, so not immediately clear on its implementation.
> > - FLI 5.6, covers embedding dynamically-loaded foreign libraries inside the Lisp image, instead of relying separate libraries loaded at runtime. The embedded-module interface handles a lot of extra complexity, if it can be used with CFFI. Maybe try this on a new branch of your source control some other time.
> > 
> > That should cover all of the possible cases for the errors you’re getting. If not, see LW 11..4 for a review of memory management in 64-bit LispWorks, or LW 11.3 for 32-bit.
> > 
> > If you’re interested in why you’re getting those specific memory error patterns, LW 11.6 has a few notes on reducing image size and garbage collection of foreign-objects that explains most of it. For example, clean-down is called automatically before delivery, IIRC.
> > 
> > 
> > --
> > 
> > Colin J.E. Lupton
> > *CEO, Founder, Principal Quantum Metamachinist*
> > *Black Brane Systems, Inc.*
> > https://blackbrane.com/
> > 
> > phone: +1 (833) 227-2630 x700
> > fax: +1 (833) 227-2630
> > email: colin@blackbrane.com
> > 
> > Sent from Outlook <https://aka.ms/qtex0l> for iOS
> > 
> > *From:* owner-lisp-hug@lispworks.com <owner-lisp-hug@lispworks.com> on behalf of Steven Githens <steve@githens.org>
> > *Sent:* Friday, December 4, 2020 7:48:39 PM
> > *To:* Arnold Noronha <arnold@tdrhq.com>
> > *Cc:* lisp-hug@lispworks.com <lisp-hug@lispworks.com>
> > *Subject:* Re: Building deliverables using CFFI libraries 
> >  
> > Hi again,
> > 
> > Thanks for the responses, it's been helpful to look through all the example code.  Also, thanks Arnold for pointing out that CFFI actually does use fli under the covers, it was helpful to clone the CFFI repo and look through how that actually works.
> > 
> > I think I'm starting to get close...  in my Delivery script I'm using:
> > 
> > (cffi:close-foreign-library 'FREETYPE2::FREETYPE2)
> > 
> > and I can see that it's returning T.
> > 
> > and in application start defun I'm using:
> > 
> > (pushnew
> > (make-pathname :directory
> > (append (butlast (pathname-directory (lw:lisp-image-name)))
> > '("Resources" "libs")))
> > cffi:*foreign-library-directories* :test #'equal)
> > (cffi:use-foreign-library freetype2::freetype2)
> > 
> > Which appears to be reloading it, although I reliably get a handful of different loading errors. (some of them below) The path in these errors IS the correct path to the library file though...
> > 
> > -Steve
> > 
> > sgithens load-foreign-library FREETYPE2 /Users/sgithens/code/boxer-sunrise2/data/boxersunrise.app/Contents/Resources/libs/libfreetype.6.dylib 
> > 
> 
> > Error: Segmentation violation(11) [code 0] at 1006BF128
> 
> >         Foreign code offset #x38 from symbol "FT_Stream_New"
> 
> >         module "/Users/sgithens/code/boxer-sunrise2/data/boxersunrise.app/Contents/Resources/libs/libfreetype.6.dylib" [ #x1006B8000 ]
> 
> > rax        1EC00 ; rbx    108164810 ; rcx 600000008600 ; rdx 70000101FB58
> 
> > rsp 70000101FAE0 ; rbp 70000101FB10 ; rdi    1080F5570 ; rsi           50
> 
> > r8             1 ; r9    40A03B6D3B ; r10   4040070C6B ; r11    1006C00A0
> 
> > r12 70000101FBB0 ; r13 600000008680 ; r14 70000101FB58 ; r15    1080F5570
> 
> >   1 (abort) Quit process.
> 
> > 
> > or 
> > 
> > sgithens load-foreign-library FREETYPE2 /Users/sgithens/code/boxer-sunrise2/data/boxersunrise.app/Contents/Resources/libs/libfreetype.6.dylib 
> > 
> 
> > Error: FreeType error: INVALID-LIBRARY-HANDLE
> 
> >   1 (abort) Quit process.
> 
> > 
> > 
> > 
> > On Fri, Dec 4, 2020, at 2:11 PM, Arnold Noronha wrote:
> >> 
> >> On Fri, Dec 04, 2020 at 01:02:50PM -0800, Steven Githens wrote:
> >> > Hi all,
> >> >
> >> > This is a convoluted question, but to start, I'm wondering if folks have successfully used the lisp works delivery mechanism incorporating libraries that use the CFFI module (not the builtin ffi module that is part of lispworks).
> >> 
> >> Since CFFI uses FLI under the hood you should still be able to use FLI
> >> functions.
> >> 
> >> I used fli:disconnect-module just before delivery. (I am using my own
> >> library though, so not 100% sure it's easy to do this from an external
> >> library loaded with CFFI). Then use fli:get-embedded-module in your
> >> app, and fli:install-embedded-module in your init function in the
> >> delivered app.
> >> 
> >> --Arnold
> >> 
> > 
> 

_______________________________________________
Lisp Hug - the mailing list for LispWorks users
lisp-hug@lispworks.com
http://www.lispworks.com/support/lisp-hug.html


Re: Building deliverables using CFFI libraries

Ok, so I think I do have this working, although it's a mess, but I can at least work backwards now.

I got the pile of compiled 64xfasl files from the cl-freetype2 cache dir and then made sure the original project wasn't anywhere in quicklisp still.  However, I found that even using asdf:load-system with cl-freetype2 still triggered something in the cffi groveller that wanted to use compile-file, so I ended up meticulously adding a list of (load "x/y/zed.64xfasl") statements for everything defined in cl-freetype2.asd... and now it seems to work (and will hopefully continue to after cleaning up everything)!!  So thanks for all input everyone.   I'll post a link to the cleaned up source in case anyone is curious.

Also, I imagine there must be some sort of option to load the pre-compiled asdf components without exciting the groveller and making it want to grovel again, which hopefully I'll discover at some point. ( I imagine this must be a prerequisite for delivering any lispworks project that uses a module driven by cffi/grovel...)

Cheers,
Steve

On Mon, Dec 7, 2020, at 12:16 PM, Steven Githens wrote:
Aha, I think this is helpful.  So, if I'm correct, the cffi and groveling that's used requires the compiling procedures which are gone after delivering, so I think I need to:

- Separately asdf:compile-system :cl-freetype2
- Somehow add all the .64xfasl files to my projects directory/cache (as well as the actual *.dylib libraries used when generating it)
- lispworks -build my-delivery.lisp, making sure things are factored such that it doesn't load cl-freetype2 at all during this stage
- The delivered application can load cl-freetype2 during it's startup methods.

Cheers,
Steve


On Mon, Dec 7, 2020, at 11:19 AM, Martin Simmons wrote:
MacOS doesn't support unloading unfortunately.  There is also a problem if you
close a module that has explicit references (such as the :library argument to
cffi:defcfun).

The recommended approach is to not load the library before creating the
deliverable (and then load it on startup as you mentioend below).

-- 
Martin Simmons
LispWorks Ltd
http://www.lispworks.com/



>>>>> On Fri, 04 Dec 2020 20:00:22 -0800, Steven Githens said:
> 
> Hi Colin,
> 
> Thanks for this meticulously crafted set of references.  I'm on MacOS Catalina with Lispworks 7.1.2, so everything should be 64-bit since it doesn't support 32-bit apps.  I actually went ahead and hacked up cl-freetype2 quick to use embedded-modules since that would be great, but pretty much get the same errors.
> 
> I did try out the deliver option ":in-memory-delivery t" and of course it works fine, so it's definitely some particular issue with loading the lisp image back up.  
> 
> Also randomly, I just did some small testing in the REPL with unloading the dylib, and got results that surprised me, in that I was still able to use the library after unloading it... I don't think it's being aggressively reloaded, because when I unload it again I get `nil` which would be expected...
> 
> I have a transcript of it here:  https://gist.github.com/sgithens/1e6c68bb985e2cc31af0e8fcd19422a6
> 
> ~Steve
> 
> On Fri, Dec 4, 2020, at 6:14 PM, Colin J.E. Lupton wrote:
> > I came upon a similar issue, and was able to find the solution in the LispWorks documentation.
> > 
> > You can work your way through the following list of solutions from top to bottom:
> > 
> > - LW 29.8, external libraries used with 64-bit LispWorks must be 64-bit libraries, with 32-bit LispWorks must be 32-bit libraries
> > - DV 4.4.5, be certain the calls to load the foreign libraries with CFFI, register-module (or the embedded-module interface mentioned below) are made within function bodies and not top-level. This ensures the dynamic library is loaded in full at runtime, when the wrapper function is called, and not during compilation or delivery.
> > - DV 10.6, there are some useful notes here on how the FLI converts between foreign and Lisp objects, and parts of the delivery process that might clobber your FLI; mostly missing templates, occasionally memory errors.
> > - FLI 5.5, how to correctly load and access both C and C++ dynamic libraries; there’s some extra work with C++. Haven’t used FREETYPE2 myself, so not immediately clear on its implementation.
> > - FLI 5.6, covers embedding dynamically-loaded foreign libraries inside the Lisp image, instead of relying separate libraries loaded at runtime. The embedded-module interface handles a lot of extra complexity, if it can be used with CFFI. Maybe try this on a new branch of your source control some other time.
> > 
> > That should cover all of the possible cases for the errors you’re getting. If not, see LW 11.4 for a review of memory management in 64-bit LispWorks, or LW 11.3 for 32-bit.
> > 
> > If you’re interested in why you’re getting those specific memory error patterns, LW 11.6 has a few notes on reducing image size and garbage collection of foreign-objects that explains most of it. For example, clean-down is called automatically before delivery, IIRC.
> > 
> > 
> > --
> > 
> > Colin J.E. Lupton
> > *CEO, Founder, Principal Quantum Metamachinist*
> > *Black Brane Systems, Inc.*
> > https://blackbrane.com/
> > 
> > phone: +1 (833) 227-2630 x700
> > fax: +1 (833) 227-2630
> > email: colin@blackbrane.com
> > 
> > Sent from Outlook <https://aka.ms/qtex0l> for iOS
> > 
> > *From:* owner-lisp-hug@lispworks.com <owner-lisp-hug@lispworks.com> on behalf of Steven Githens <steve@githens.org>
> > *Sent:* Friday, December 4, 2020 7:48:39 PM
> > *To:* Arnold Noronha <arnold@tdrhq.com>
> > *Cc:* lisp-hug@lispworks.com <lisp-hug@lispworks.com>
> > *Subject:* Re: Building deliverables using CFFI libraries 
> >  
> > Hi again,
> > 
> > Thanks for the responses, it's been helpful to look through all the example code.  Also, thanks Arnold for pointing out that CFFI actually does use fli under the covers, it was helpful to clone the CFFI repo and look through how that actually works.
> > 
> > I think I'm starting to get close...  in my Delivery script I'm using:
> > 
> > (cffi:close-foreign-library 'FREETYPE2::FREETYPE2)
> > 
> > and I can see that it's returning T.
> > 
> > and in application start defun I'm using:
> > 
> > (pushnew
> > (make-pathname :directory
> > (append (butlast (pathname-directory (lw:lisp-image-name)))
> > '("Resources" "libs")))
> > cffi:*foreign-library-directories* :test #'equal)
> > (cffi:use-foreign-library freetype2::freetype2)
> > 
> > Which appears to be reloading it, although I reliably get a handful of different loading errors. (some of them below) The path in these errors IS the correct path to the library file though...
> > 
> > -Steve
> > 
> > sgithens load-foreign-library FREETYPE2 /Users/sgithens/code/boxer-sunrise2/data/boxersunrise.app/Contents/Resources/libs/libfreetype.6.dylib 
> > 
> 
> > Error: Segmentation violation(11) [code 0] at 1006BF128
> 
> >         Foreign code offset #x38 from symbol "FT_Stream_New"
> 
> >         module "/Users/sgithens/code/boxer-sunrise2/data/boxersunrise.app/Contents/Resources/libs/libfreetype.6.dylib" [ #x1006B8000 ]
> 
> > rax        1EC00 ; rbx    108164810 ; rcx 600000008600 ; rdx 70000101FB58
> 
> > rsp 70000101FAE0 ; rbp 70000101FB10 ; rdi    1080F5570 ; rsi           50
> 
> > r8             1 ; r9    40A03B6D3B ; r10   4040070C6B ; r11    1006C00A0
> 
> > r12 70000101FBB0 ; r13 600000008680 ; r14 70000101FB58 ; r15    1080F5570
> 
> >   1 (abort) Quit process.
> 
> > 
> > or 
> > 
> > sgithens load-foreign-library FREETYPE2 /Users/sgithens/code/boxer-sunrise2/data/boxersunrise.app/Contents/Resources/libs/libfreetype.6.dylib 
> > 
> 
> > Error: FreeType error: INVALID-LIBRARY-HANDLE
> 
> >   1 (abort) Quit process.
> 
> > 
> > 
> > 
> > On Fri, Dec 4, 2020, at 2:11 PM, Arnold Noronha wrote:
> >> 
> >> On Fri, Dec 04, 2020 at 01:02:50PM -0800, Steven Githens wrote:
> >> > Hi all,
> >> >
> >> > This is a convoluted question, but to start, I'm wondering if folks have successfully used the lisp works delivery mechanism incorporating libraries that use the CFFI module (not the builtin ffi module that is part of lispworks).
> >> 
> >> Since CFFI uses FLI under the hood you should still be able to use FLI
> >> functions.
> >> 
> >> I used fli:disconnect-module just before delivery. (I am using my own
> >> library though, so not 100% sure it's easy to do this from an external
> >> library loaded with CFFI). Then use fli:get-embedded-module in your
> >> app, and fli:install-embedded-module in your init function in the
> >> delivered app.
> >> 
> >> --Arnold
> >> 
> > 
> 

_______________________________________________
Lisp Hug - the mailing list for LispWorks users
lisp-hug@lispworks.com
http://www.lispworks.com/support/lisp-hug.html



Re: Building deliverables using CFFI libraries

That will probably work, but is not the best approach because it means that
you have to keep the fasl loader and symbols in the deliverable.

I think the best approach is to find the code that is loading the library when
the fasls are loaded (e.g. trace cffi-sys:%load-foreign-library with break).
Then change that code to use cffi:define-foreign-library when the fasls are
loaded and call cffi:load-foreign-library at startup.

-- 
Martin Simmons
LispWorks Ltd
http://www.lispworks.com/



>>>>> On Mon, 07 Dec 2020 18:24:21 -0800, Steven Githens said:
> 
> Ok, so I think I do have this working, although it's a mess, but I can at least work backwards now.
> 
> I got the pile of compiled 64xfasl files from the cl-freetype2 cache dir and then made sure the original project wasn't anywhere in quicklisp still.  However, I found that even using asdf:load-system with cl-freetype2 still triggered something in the cffi groveller that wanted to use compile-file, so I ended up meticulously adding a list of (load "x/y/zed.64xfasl") statements for everything defined in cl-freetype2.asd... and now it seems to work (and will hopefully continue to after cleaning up everything)!!  So thanks for all input everyone.   I'll post a link to the cleaned up source in case anyone is curious.
> 
> Also, I imagine there must be some sort of option to load the pre-compiled asdf components without exciting the groveller and making it want to grovel again, which hopefully I'll discover at some point. ( I imagine this must be a prerequisite for delivering any lispworks project that uses a module driven by cffi/grovel...)
> 
> Cheers,
> Steve
> 
> On Mon, Dec 7, 2020, at 12:16 PM, Steven Githens wrote:
> > Aha, I think this is helpful.  So, if I'm correct, the cffi and groveling that's used requires the compiling procedures which are gone after delivering, so I think I need to:
> > 
> > - Separately asdf:compile-system :cl-freetype2
> > - Somehow add all the .64xfasl files to my projects directory/cache (as well as the actual *.dylib libraries used when generating it)
> > - lispworks -build my-delivery.lisp, making sure things are factored such that it doesn't load cl-freetype2 at all during this stage
> > - The delivered application can load cl-freetype2 during it's startup methods.
> > 
> > Cheers,
> > Steve
> > 
> > 
> > On Mon, Dec 7, 2020, at 11:19 AM, Martin Simmons wrote:
> >> MacOS doesn't support unloading unfortunately.  There is also a problem if you
> >> close a module that has explicit references (such as the :library argument to
> >> cffi:defcfun).
> >> 
> >> The recommended approach is to not load the library before creating the
> >> deliverable (and then load it on startup as you mentioend below).
> >> 
> >> -- 
> >> Martin Simmons
> >> LispWorks Ltd
> >> http://www.lispworks.com/
> >> 
> >> 
> >> 
> >> >>>>> On Fri, 04 Dec 2020 20:00:22 -0800, Steven Githens said:
> >> > 
> >> > Hi Colin,
> >> > 
> >> > Thanks for this meticulously crafted set of references.  I'm on MacOS Catalina with Lispworks 7.1.2, so everything should be 64-bit since it doesn't support 32-bit apps.  I actually went ahead and hacked up cl-freetype2 quick to use embedded-modules since that would be great, but pretty much get the same errors.
> >> > 
> >> > I did try out the deliver option ":in-memory-delivery t" and of course it works fine, so it's definitely some particular issue with loading the lisp image back up.  
> >> > 
> >> > Also randomly, I just did some small testing in the REPL with unloading the dylib, and got results that surprised me, in that I was still able to use the library after unloading it... I don't think it's being aggressively reloaded, because when I unload it again I get `nil` which would be expected...
> >> > 
> >> > I have a transcript of it here:  https://gist.github.com/sgithens/1e6c68bb985e2cc31af0e8fcd19422a6
> >> > 
> >> > ~Steve
> >> > 
> >> > On Fri, Dec 4, 2020, at 6:14 PM, Colin J.E. Lupton wrote:
> >> > > I came upon a similar issue, and was able to find the solution in the LispWorks documentation.
> >> > > 
> >> > > You can work your way through the following list of solutions from top to bottom:
> >> > > 
> >> > > - LW 29.8, external libraries used with 64-bit LispWorks must be 64-bit libraries, with 32-bit LispWorks must be 32-bit libraries
> >> > > - DV 4.4.5, be certain the calls to load the foreign libraries with CFFI, register-module (or the embedded-module interface mentioned below) are made within function bodies and not top-level. This ensures the dynamic library is loaded in full at runtime, when the wrapper function is called, and not during compilation or delivery.
> >> > > - DV 10.6, there are some useful notes here on how the FLI converts between foreign and Lisp objects, and parts of the delivery process that might clobber your FLI; mostly missing templates, occasionally memory errors.
> >> > > - FLI 5.5, how to correctly load and access both C and C++ dynamic libraries; there’s some extra work with C++. Haven’t used FREETYPE2 myself, so not immediately clear on its implementation.
> >> > > - FLI 5.6, covers embedding dynamically-loaded foreign libraries inside the Lisp image, instead of relying separate libraries loaded at runtime. The embedded-module interface handles a lot of extra complexity, if it can be used with CFFI. Maybe try this on a new branch of your source control some other time.
> >> > > 
> >> > > That should cover all of the possible cases for the errors you’re getting. If not, see LW 11.4 for a review of memory management in 64-bit LispWorks, or LW 11.3 for 32-bit.
> >> > > 
> >> > > If you’re interested in why you’re getting those specific memory error patterns, LW 11.6 has a few notes on reducing image size and garbage collection of foreign-objects that explains most of it. For example, clean-down is called automatically before delivery, IIRC.
> >> > > 
> >> > > 
> >> > > --
> >> > > 
> >> > > Colin J.E. Lupton
> >> > > *CEO, Founder, Principal Quantum Metamachinist*
> >> > > *Black Brane Systems, Inc.*
> >> > > https://blackbrane.com/
> >> > > 
> >> > > phone: +1 (833) 227-2630 x700
> >> > > fax: +1 (833) 227-2630
> >> > > email: colin@blackbrane.com
> >> > > 
> >> > > Sent from Outlook <https://aka.ms/qtex0l> for iOS
> >> > > 
> >> > > *From:* owner-lisp-hug@lispworks.com <owner-lisp-hug@lispworks.com> on behalf of Steven Githens <steve@githens.org>
> >> > > *Sent:* Friday, December 4, 2020 7:48:39 PM
> >> > > *To:* Arnold Noronha <arnold@tdrhq.com>
> >> > > *Cc:* lisp-hug@lispworks.com <lisp-hug@lispworks.com>
> >> > > *Subject:* Re: Building deliverables using CFFI libraries 
> >> > >  
> >> > > Hi again,
> >> > > 
> >> > > Thanks for the responses, it's been helpful to look through all the example code.  Also, thanks Arnold for pointing out that CFFI actually does use fli under the covers, it was helpful to clone the CFFI repo and look through how that actually works.
> >> > > 
> >> > > I think I'm starting to get close...  in my Delivery script I'm using:
> >> > > 
> >> > > (cffi:close-foreign-library 'FREETYPE2::FREETYPE2)
> >> > > 
> >> > > and I can see that it's returning T.
> >> > > 
> >> > > and in application start defun I'm using:
> >> > > 
> >> > > (pushnew
> >> > > (make-pathname :directory
> >> > > (append (butlast (pathname-directory (lw:lisp-image-name)))
> >> > > '("Resources" "libs")))
> >> > > cffi:*foreign-library-directories* :test #'equal)
> >> > > (cffi:use-foreign-library freetype2::freetype2)
> >> > > 
> >> > > Which appears to be reloading it, although I reliably get a handful of different loading errors. (some of them below) The path in these errors IS the correct path to the library file though...
> >> > > 
> >> > > -Steve
> >> > > 
> >> > > sgithens load-foreign-library FREETYPE2 /Users/sgithens/code/boxer-sunrise2/data/boxersunrise.app/Contents/Resources/libs/libfreetype.6.dylib 
> >> > > 
> >> > 
> >> > > Error: Segmentation violation(11) [code 0] at 1006BF128
> >> > 
> >> > >         Foreign code offset #x38 from symbol "FT_Stream_New"
> >> > 
> >> > >         module "/Users/sgithens/code/boxer-sunrise2/data/boxersunrise.app/Contents/Resources/libs/libfreetype.6.dylib" [ #x1006B8000 ]
> >> > 
> >> > > rax        1EC00 ; rbx    108164810 ; rcx 600000008600 ; rdx 70000101FB58
> >> > 
> >> > > rsp 70000101FAE0 ; rbp 70000101FB10 ; rdi    1080F5570 ; rsi           50
> >> > 
> >> > > r8             1 ; r9    40A03B6D3B ; r10   4040070C6B ; r11    1006C00A0
> >> > 
> >> > > r12 70000101FBB0 ; r13 600000008680 ; r14 70000101FB58 ; r15    1080F5570
> >> > 
> >> > >   1 (abort) Quit process.
> >> > 
> >> > > 
> >> > > or 
> >> > > 
> >> > > sgithens load-foreign-library FREETYPE2 /Users/sgithens/code/boxer-sunrise2/data/boxersunrise.app/Contents/Resources/libs/libfreetype.6.dylib 
> >> > > 
> >> > 
> >> > > Error: FreeType error: INVALID-LIBRARY-HANDLE
> >> > 
> >> > >   1 (abort) Quit process.
> >> > 
> >> > > 
> >> > > 
> >> > > 
> >> > > On Fri, Dec 4, 2020, at 2:11 PM, Arnold Noronha wrote:
> >> > >> 
> >> > >> On Fri, Dec 04, 2020 at 01:02:50PM -0800, Steven Githens wrote:
> >> > >> > Hi all,
> >> > >> >
> >> > >> > This is a convoluted question, but to start, I'm wondering if folks have successfully used the lisp works delivery mechanism incorporating libraries that use the CFFI module (not the builtin ffi module that is part of lispworks).
> >> > >> 
> >> > >> Since CFFI uses FLI under the hood you should still be able to use FLI
> >> > >> functions.
> >> > >> 
> >> > >> I used fli:disconnect-module just before delivery. (I am using my own
> >> > >> library though, so not 100% sure it's easy to do this from an external
> >> > >> library loaded with CFFI). Then use fli:get-embedded-module in your
> >> > >> app, and fli:install-embedded-module in your init function in the
> >> > >> delivered app.
> >> > >> 
> >> > >> --Arnold
> >> > >> 
> >> > > 
> >> > 
> >> 
> >> _______________________________________________
> >> Lisp Hug - the mailing list for LispWorks users
> >> lisp-hug@lispworks.com
> >> http://www.lispworks.com/support/lisp-hug.html
> >> 
> > 
> 

_______________________________________________
Lisp Hug - the mailing list for LispWorks users
lisp-hug@lispworks.com
http://www.lispworks.com/support/lisp-hug.html

Updated at: 2020-12-10 08:28 UTC