Creating FB bindings for C libraries



This page aims to document the problems and solutions commonly encountered when creating FB bindings for C libraries.

In general, FB and C/C++ are very similar. FB follows the same ABI as GCC where applicable, in order to be binary-compatible as much as possible. The language syntax is also similar to C/C++. As a result, a lot of type and procedure declarations can be translated directly 1:1 between C and FB. However, there also are constructs which cannot be translated directly, for example: typedefs declaring function types. FB has function pointer types, but not plain function types.


Data types
C/C++ type Size in bytes (GCC on Linux/Windows) Corresponding FreeBASIC type
char 1 Byte
short [int] 2 Short
int 4 Long
enum (underlying type int) 4 Long
long long [int] 8 LongInt
float 4 Single
double 8 Double
long double 12 on 32bit, 16 on 64bit CLongDouble from crt/longdouble.bi
_Bool/bool 1 Byte / Boolean (from fbc version 1.04)
* (pointer) 4 on 32bit, 8 on 64bit Ptr/Pointer
ssize_t, intptr_t 4 on 32bit, 8 on 64bit Integer
size_t, uintptr_t 4 on 32bit, 8 on 64bit UInteger
long [int] 4 on 32bit systems and Win64 (!), 8 on 64bit Linux/BSD CLong from crt/long.bi



For example:

enum MyEnum {
    A,
    B
}

has to be translated as:

Type MyEnum As Long
Enum
    A
    B
End Enum



Symbol name conflicts


Examples

C code using FB keywords as identifiers:
typedef int INT;
void open(void);

Type INT_ As Long
Declare Sub open_ CDecl Alias "open"()


C code relying on case-sensitivity:
void foo(void);
void Foo(void);
void FOO(void);

'' Wrong translation:
Extern "C"
    Declare Sub foo()
    Declare Sub Foo()  '' error: duplicate definition
    Declare Sub FOO()  '' error: duplicate definition
End Extern

'' Correct translation:
Extern "C"
    Declare Sub foo()
    Declare Sub Foo_ Alias "Foo"()
    Declare Sub FOO__ Alias "FOO"()
End Extern


Another classic example where this kind of conflict happens:
#define GET_VERSION_NUMBER 123
int get_version_number(void);

Extern "C"
    #define GET_VERSION_NUMBER_ 123  '' renamed to avoid conflict
    Declare Function get_version_number() As Long
End Extern


Conflict between procedure and macro:
void f(int);
#define f(i) f(i + 1)

Extern "C"
    Declare Sub f(ByVal As Long)
    #define f_(i) f(i + 1)  '' renamed to avoid conflict
End Extern


Solutions

  • Symbols should be renamed by appending _ underscores. This way we solve the conflicts and still stay close to the original API.
  • Renaming a symbol should not cause further renames (for example, if foo must be renamed, but foo_ already exists, then foo should be renamed to foo__ instead)
  • A list of renamed symbols should be available in the binding or in the binding's documentation such that users can identify such differences to the original API.
  • Fields inside structures do not need to be renamed just because they match an FB keyword. By using the "As DataType Name" syntax they can be use FB keywords as identifiers. This only works as long as it is a simple structure (plain old data), not a class.
  • Type UdtWithKeywordFields
        As ZString Ptr String  '' Field "String" of type ZString Ptr
        As Long Type  '' Field "Type" of type "Long"
        As Long As  '' Field "As" of type "Long"
    End Type


Function types
In C it's possible to have typedefs with function types. Dereferencing a function pointer type results in a function type. FB only has function pointer types, but not function types.

// A function typedef (function result = void, no parameters)
typedef void F(void);

// Using it to declare a function called f1
F f1;

// Usually f1 would be declared like this (use of function typedefs is pretty rare):
void f1(void);

// A more common use for function typedefs is to declare pointers to them (function pointers):
extern F *pf1;


Since FB does not have function types, such typedefs have to be solved out, or turned into a function pointer:

Extern "C"

Type F As Sub()  '' Function pointer type

'' Declaring procedures is only possible with Declare in FB
Declare Sub f1()

'' But at least FB has function pointer types.
'' Since F already is the function pointer in the FB translation, there is no extra PTR here
Extern pf1 As F

End Extern


Back to FreeBASIC Developer Information

Back to Table of Contents
Valid XHTML :: Valid CSS: :: Powered by WikkaWiki



sf.net phatcode