Changes between Version 1 and Version 2 of CustomFramework


Ignore:
Timestamp:
Feb 3, 2011, 8:43:10 PM (9 years ago)
Author:
rme
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • CustomFramework

    v1 v2  
    1 The Objective-C bridge makes it very easy to use existing Cocoa classes from Lisp code, and to define classes in Lisp that interact with Objective-C code.  However, sometimes you may wish to access functionality contained in third-party Objective-C sources.  It is possible to do this using the Objective-C sources; however, there are a few steps, so I will list them here.
     1= Building Framework Interfaces =
    22
    3 1. You will want to build a framework from the Objective-C sources containing the desired functionality.  This can be done with XCode, and there are good explanations elsewhere.
     3Clozure CL comes with pre-built interfaces for several Mac OS X frameworks.  It's possible to create interfaces
     4for other frameworks, too.
    45
    5 2. To support its FFI, CCL maintains a binary database of information about classes, methods, functions, types, and variables available from foreign libraries in several ".cdb" files.  You will need to generate this information for your particular library.  In order to do this, you will need to obtain and build [wiki:BuildFFIGEN ffigen4].  Once you have done so, navigate to $CCL_DIRECTORY/darwin-x86-headers or $CCL_DIRECTORY/darwin-x86-headers64, depending.  In this directory, create a directory with the same name as the Framework you built in step 1, and inside that directory, create a directory named "C".  Inside C, you must write a shell script named "populate.sh," that invokes another shell script "h-to-ffi.sh," (which should be on your path after building and installing ffigen4) on every header in your framework.  The directories that already exist in darwin-x86-headers[64] contain examples that can be adapted to this purpose.  (Note that Apple's frameworks have one "mega header" that includes all of the others, so many (all?) of the example shell scripts only have to pass one header to h-to-ffi.sh.  This will generate a directory tree that contains (eventually) several ".ffi" files inside the directory "C."
     6== Build Framework ==
     7If the framework of interest is not a system-supplied framework, you will need
     8to build the framework from the Objective-C sources containing the desired functionality.
     9This can be done with Xcode, and there are good explanations elsewhere.
    610
    7 3. Now, the ".ffi" files must be converted to ".cdb" files.  This happens entirely within Lisp.  Just invoke the command (ccl::parse-standard-ffi-files :interface-dir), where :interface-dir is the name of the directory that you created in step 2.
     11=== Use ffigen ===
     12To support its FFI, CCL maintains a binary database of information about classes, methods, functions, types, and variables available from foreign libraries in several ".cdb" files.  You will need to generate this information for your particular library.  In order to do this, you will need to obtain and build [wiki:BuildFFIGEN ffigen4].  Once you have done so, navigate to $CCL_DIRECTORY/darwin-x86-headers or $CCL_DIRECTORY/darwin-x86-headers64, depending.  In this directory, create a directory with the same name as the Framework you built in step 1, and inside that directory, create a directory named "C".  Inside C, you must write a shell script named "populate.sh," that invokes another shell script "h-to-ffi.sh," (which should be on your path after building and installing ffigen4) on every header in your framework.  The directories that already exist in darwin-x86-headers[64] contain examples that can be adapted to this purpose.  (Note that Apple's frameworks have one "mega header" that includes all of the others, so many of the example shell scripts only have to pass one header to h-to-ffi.sh.  This will generate a directory tree that contains (eventually) several ".ffi" files inside the directory "C."
    813
    9 4. CCL maintains a list of "active interface directories".  In order to successfully (require 'cocoa), the only directories that can be active are :cocoa and :libc.  Unfortunately, the previous command adds your interface directory to this list, which will cause (require 'cocoa) to bork.  So, exit the REPL or otherwise modify the state of the Lisp image to be original and pristine.
     14=== Build interface files ===
     15Now, the ".ffi" files must be converted to ".cdb" files.  This happens entirely within Lisp. Start up the lisp and do `(require 'ffi)` and `(ccl::parse-standard-ffi-files :interface-dir)`, where :interface-dir is the name of the directory that you created in the step above.
    1016
    11 5. Now, you can (require 'cocoa), followed by an (objc:load-framework :framework :interface-dir) and use the classes from your own Objective-C framework.
     17CCL maintains a list of "active interface directories".  In order to successfully `(require 'cocoa)`, the only directories that can be active are :cocoa and :libc.  Unfortunately, the previous command adds your interface directory to this list, which will cause (require 'cocoa) to bork.  So, exit the REPL or otherwise modify the state of the Lisp image to be original and pristine.
     18
     19=== Use new interfaces ===
     20Now, you can (require 'cocoa), followed by an (objc:load-framework :framework :interface-dir) and use the classes from your own Objective-C framework.
     21
     22== Example: Accelerate.framework ==
     23As an example, here's how to build interfaces for the Accelerate framework,
     24which is an Apple-supplied framework.  This assumes that you've already
     25installed ffigen.
     26{{{
     27$ cd /usr/local/src/ccl/darwin-x86-headers64
     28$ mkdir -p accelerate/C
     29$ cd accelerate/C
     30$ cat >populate.sh
     31#!/bin/sh
     32rm -rf System Developer usr
     33SDK=/Developer/SDKs/MacOSX10.5.sdk
     34CFLAGS="-m64 -fobjc-abi-version=2 -isysroot ${SDK} -mmacosx-version-min=10.5"; export CFLAGS
     35h-to-ffi.sh ${SDK}/System/Library/Frameworks/Accelerate.framework/Headers/Accelerate.h
     36^D
     37$ sh populate.sh
     38+++ .../Accelerate.framework/Headers/Accelerate.h
     39$ ccl
     40Welcome to Clozure Common Lisp Version 1.7-dev-r14622:14636  (DarwinX8664)!
     41? (require 'parse-ffi)
     42PARSE-FFI
     43("PARSE-FFI")
     44
     45? (parse-standard-ffi-files :accelerate)
     46#P".../Accelerate.framework/Headers/Accelerate.ffi" ...
     47T
     48?
     49}}}
     50
     51Now, if you're using the Objective-C bridge already, just do (objc:load-framework :accelerate).  Otherwise, do this:
     52{{{
     53? (open-shared-library "/System/Library/Frameworks/Accelerate.framework/Accelerate")     
     54#<SHLIB /System/Library/Frameworks/Accelerate.framework/Accelerate #x3020005344CD>
     55? (use-interface-dir :accelerate)
     56#<INTERFACE-DIR :ACCELERATE #P"accelerate/" #x30200054C80D>
     57? (rletz ((x (:array :double 10)))
     58    (setf (paref x (:array :double) 5) 100d0
     59          (paref x (:array :double) 8) -1000d0)
     60    (#_cblas_idamax 10 x 1))
     618
     62?
     63}}}