Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
FreeBASIC binding creation tool
Visual Basic C C++ Objective-C
Branch: master

readme.txt

  fbfrog -- FreeBASIC binding generator
  Copyright (C) 2011 - 2015  Daniel C. Klauer <daniel.c.klauer[at]web.de>

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.


What's this?

  fbfrog is a tool that reads *.h files (C API declarations) and generates a
  corresponding *.bi file (FreeBASIC API declarations). It's intended to
  automate most of the work needed to create and maintain FB bindings for C
  libraries.

  C and FB are similar enough to allow most declarations to be converted 1:1 by
  doing a pure syntax conversion, for example:
      struct UDT {              =>    type UDT
          float f;              =>        f as single
      };                        =>    end type
      void f(struct UDT *p);    =>    declare sub f(byval p as UDT ptr)

  Besides that, fbfrog performs the following "high-level" transformations:
   * C types + size_t/int32_t/... => FB types
   * char => byte, char* => zstring ptr, char[N] => zstring * N
     (same for wchar_t/wstring)
   * Most used calling convention => Extern block
   * Other calling conventions (if header uses multiple ones) => emitted on
     individual procedures
   * Function/array typedefs (not supported in FB) => solved out
   * Array parameters (not supported in FB) => pointers
   * Arrays/strings declared with unknown size => "..." ellipsis
   * jmp_buf parameters => pointers (jmp_buf is a UDT in FB, not an array type)
   * Anonymous structs (not supported in FB) => named after first typedef that
     uses them, or auto-generated name
   * typedef struct FOO FOO; => solved out (FB doesn't have separate types/tags)
   * #defines with simple constant expression in their bodies => FB constants
   * #defines nested inside struct bodies => moved to toplevel (helps when
     converting #defines to constants, because FB scopes those inside UDTs)
   * #define m(a, ...) __VA_ARGS__ => #define m(a, __VA_ARGS__...) __VA_ARGS__
   * Named enum => type enumname as long + anonymous enum
     (C enums/ints stay 32bit on 64bit, so in FB we have to use the always-32bit
     LONG type instead of the default ENUM/INTEGER type)
   * #pragma comment(lib, "foo.lib"|"libfoo.a") => #inclib "foo"

  Declarations which cannot be processed automatically (yet) will be embedded
  into the *.bi file in form of a "TODO" comment, for example:
    '' TODO: #define FOO ...
  This affects:
   * Complicated #defines ("arbitrary" token sequences)
   * Function bodies (inline functions)
   * Plus some others (you'll see; most things should be supported by now, but
     there's always something missing...)

  fbfrog preprocesses and parses the input headers multiple times: once for each
  supported target (DOS/Linux/Windows, x86/x86_64) and merges all these APIs
  together into the final binding. If you need to override this (for example if
  your .h files don't support DOS and have an #error statement for this case),
  then use -target and specify the needed targets manually.


Compiling:
  fbc *.bas -m fbfrog

Running the tests:
  1. fbc tests/run.bas
  2. tests/run
  3. Use Git to check the status of the tests/ directory.
     Any changes indicate test failures.


Usage:

  Run fbfrog and pass the *.h file(s) on the command line:
    fbfrog foo.h

  It's only necessary to pass the "entry points" - the header(s) that you would
  #include in a C program. fbfrog expands all #includes it can find.
  The generated binding will cover the API that would become available by
  #including those headers in the given order. Separate headers that aren't
  intended to be #included together shouldn't be passed to fbfrog together, but
  in separate invocations.

  If fbfrog can't find #included header files, you can use this option:
    -incdir <path>
  Sometimes this is needed to allow the main header to be parsed successfully.
  (for example, a macro can only be expanded if the #define statement was seen)

  The .bi file generated by fbfrog needs to be reviewed and tested. TODOs must
  be fixed up manually.


Using the -declare*/-select/-ifdef options:

  fbfrog is able to read multiple headers or multiple versions of the same
  header (preprocessed differently) and merge them into a single binding.
  1. This is used to support multiple targets (DOS/Linux/Win32, x86/x86_64):
     Instead of looking for #ifs in the input headers and possibly trying to
     preserve those, fbfrog preprocesses and parses the input header files
     multiple times (using different predefines each time), and then merges the
     resulting target-specific APIs into one final binding, by (re-)inserting
     #ifs (such as #ifdef __FB_WIN32__) where needed.
  2. and by using the -declare* command line options yourself you can combine
     pretty much any APIs, for example version 1.0 and 2.0 of a library, or the
     ANSI and UNICODE versions of a Win32-specific header. Of course it only
     makes sense if the APIs belong together. Sometimes the merging algorithm
     produces a rather ugly result though, especially if the differences between
     the APIs are too big, so it's not always useful.

  Assuming we have the header files foo1.h and foo2.h, let's use the following
  fbfrog options:

    -declareversions __LIBFOO_VERSION 1 2
    -select __LIBFOO_VERSION
    -case 1
        foo1.h
    -case 2
        foo2.h
    -endselect

  Save those options into a foo.fbfrog helper file (because it's too much to
  type at the command line), and pass it to fbfrog:

    fbfrog foo.fbfrog

  The created binding will allow the user to #define __LIBFOO_VERSION to 1 or
  2 in order to select that specific API version:

    [...declarations that existed in both foo1.h and foo2.h...]
    #if __LIBFOO_VERSION = 1
        [...declarations that existed only in foo1.h...]
    #else
        [...declarations that existed only in foo2.h...]
    #endif
    [...etc...]

  You can use -declare* options as wanted to support multiple APIs in 1 binding:

    -declareversions <symbol> <numbers...>
        Useful to allow selecting an API by version. This will produce #if
        blocks such as #if <symbol> = <number>.

    -declarebool <symbol>
        Useful to allow API selection based on whether a certain symbol is
        defined or not. This is used for __FB_64BIT__ in default.fbfrog, but
        could also be used to support distinguishing between UNICODE and ANSI
        versions of a binding (-declarebool UNICODE -> #ifdef UNICODE) or
        the shared library/DLL version and the static library version, etc.

  If multiple -declare* options are given, they multiply. For example:
    -declarebool A -declarebool B
  produces these APIs:
         defined(A)  and      defined(B)
         defined(A)  and (not defined(B))
    (not defined(A)) and      defined(B)
    (not defined(A)) and (not defined(B))

  You can use the -select/-ifdef logic options to create different "code paths"
  where some options will only be used for some APIs (instead of applying to
  all APIs). This also works with -declare* options, allowing you to build
  even complex API condition trees. See for example
  include/fbfrog/default.fbfrog, which declares 64bit versions for all systems
  except DOS.


Why use a custom C preprocessor and parser instead of an existing one?
  fbfrog wants to do things that existing preprocessors/parsers don't support:
    * preserve #defines and parse their bodies
    * selective/optional expansion of macros and #includes
    * fully configurable pre-#defines, no hard-coded target/compiler-specifics
    * modify the AST to make it FB-friendly, insert FB-specific constructs


Why make fbfrog a standalone tool? How about integrating C parsing (or rather,
a binding creation tool) into fbc itself directly, so bindings would become
unnecessary?
  1. Until we can translate all constructs to FB automatically, the .bi files
     are needed as a "buffer" where we can fix things up manually.
  2. fbc's existing lexing/preprocessing/parsing code could not be reused to
     parse C headers, because it's way too different from C. Thus it'd be
     necessary to maintain a full binding creation tool as part of fbc, and it'd
     be more or less the same amount of work as keeping it separate -- although
     having it included in fbc would probably be more convenient for the user.
  3. fbc is the FB compiler, not a C compiler, and FB itself should be good
     enough to specify the API/ABI for accessing external libraries.
  4. Users may expect to be able to interact with the #included .h file directly
     by using FB #define statements etc., but that wouldn't be possible unless
     we had an FB-to-C translator too.


To do:

Bugs:
* C parser needs to verify #directives, since they can be inserted by "to c" -replacements,
  which aren't verified by the CPP
* in winapi, there is a case where an auto-generated tagid conflicts
  with a real typedef, which is errornously renamed. Luckily fbc detects this
  problem easily (recursive UDT).
	struct Foo {
		struct {
			HWND hwnd;
		} HWND;
	};
* <wstr("a") wstr("b")> doesn't work as string literal, + string concat
  operators have to be inserted
* void casts shouldn't silently be translated to cast(any, ...), as that's not
  allowed in FB but could easily be missed if it's in a macro body
  (at least, mark it with a TODO)

Interesting improvements:
* don't build VERAND conditions at frogEvaluateScript() time, but rather do it
  later when generating the #if conditions.
  - -declareversions: store version number in ApiInfo
  - -declarebool: store flags in ApiInfo
  - frogEvaluateScript() should build ApiInfo objects directly, then copy them
    for recursive invocations, no more separate loadOptions()
* consecutive verblocks should be added to a prefix tree, to solve out common
  API conditions, e.g.:
	#if win32 and static		#if win32
		...				#if static
	#endif						...
	#if win32				#endif
		...		=>		...
	#endif					#if static
	#if win32 and static				...
		...				#endif
	#endif				#endif
  and to catch bad merges:
	#if win32			#if win32
		[win32 1]			[win32 1]
	#else					[win32 2]
		[linux]		=>	#else
	#endif					[linux]
	#if win32			#endif
		[win32 2]
	#endif
* LCS is main bottle-neck, can it be optimized?
* Turn more inline functions into macros: also void functions whose body can
  just be used as macro'd scope block, and doesn't contain any RETURNs
* X11 headers have commented out parameter names. It'd be nice if fbfrog could
  preserve/uncomment them.
    1. preserve comments
    2. for unnamed parameters, check if the comment is just an id, and if so
       use it as the param id.
* add pass for fixing up string literal casts (useful for gtk3 at least):
	cast(SomePtrType, "foo")  =>  cast(SomePtrType, @"foo")
* fbfrog-fbc-wrapper for compiling .bas files that contain #fbfrog directives
  * process #fbfrog directives in the .bas and in each included .bi; must do
    #include search just like the fbc. Query fbc's incdir via 'fbc -print incdir'
    and also intercept -i <path> options passed on the fbc command line.
  * #fbfrog <fbfrog command line options>
  * invoke fbfrog with these options, but add -target for 1 target only
  * let fbfrog create a temp .bi: -o *.temp.bi, then produce a *.temp.bas which
    #includes the *.temp.bi instead of having a #fbfrog directive, then invoke
    fbc to compile it.
  * query system/gcc incdirs and pass them as fbfrog -incdirs
* Change AST:
  Store fields/procbodies at toplevel wrapped in TYPEBEGIN/TYPEEND/PROCBEGIN/PROCEND,
  allowing nested LOC to be merged separate from the compound.
  (interesting for fields if UDT's FIELD=N value changes between targets)
  Store LOC as array (save memory, better caching, re-use as decltables for merging)
  (even though highlevel passes require insert/delete, that's not that much since
  it will be only ~ 20k * sizeof(StmtNode) array elements, and if needed a gap buffer
  can be used)
  * use separate ExprNode to hold expressions
      - 2 kinds of macros: 1. expression macro, 2. code block macro
* Show #include tree
* Hard-code default.fbfrog and default.h, remove include/fbfrog/
  add a tools/gcc.sh or similar that queries various gcc toolchains and
  generates a gccpredefs.bi
* Don't expand macro constants outside CPP expressions, to keep them as array size etc.
* Solve out tag ids if there is an alias typedef, unless the tag id is used elsewhere
* Turn alias #defines into proper decls (typedefs, procdecls)
   1st pass: collect all types/procs
   2nd pass: find alias #defines and turn them into real decls. For procs, 1.
   duplicate the PROC node, 2. rename it to get an ALIAS emitted.
* pattern-based -removedefine, e.g. -removedefine '__*'
* pattern-based renames, e.g. -renamedefine '%' 'FOO_%',
  or at least --rename-define-add-prefix '*' FOO_  <- add prefix FOO_ to matching defines.
* -rename <id> which automatically appends an _ underscore
* auto-convert C's [] array indexing into FB's (): track which vars/fields are
  arrays (or pointers) and then compare indexing BOPs against that.
* Add support for
    #pragma pack(push, <identifier> [, N])
    #pragma pack(pop, <identifier>)
  i.e. pack stack entries can be named. popping by name means popping everything
  until that node is popped. If not found, nothing is popped.
  (MinGW-w64 CRT headers use this)
* Continue support for parsing function bodies:
  - ++ and -- operators
  - for loops (probably useless without ++/-- support)
  - continue/break
  - goto/labels/switch/case
Something went wrong with that request. Please try again.