Opened 12 years ago

Closed 12 years ago

#19 closed defect (invalid)

Bug in bridge/FFI?

Reported by: phil Owned by: gb
Priority: major Milestone:
Component: Foreign Function Interface Version:
Keywords: Cc:

Description

I'm attempting to use the GraphX framework (http://blog.oofn.net/projects/graphx) via the bridge but it doesn't seem to be fully 'registering' as the bridge knows about the class methods but doesn't seem to pick up the classes themselves. As a result, I obviously can't create an instance:

(objc:make-objc-instance "CTScatterPlotView")

ObjC class CTScatterPlotView not found

[Condition of type SIMPLE-ERROR]

Restarts:

0: [ABORT-REQUEST] Abort handling SLIME request. 1: [ABORT-BREAK] Reset this process 2: [ABORT] Kill this process

Backtrace:

0: (CCL::LOOKUP-OBJC-CLASS "CTScatterPlotView" 'T) 1: (CCL::%OBJC-CLASS-CLASSPTR #S(CCL::OBJC-CLASS-DESCRIPTOR :NAME "CTScatterPlotView" :CLASSPTR NIL))

So I confirm that the bridge doesn't see the class:

(objc:@class "CTScatterPlotView")

ObjC class CTScatterPlotView not found

[Condition of type SIMPLE-ERROR]

Restarts:

0: [ABORT-REQUEST] Abort handling SLIME request. 1: [ABORT-BREAK] Reset this process 2: [ABORT] Kill this process

Backtrace:

0: (CCL::LOOKUP-OBJC-CLASS "CTScatterPlotView" 'T) 1: (CCL::%OBJC-CLASS-CLASSPTR #S(CCL::OBJC-CLASS-DESCRIPTOR :NAME "CTScatterPlotView" :CLASSPTR NIL))

But the methods were picked up so it is at least partially loading the interfaces:

(ccl::lookup-objc-message-info "showFill") #S(CCL::OBJC-MESSAGE-INFO :MESSAGE-NAME "showFill" :METHODS (#<OBJC-METHOD-INFO -[CTCurveView showFill] #x9880F1E> #<OBJC-METHOD-INFO -[CTHistogramView showFill] #x9880F8E> #<OBJC-METHOD-INFO -[CTScatterPlotView showFill] #x988100E>) :AMBIGUOUS-METHODS NIL :REQ-ARGS NIL :FLAGS NIL :PROTOCOL-METHODS NIL :LISP-NAME NIL :SELECTOR NIL)

I've also confirmed that class definition is making it into the FFI and then the CDB files. (I only confirmed that there was a class entry in the FFI file and ran 'strings objc-classes.cdb | grep CT')

Attachments (1)

GET-OBJC-CLASS-DECL trace output.txt (180.0 KB) - added by phil 12 years ago.

Download all attachments as: .zip

Change History (4)

comment:1 Changed 12 years ago by gb

OBJC:LOAD-FRAMEWORK is supposed to handle this sort of thing. The general idea is:

  1. Open the interfaces associated with the framework.
  1. Load the executable; this usually causes new classes to be introduced into the ObjC runtime.
  1. For each previously unknown class, check (by calling CCL::GET-OBJC-CLASS-DECL) to see if there's a declaration for that class in the interfaces (including the interfaces opened in step 1 above.)
  1. If there is a declaration, introduce the class into CLOS. Among other things, this will allow the method processing in step 4 to work (where "work" means "avoid th error you encountered".
  2. If there is not a declaration, treat the class as "private and internal".
  1. Discover whether or not new method declarations introduce ambiguity, cache information about new "init" messages.

If you're not loading the framework with OBJC:LOAD-FRAMEWORK, you need to do these steps in this order. The easiest way to do that is to use OBJC:LOAD-FRAMEWORK. If you're doing that, then tracing CCL::GET-OBJC-CLASS-DECL might help to reveal what's going wrong. Is this function getting called on the classes that aren't defined ? If so, is a declaration found ?

comment:2 Changed 12 years ago by phil

OBJC:LOAD-FRAMEWORK is being used (specifically I'm calling (objc:load-framework "GraphX" :graphx) as part of the initialization code I use to load my other frameworks which are working)

(ccl::get-objc-class-decl "CTScatterPlotView") returns:

(CCL::DB-OBJC-CLASS-INFO :CLASS-NAME "CTScatterPlotView" :SUPERCLASS-NAME "CTGraphView" :PROTOCOLS NIL :IVARS (#<FOREIGN-RECORD-FIELD #<FOREIGN-POINTER-TYPE (:* (:STRUCT :OBJC_OBJECT (:ISA (:* (:STRUCT :OBJC_CLASS (:ISA (:* (:STRUCT :OBJC_CLASS)) 32) (:SUPER_CLASS (:* (:STRUCT :OBJC_CLASS)) 32) (:NAME (:* (:SIGNED 8)) 32) (:VERSION (:SIGNED 32) 32) (:INFO (:SIGNED 32) 32) (:INSTANCE_SIZE (:SIGNED 32) 32) (:IVARS (:* (:STRUCT :OBJC_IVAR_LIST (:IVAR_COUNT (:SIGNED 32) 32) (:IVAR_LIST (ARRAY (:STRUCT :OBJC_IVAR (:IVAR_NAME (:* (:SIGNED 8)) 32) (:IVAR_TYPE (:* (:SIGNED 8)) 32) (:IVAR_OFFSET (:SIGNED 32) 32)) 1) 96))) 32) (:METHOD<L>ISTS (:* (:* (:STRUCT :OBJC_METHOD_LIST (:OBSOLETE (:* (:STRUCT :OBJC_METHOD_LIST)) 32) (:METHOD_COUNT (:SIGNED 32) 32) (:METHOD_LIST (ARRAY (:STRUCT :OBJC_METHOD (:METHOD_NAME (:* (:STRUCT :OBJC_SELECTOR)) 32) (:METHOD_TYPES (:* (:SIGNED 8)) 32) (:METHOD_IMP (:* (:* :VOID)) 32)) 1) 96)))) 32) (:CACHE (:* (:STRUCT :OBJC_CACHE)) 32) (:PROTOCOLS (:* (:STRUCT :OBJC_PROTOCOL_LIST (:NEXT (:* (:STRUCT :OBJC_PROTOCOL_LIST)) 32) (:COUNT (:SIGNED 32) 32) (:LIST (ARRAY (:* (:STRUCT :<P>ROTOCOL (:ISA (:* (:STRUCT :OBJC_CLASS)) 32) (:PROTOCOL_NAME (:* (:SIGNED 8)) 32) (:PROTOCOL_LIST (:* (:STRUCT :OBJC_PROTOCOL_LIST)) 32) (:INSTANCE_METHODS (:* (:STRUCT :OBJC_METHOD_DESCRIPTION_LIST)) 32) (:CLASS_METHODS (:* (:STRUCT :OBJC_METHOD_DESCRIPTION_LIST)) 32))) 1) 32))) 32))) 32))) #x989999E> :DATA<S>OURCE 32@1632> #<FOREIGN-RECORD-FIELD #<FOREIGN-POINTER-TYPE (:* (:STRUCT :OBJC_OBJECT (:ISA (:* (:STRUCT :OBJC_CLASS (:ISA (:* (:STRUCT :OBJC_CLASS)) 32) (:SUPER_CLASS (:* (:STRUCT :OBJC_CLASS)) 32) (:NAME (:* (:SIGNED 8)) 32) (:VERSION (:SIGNED 32) 32) (:INFO (:SIGNED 32) 32) (:INSTANCE_SIZE (:SIGNED 32) 32) (:IVARS (:* (:STRUCT :OBJC_IVAR_LIST (:IVAR_COUNT (:SIGNED 32) 32) (:IVAR_LIST (ARRAY (:STRUCT :OBJC_IVAR (:IVAR_NAME (:* (:SIGNED 8)) 32) (:IVAR_TYPE (:* (:SIGNED 8)) 32) (:IVAR_OFFSET (:SIGNED 32) 32)) 1) 96))) 32) (:METHOD<L>ISTS (:* (:* (:STRUCT :OBJC_METHOD_LIST (:OBSOLETE (:* (:STRUCT :OBJC_METHOD_LIST)) 32) (:METHOD_COUNT (:SIGNED 32) 32) (:METHOD_LIST (ARRAY (:STRUCT :OBJC_METHOD (:METHOD_NAME (:* (:STRUCT :OBJC_SELECTOR)) 32) (:METHOD_TYPES (:* (:SIGNED 8)) 32) (:METHOD_IMP (:* (:* :VOID)) 32)) 1) 96)))) 32) (:CACHE (:* (:STRUCT :OBJC_CACHE)) 32) (:PROTOCOLS (:* (:STRUCT :OBJC_PROTOCOL_LIST (:NEXT (:* (:STRUCT :OBJC_PROTOCOL_LIST)) 32) (:COUNT (:SIGNED 32) 32) (:LIST (ARRAY (:* (:STRUCT :<P>ROTOCOL (:ISA (:* (:STRUCT :OBJC_CLASS)) 32) (:PROTOCOL_NAME (:* (:SIGNED 8)) 32) (:PROTOCOL_LIST (:* (:STRUCT :OBJC_PROTOCOL_LIST)) 32) (:INSTANCE_METHODS (:* (:STRUCT :OBJC_METHOD_DESCRIPTION_LIST)) 32) (:CLASS_METHODS (:* (:STRUCT :OBJC_METHOD_DESCRIPTION_LIST)) 32))) 1) 32))) 32))) 32))) #x989988E> :DELEGATE 32@1664> #<FOREIGN-RECORD-FIELD #<FOREIGN-INTEGER-TYPE (:UNSIGNED 32) #x840A356> :DRAW<G>RAPH<F>LAG 32@1696> #<FOREIGN-RECORD-FIELD #<FOREIGN-INTEGER-TYPE (:UNSIGNED 32) #x840A356> :DRAW<F>ILL<F>LAG 32@1728> #<FOREIGN-RECORD-FIELD #<FOREIGN-SINGLE-FLOAT-TYPE SINGLE-FLOAT #x841BE46> :CURVE<L>INE<W>IDTH 32@1760> #<FOREIGN-RECORD-FIELD #<FOREIGN-POINTER-TYPE (:* (:STRUCT :<NSB>EZIER<P>ATH (:ISA (:* (:STRUCT :OBJC_CLASS (:ISA (:* (:STRUCT :OBJC_CLASS)) 32) (:SUPER_CLASS (:* (:STRUCT :OBJC_CLASS)) 32) (:NAME (:* (:SIGNED 8)) 32) (:VERSION (:SIGNED 32) 32) (:INFO (:SIGNED 32) 32) (:INSTANCE_SIZE (:SIGNED 32) 32) (:IVARS (:* (:STRUCT :OBJC_IVAR_LIST (:IVAR_COUNT (:SIGNED 32) 32) (:IVAR_LIST (ARRAY (:STRUCT :OBJC_IVAR (:IVAR_NAME (:* (:SIGNED 8)) 32) (:IVAR_TYPE (:* (:SIGNED 8)) 32) (:IVAR_OFFSET (:SIGNED 32) 32)) 1) 96))) 32) (:METHOD<L>ISTS (:* (:* (:STRUCT :OBJC_METHOD_LIST (:OBSOLETE (:* (:STRUCT :OBJC_METHOD_LIST)) 32) (:METHOD_COUNT (:SIGNED 32) 32) (:METHOD_LIST (ARRAY (:STRUCT :OBJC_METHOD (:METHOD_NAME (:* (:STRUCT :OBJC_SELECTOR)) 32) (:METHOD_TYPES (:* (:SIGNED 8)) 32) (:METHOD_IMP (:* (:* :VOID)) 32)) 1) 96)))) 32) (:CACHE (:* (:STRUCT :OBJC_CACHE)) 32) (:PROTOCOLS (:* (:STRUCT :OBJC_PROTOCOL_LIST (:NEXT (:* (:STRUCT :OBJC_PROTOCOL_LIST)) 32) (:COUNT (:SIGNED 32) 32) (:LIST (ARRAY (:* (:STRUCT :<P>ROTOCOL (:ISA (:* (:STRUCT :OBJC_CLASS)) 32) (:PROTOCOL_NAME (:* (:SIGNED 8)) 32) (:PROTOCOL_LIST (:* (:STRUCT :OBJC_PROTOCOL_LIST)) 32) (:INSTANCE_METHODS (:* (:STRUCT :OBJC_METHOD_DESCRIPTION_LIST)) 32) (:CLASS_METHODS (:* (:STRUCT :OBJC_METHOD_DESCRIPTION_LIST)) 32))) 1) 32))) 32))) 32) (:_STATE (:SIGNED 32) 32) (:_SEGMENT<C>OUNT (:SIGNED 32) 32) (:_SEGMENT<M>AX (:SIGNED 32) 32) (:_HEAD (:* (:STRUCT :<PATHSEGMENT>)) 32) (:_LAST<S>UBPATH<I>NDEX (:SIGNED 32) 32) (:_ELEMENT<C>OUNT (:SIGNED 32) 32) (:_LINE<W>IDTH SINGLE-FLOAT 32) (:_BOUNDS (:STRUCT :_<NSR>ECT (:ORIGIN (:STRUCT :_<NSP>OINT (:X SINGLE-FLOAT 32) (:Y SINGLE-FLOAT 32)) 64) (:SIZE (:STRUCT :_<NSS>IZE (:WIDTH SINGLE-FLOAT 32) (:HEIGHT SINGLE-FLOAT 32)) 64)) 128) (:_CONTROL<P>OINT<B>OUNDS (:STRUCT :_<NSR>ECT) 128) (:_FLAGS (:UNSIGNED 8) 8) (:_MITER<L>IMIT SINGLE-FLOAT 32) (:_FLATNESS SINGLE-FLOAT 32) (:_DASHED<L>INE<P>ATTERN (:* SINGLE-FLOAT) 32) (:_DASHED<L>INE<C>OUNT (:UNSIGNED 32) 32) (:_DASHED<L>INE<P>HASE SINGLE-FLOAT 32))) #x98994DE> :CURVE 32@1792> #<FOREIGN-RECORD-FIELD #<FOREIGN-POINTER-TYPE (:* (:STRUCT :<NSB>EZIER<P>ATH (:ISA (:* (:STRUCT :OBJC_CLASS (:ISA (:* (:STRUCT :OBJC_CLASS)) 32) (:SUPER_CLASS (:* (:STRUCT :OBJC_CLASS)) 32) (:NAME (:* (:SIGNED 8)) 32) (:VERSION (:SIGNED 32) 32) (:INFO (:SIGNED 32) 32) (:INSTANCE_SIZE (:SIGNED 32) 32) (:IVARS (:* (:STRUCT :OBJC_IVAR_LIST (:IVAR_COUNT (:SIGNED 32) 32) (:IVAR_LIST (ARRAY (:STRUCT :OBJC_IVAR (:IVAR_NAME (:* (:SIGNED 8)) 32) (:IVAR_TYPE (:* (:SIGNED 8)) 32) (:IVAR_OFFSET (:SIGNED 32) 32)) 1) 96))) 32) (:METHOD<L>ISTS (:* (:* (:STRUCT :OBJC_METHOD_LIST (:OBSOLETE (:* (:STRUCT :OBJC_METHOD_LIST)) 32) (:METHOD_COUNT (:SIGNED 32) 32) (:METHOD_LIST (ARRAY (:STRUCT :OBJC_METHOD (:METHOD_NAME (:* (:STRUCT :OBJC_SELECTOR)) 32) (:METHOD_TYPES (:* (:SIGNED 8)) 32) (:METHOD_IMP (:* (:* :VOID)) 32)) 1) 96)))) 32) (:CACHE (:* (:STRUCT :OBJC_CACHE)) 32) (:PROTOCOLS (:* (:STRUCT :OBJC_PROTOCOL_LIST (:NEXT (:* (:STRUCT :OBJC_PROTOCOL_LIST)) 32) (:COUNT (:SIGNED 32) 32) (:LIST (ARRAY (:* (:STRUCT :<P>ROTOCOL (:ISA (:* (:STRUCT :OBJC_CLASS)) 32) (:PROTOCOL_NAME (:* (:SIGNED 8)) 32) (:PROTOCOL_LIST (:* (:STRUCT :OBJC_PROTOCOL_LIST)) 32) (:INSTANCE_METHODS (:* (:STRUCT :OBJC_METHOD_DESCRIPTION_LIST)) 32) (:CLASS_METHODS (:* (:STRUCT :OBJC_METHOD_DESCRIPTION_LIST)) 32))) 1) 32))) 32))) 32) (:_STATE (:SIGNED 32) 32) (:_SEGMENT<C>OUNT (:SIGNED 32) 32) (:_SEGMENT<M>AX (:SIGNED 32) 32) (:_HEAD (:* (:STRUCT :<PATHSEGMENT>)) 32) (:_LAST<S>UBPATH<I>NDEX (:SIGNED 32) 32) (:_ELEMENT<C>OUNT (:SIGNED 32) 32) (:_LINE<W>IDTH SINGLE-FLOAT 32) (:_BOUNDS (:STRUCT :_<NSR>ECT (:ORIGIN (:STRUCT :_<NSP>OINT (:X SINGLE-FLOAT 32) (:Y SINGLE-FLOAT 32)) 64) (:SIZE (:STRUCT :_<NSS>IZE (:WIDTH SINGLE-FLOAT 32) (:HEIGHT SINGLE-FLOAT 32)) 64)) 128) (:_CONTROL<P>OINT<B>OUNDS (:STRUCT :_<NSR>ECT) 128) (:_FLAGS (:UNSIGNED 8) 8) (:_MITER<L>IMIT SINGLE-FLOAT 32) (:_FLATNESS SINGLE-FLOAT 32) (:_DASHED<L>INE<P>ATTERN (:* SINGLE-FLOAT) 32) (:_DASHED<L>INE<C>OUNT (:UNSIGNED 32) 32) (:_DASHED<L>INE<P>HASE SINGLE-FLOAT 32))) #x989936E> :DISPLACEMENT 32@1824>) :INSTANCE-METHODS NIL :CLASS-METHODS NIL)

Also, as you suggested I traced GET-OBJC-CLASS-DECL and have attached the file with the trace output. I don't see any of the CT* (i.e. CTScatterPlotView) class names in the trace output.

Changed 12 years ago by phil

comment:3 Changed 12 years ago by gb

  • Component changed from ANSI CL Compliance to Foreign Function Interface
  • Resolution set to invalid
  • Status changed from new to closed

As it's distributed, GraphX seems to have some unusual entries in the framework bundle's Info.plist file; notably, the value of the CFBundleExecutable key seems to be "GraphKit" (though the library seems to be called "GraphX"). I suspect that fixing this (changing the CFBundleExecutable key to "GraphX") will fix at least this problem.

Before this change, the lisp would open the framework bundle, ask the bundle what its executablePath was, and get told that it didn't have one. (It might have been better to have been told "it has one, but it's misconfigured.") It's not an error for a framework to not contain a "main executable resource", so the lisp quietly skips the step of loading the library.

In the context where OBJC:LOAD-FRAMEWORK is opening the framework, it's certainly expecting there to be a usable library in there, so it'd probably have been better to have gotten an error or warning in this case.

Other than how well it deals with misconfigured frameworks, I'm not sure that there's an FFI/bridge problem here.

I didn't try to build GraphX from source, and don't know whether the bad Info.plist problem would have been present if I'd done so.

I'm tempted to want to close this, and maybe open a "OBJC:LOAD-FRAMEWORK doesn't deal with misconfigured frameworks" bug. Maybe. I'm sure that there are other ways to lose, and I doubt if there's anything OpenMCL-specific about losing in this or other ways; you might want to ask the author if they or anyone else can use the framework as it's distributed.

Note: See TracTickets for help on using tickets.