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 and definition is at... extern "C" { CXIndex clang_createIndex( ) { ... CIndexer *CIdxr = new CIndexer(); ... return CIndexer; } } |
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
|
Free forum by Nabble | Edit this page |