Hi Ben, 

here you do not need to use an opaque object (is not that what you want). 
in this case you have two paths to follow: 

1) you just declare CXIndex as an alias of ExternalAddress (or void*). This 
will work but is not cool because UFFI will answer you an ExternalAddress and 
probably you want to treat CXIndex as an object. 

2) then you need to declare CXIndex as FFIExternalObject (not OpaqueObject).

FFIExternalObject subclass: #CXIndex. 

this will work as you expected.

Opaque objects are structures that you do not care content, so it is not  what 
you wan here: https://en.wikipedia.org/wiki/Opaque_data_type

instead FFIExternalObject is precisely meant to manage pointer types (and you 
do not need to do all that hacking around).

cheers, 
Esteban



> On 09 Sep 2016, at 16:53, Ben Coman <b...@openinworld.com> wrote:
> 
> I have a type definition...
>    typedef void *CXIndex;
> 
> which I believe reads "CXIndex is a pointer at void"
> that is returned by...
>     CXIndex clang_createIndex(int x, int y)
> 
> This seems an obvious candidate to be a FFIOpaqueObject defined like this...
> 
>   FFIOpaqueObject subclass: #CXIndex
>       instanceVariableNames: ''
>       classVariableNames: ''
>       package: 'LibclangPractice'
> 
>   CXIndex class >> create
>       ^ self ffiCall: #( CXIndex clang_createIndex ( 0, 0 ) )
> 
> however  "CXIndex create inspect"
> produces an error ==> FFIDereferencedOpaqueObjectError.
> because..."external objects have a natural arity of zero but they MUST be 
> called with some arity,
> because they are actually external addresses (pointers) and you need to 
> always declare external objects as this example:
>    self ffiCall: #( FFIExternalObject *c_function ( FFIExternalObject *handle 
> ) )  
> "
> 
> which is enforced by...
>   FFIOpaqueObjectType>>validateAfterParse: typeAndArityTuple
>       self pointerArity >= 1 ifTrue: [ ^ self ].  "@0"
>       typeAndArityTuple second >= 1 ifTrue: [ ^ self ].
>       FFIDereferencedOpaqueObjectError signal
> 
> 
> where pointerArity seems set earlier just by counting the number of pointer 
> stars in the functions return type, which in this case is none...
>   FFICallout>>resolveType: aTypeName   "aTypeName==> 'CXIndex' "
>       | name newName resolver binding ptrArity |
>       newName := aTypeName.
>       ptrArity := 0.
>       "resolve aliases and pointers"
>       [
>             name := newName asString trimRight.  
>             newName := self aliasForType: name.
>             newName last = $* ifTrue: [
>                   ptrArity := ptrArity + 1.
>                   newName := newName allButLast ].
>             name = newName
>       ] whileFalse.
>       resolver := requestor ifNil: [ self class ].    "resolver==> CXIndex 
> class"
>       binding := resolver ffiBindingOf: name asSymbol.   "binding==> 
> #CXIndex->CXIndex"
>       binding ifNotNil: [
>           ^ (binding value "@1" asExternalTypeOn: self) "@2" pointerArity: 
> ptrArity ] .
> 
> which @1 invokes...
>   CXIndex(FFIOpaqueObject) class >> asExternalTypeOn: generator
>        ^ FFIOpaqueObjectType objectClass: self
> 
>   FFIOpaqueObjectType(FFIExternalReferenceType) class >> objectClass: aClass
>       ^ self new objectClass: aClass     
>   
>   FFIOpaqueObjectType(FFIExternalReferenceType) >> objectClass: aClass
>       objectClass := aClass.    "aClass==>CXIndex"
>         pointerArity := 0.  "actually this was done in #initialize"   "@3"
> 
> 
> Thus FFIOpaqueObjectType(CXIndex) is returned @2 which invokes...
>   FFIOpaqueObjectType(FFIExternalType)>>pointerArity: additionalArity
>       pointerArity := pointerArity + additionalArity.
> which sets pointerArity ==> 0.
> 
> 
> But I hazard to suggest that...
>     typedef void *CXIndex;
> 
> should make pointerArity:=1 when objectClass is assigned @3.  
> 
> 
> So I hacked around this by....
>   FFIExternalReference class >> pointerArity
>       ^0
> 
>   CXIndex class >> pointerArity
>       ^1
>   
>   FFIExternalReferenceType >> objectClass: aClass
>       objectClass := aClass.
>       pointerArity := aClass pointerArity.
> 
> but I wonder if this is the best way, or if external references these opaque 
> objects should have a class-side method similar to #fieldDesc like... 
>     typedef  
>        ^#( void * )
> 
> Thus CXIndex create "==> a CXIndex((void*)@ 16rB6D514A8)"
> 
> I am yet to test out this returned object by passing it to another C-library 
> function, but I thought the above was enough for one sitting.
> 
> cheers -ben
> 
> 
> P.S. Further background...
> 
> Declarations...
>     typedef void *CXIndex;  
>     CXIndex clang_createIndex(int xx, int yy));
> defined at...
> https://github.com/llvm-mirror/clang/blob/release_39/include/clang-c/Index.h 
> <https://github.com/llvm-mirror/clang/blob/release_39/include/clang-c/Index.h>
> 
> and definition is at... 
> https://github.com/llvm-mirror/clang/blob/release_39/include/clang-c/Index.h 
> <https://github.com/llvm-mirror/clang/blob/release_39/include/clang-c/Index.h>
> 
>    extern "C" {
>       CXIndex clang_createIndex(  ) {
>            ...
>            CIndexer *CIdxr = new CIndexer();
>            ...
>            return CIndexer;
>      } }
> 

Reply via email to