Ffi pack

The ffi pack has a problem parsing declarations like these:

# define	uint8_t			unsigned char
# define	uint16_t		unsigned short
# define	uint32_t		unsigned int
# define	uint64_t		unsigned long long

# define	sint8_t			signed char
# define	sint16_t		signed short
# define	sint32_t		signed int
# define	sint64_t		signed long long

// Unsigned integer types
void Array_SubVector_uint8 (uint8_t target[], const uint8_t source[], size_t size);
void Array_SubVector_uint16 (uint16_t target[], const uint16_t source[], size_t size);
void Array_SubVector_uint32 (uint32_t target[], const uint32_t source[], size_t size);
void Array_SubVector_uint64 (uint64_t target[], const uint64_t source[], size_t size);

// Signed integer types
void Array_SubVector_sint8 (sint8_t target[], const sint8_t source[], size_t size);
void Array_SubVector_sint16 (sint16_t target[], const sint16_t source[], size_t size);
void Array_SubVector_sint32 (sint32_t target[], const sint32_t source[], size_t size);
void Array_SubVector_sint64 (sint64_t target[], const sint64_t source[], size_t size);
size);

These are the kind of errors I get:

ERROR: /home/u/bld/prolog/linasm4pl/prolog/linasm/array.pl:13:
ERROR:    FFI: 'Array_SubVector_sint64': incompatible parameter: *longlong -> target-signed
ERROR: /home/u/bld/prolog/linasm4pl/prolog/linasm/array.pl:13:
ERROR:    FFI: 'Array_SubVector_sint64': incompatible parameter: *longlong -> source-signed
ERROR: /home/u/bld/prolog/linasm4pl/prolog/linasm/array.pl:13:
ERROR:    FFI: 'Array_SubVector_sint64': incompatible parameter: ulong -> size-unsigned

Prolog code like this:

:- c_import("#include \"Array.h\"",                  % ffi:cpp_hook provides -I flag
            [ linasm(lib/'liblinasm.so') ],
	    [
	    'Array_SubVector_sint64'(  *longlong,       % sint64_t target[],
	                               *longlong,       % const sint64_t source[],
				                   ulong,     % size_t size,
				                   [void])
	    ]).

There are a number of problems. I pushed an update to the package that deals with some of them:

  • size_t support was broken after size_t was added as a basic type because some C compilers handle it like that. Only partial support was added though :frowning:
  • Handling of types in parameters without using typedef was incomplete.
  • Handling of explicit signed was broken.
  • Handling type name[] as parameter types was broken.

Some of this seems to be used quite rarely … In addition, your Prolog declaration is wrong. The types you specify there are not the C types, but the Prolog facing type. Thus, int should be used for all integral C types. The library finds the actual C type and inserts the correct conversion. You can see why this is necessary as ulong is incorrect for size_t on 64-bit Windows (must be unsigned long long).

The header is now parsed without complaints. Whether it also works cannot be tested without the shared object.

edit see PDF docs at https://raw.githubusercontent.com/wiki/JanWielemaker/ffi/files/ffi.pdf

2 Likes

Thanks Jan, my small test is working well. The only thing I noticed is that I can’t do

 c_alloc(ArrayPtr, longlong[]=IntList).     

anymore, but I have to use

 c_alloc(ArrayPtr, long[]=IntList).    

It doesn’t matter in this case because long is the same size as longlong but I wonder if this would cause problems in other architectures.

You can download the library here: Download LinAsm from SourceForge.net. Just run make and you’ll get the shared lib. It is a very very fast library, and well done also, as I wrote in another post.

Yes, I did this in the beginning, but then calling c_alloc/2 I used int also, and this of course caused a segfault because int's are 32 bits, so to make it clearer I chose to use longlong in the declaration instead, but I did revert it back to int now.

Also had two questions:

  1. How do you pass the -I flag to the preprocessor? I had to use ffi:cpp_hook/2 because ['-I','somedir/linasm/include',linasm('liblinasm.so')] did not work for the c_import/2 flags.
  2. Many times you want to calculate the flags or even the function declarations from prolog code itself, but code like this doesn’t work:
:- ffi_flags_and_decls(Flags,Decls), 
   c_import("#include \"Array.h\"",   Flags, Decls).

because c_import/3 wants to be alone as a directive. Any way to allow this?

Oops. copied/paste error. Should work again.

I see. It does make sense to specify the real type if you need pass an array of some integer type and you do that using the c_alloc/2 predicates. If we do so we should also raise an error if the with of the type from the C header differs from what the user specified. I’m done with ffi for now, but happy to receive PRs.

I think as one option, i.e., -Isomedir/linasm/include

Its long ago. As a general issue with this type of terms that are subject to term expansion, one option is to use a local term_expansion/2 rule that creates the right directive.

The ffi package addresses this by allowing the user to define rules for c_define/2 as you can find in the examples.


Pushed version 0.3. This fixes the longlong issue and works again on MacOS. The MacOS port required supporting function pointer specification without typedef for struct members and function parameters (lacking functionality), ignore some more Clang attributes and type qualifiers and hack around MacOS 11 and later that no longer provide libc.dylib on the filesystem.