libtcc 0.9.26 dynamic Windows Linux 32/64-bit.

Headers, Bindings, Libraries for use with FreeBASIC, Please include example of use to help ensure they are tested and usable.
Post Reply
D.J.Peters
Posts: 8586
Joined: May 28, 2005 3:28
Contact:

libtcc 0.9.26 dynamic Windows Linux 32/64-bit.

Post by D.J.Peters »

I build libtcc 0.9.26 the Tiny C compiler as dynamic loaded lib for FreeBASIC

homepage: http://bellard.org/tcc/

download: libtcc.zip

Joshy

Code: Select all

#ifndef TCC_DYNAMIC_BI
#define TCC_DYNAMIC_BI

type TCCState   as any
type TCC_OUTPUT as long
#define TCC_RELOCATE_AUTO cptr(any ptr,1)
const as TCC_OUTPUT TCC_OUTPUT_MEMORY    = 0 ' output will be run in memory (default)
const as TCC_OUTPUT TCC_OUTPUT_EXE       = 1 ' executable file
const as TCC_OUTPUT TCC_OUTPUT_DLL       = 2 ' dynamic library
const as TCC_OUTPUT TCC_OUTPUT_OBJ       = 3 ' object file

type error_func as sub cdecl (byval opaque as any ptr, byval msg as const zstring ptr)

type TCC_DYNAMIC
  declare constructor
  declare destructor
  declare function IsAvailable as boolean
  ' create a new TCC compilation context
  tcc_new                 as function cdecl () as TCCState ptr
  ' free a TCC compilation context
  tcc_delete              as sub      cdecl (byval s as TCCState ptr)
  ' set CONFIG_TCCDIR at runtime
  tcc_set_lib_path        as sub      cdecl (byval s as TCCState ptr, _
                                             byval path as const zstring ptr)
  ' set error/warning display callback
  tcc_set_error_func      as sub      cdecl (byval s as TCCState ptr, _
                                             byval error_opaque as any ptr, _
                                             byval cb as error_func)
  ' set options as from command line (multiple supported)
  tcc_set_options         as function cdecl (byval s as TCCState ptr, _
                                             byval options as const zstring ptr) as long
  ' preprocessor
  ' add include path
  tcc_add_include_path    as function cdecl (byval s as TCCState ptr, _
                                             byval pathname as const zstring ptr) as long
  ' add in system include path
  tcc_add_sysinclude_path as function cdecl (byval s as TCCState ptr, _
                                             byval pathname as const zstring ptr) as long
  ' define preprocessor symbol 'sym'. Can put optional value */
  tcc_define_symbol       as sub      cdecl (byval s as TCCState ptr, _
                                             byval sym as const zstring ptr, _
                                             byval value as const zstring ptr)
  ' undefine preprocess symbol 'sym'
  tcc_undefine_symbol     as sub      cdecl (byval s as TCCState ptr, _
                                             byval sym as const zstring ptr)
  ' compiling
  ' add a file (C file, dll, object, library, ld script). Return -1 if error.
  tcc_add_file            as function cdecl (byval s as TCCState ptr, _
                                             byval filename as const zstring ptr) as long
  ' compile a string containing a C source. Return -1 if error.
  tcc_compile_string      as function cdecl (byval s as TCCState ptr, _
                                             byval buf as const zstring ptr) as long

  ' linking commands
  ' set output type. MUST BE CALLED before any compilation
  tcc_set_output_type     as function cdecl(byval s as TCCState ptr, _
                                            byval output_type as TCC_OUTPUT) as long
  ' equivalent to -Lpath option
  tcc_add_library_path    as function cdecl(byval s as TCCState ptr, _
                                            byval pathname as const zstring ptr) as long
  ' the library name is the same as the argument of the '-l' option
  tcc_add_library         as function cdecl(byval s as TCCState ptr, _
                                            byval libraryname as const zstring ptr) as long
  ' add a symbol to the compiled program
  tcc_add_symbol          as function cdecl(byval s as TCCState ptr, _
                                            byval name_ as const zstring ptr, byval value as const zstring ptr) as long
  ' output an executable, library or object file. DO NOT call tcc_relocate() before.
  tcc_output_file         as function cdecl(byval s as TCCState ptr, _
                                            byval filename as const zstring ptr) as long
  ' link and run main() function and return its value. DO NOT call tcc_relocate() before.
  tcc_run                 as function cdecl(byval s as TCCState ptr, _
                                            byval argc as long, _
                                            byval argv as zstring ptr ptr) as long
  '* do all relocations (needed before using tcc_get_symbol())
  ' possible values for 'p': TCC_RELOCATE_AUTO : Allocate and manage memory internally
  '                          NULL              : return required memory size for the step below
  '                          memory address    : copy code to memory passed by the caller
  ' returns -1 if error.
  tcc_relocate            as function cdecl(byval s as TCCState ptr, _
                                            byval p as any ptr) as long
  ' return symbol value or NULL if not found
  tcc_get_symbol          as function cdecl(byval s as TCCState ptr, _
                                            byval name_ as const zstring ptr) as any ptr
  as TCCState ptr state
  private:
  as any ptr hLib 
end type

constructor TCC_DYNAMIC
  var oldPath = CurDir()
  ChDir(ExePath())
#ifdef __FB_WIN32__
 #ifndef __FB_64BIT__
   var libfolder ="lib\win32"
 #else
   var libfolder = "lib\win64"
 #endif
#else
 #ifndef __FB_64BIT__
   var libfolder = "lib/lin32"
 #else
   var libfolder = "lib/lin64"
 #endif
#endif

  ChDir(libfolder)
#ifdef __FB_WIN32__
  hLib = DyLibLoad("libtcc") ' libtcc.dll
#else
  hLib = DyLibLoad("tcc") ' libtcc.so
#endif

  if hLib then
    tcc_new                 = DyLibSymbol(hLib,"tcc_new")
    tcc_delete              = DyLibSymbol(hLib,"tcc_delete")
    tcc_set_lib_path        = DyLibSymbol(hLib,"tcc_set_lib_path")
    tcc_set_error_func      = DyLibSymbol(hLib,"tcc_set_error_func")
    tcc_set_options         = DyLibSymbol(hLib,"tcc_set_options")
    tcc_add_include_path    = DyLibSymbol(hLib,"tcc_add_include_path")
    tcc_add_sysinclude_path = DyLibSymbol(hLib,"tcc_add_sysinclude_path")
    tcc_define_symbol       = DyLibSymbol(hLib,"tcc_define_symbol")
    tcc_undefine_symbol     = DyLibSymbol(hLib,"tcc_undefine_symbol")
    tcc_add_file            = DyLibSymbol(hLib,"tcc_add_file")
    tcc_compile_string      = DyLibSymbol(hLib,"tcc_compile_string")
    tcc_set_output_type     = DyLibSymbol(hLib,"tcc_set_output_type")
    tcc_add_library_path    = DyLibSymbol(hLib,"tcc_add_library_path")
    tcc_add_library         = DyLibSymbol(hLib,"tcc_add_library")
    tcc_add_symbol          = DyLibSymbol(hLib,"tcc_add_symbol")
    tcc_output_file         = DyLibSymbol(hLib,"tcc_output_file")
    tcc_run                 = DyLibSymbol(hLib,"tcc_run")
    tcc_relocate            = DyLibSymbol(hLib,"tcc_relocate")
    tcc_get_symbol          = DyLibSymbol(hLib,"tcc_get_symbol")
    if tcc_new then state=tcc_new()
    if state=0 then
      DyLibFree hLib
      hLib = 0
    else
      tcc_add_library_path(state,libfolder)
    end if
  end if
  ChDir(oldPath)
end constructor 

destructor TCC_DYNAMIC
  if state then 
    tcc_delete(state)
  end if
end destructor

function TCC_DYNAMIC.IsAvailable as boolean
  return iif(state<>0,true,false)
end function

#endif ' TCC_DYNAMIC_BI
Last edited by D.J.Peters on Oct 12, 2022 18:30, edited 5 times in total.
D.J.Peters
Posts: 8586
Joined: May 28, 2005 3:28
Contact:

Re: libtcc 0.9.26 dynamic

Post by D.J.Peters »

First simple test.

Joshy

Code: Select all

#include "tcc_dynamic.bi"

' this function is called by the generated code
function myAdd cdecl (byval a as long, byval b as long) as long
  return a + b
end function

dim func as function cdecl (byval n as long) as long

dim as string c_code
c_code &=!"int fib(int n) {\n"
c_code &=!"  if (n <= 2)\n"
c_code &=!"    return 1;\n"
c_code &=!"  else\n"
c_code &=!"    return fib(n-1) + fib(n-2);\n"
c_code &=!"}\n"

c_code &=!"int foo(int n) {\n"
c_code &=!"  printf(\"Hello World!\\n\");\n"
c_code &=!"  printf(\"fib(%d) = %d\\n\", n, fib(n));\n"
c_code &=!"  printf(\"add(%d, %d) = %d\\n\", n, 2 * n, add(n, 2 * n));\n"
c_code &=!"  return 0;\n"
c_code &=!"}\n"


dim as TCC_DYNAMIC tcc
if tcc.IsAvailable=false then
  print "error: could not load libtcc !"
  beep : sleep : end 1
end if

' MUST BE CALLED before any compilation
tcc.tcc_set_output_type(tcc.state, TCC_OUTPUT_MEMORY)
if (tcc.tcc_compile_string(tcc.state, c_code) = -1) then
  print "error: tcc_compile_string !"
  beep : sleep : end 1
end if

' as a test, we add a symbol that the compiled program can use.
' You may also open a dll with tcc_add_dll() and use symbols from that */
tcc.tcc_add_symbol(tcc.state, "add",cptr(any ptr,@myAdd))
' relocate the code
if (tcc.tcc_relocate(tcc.state, TCC_RELOCATE_AUTO) < 0) then
  print "error: tcc_relocate !"
  beep : sleep : end 1
end if
' get entry symbol
func = tcc.tcc_get_symbol(tcc.state, "foo")
if (func=0) then
  print "error: tcc_get_symbol !"
  beep : sleep : end 1
end if
' run the code
func(32)
sleep
srvaldez
Posts: 3373
Joined: Sep 25, 2005 21:54

Re: libtcc 0.9.26 dynamic

Post by srvaldez »

Hi Joshy
thank you for this, now we can compile and run embedded C code, interesting :)
D.J.Peters
Posts: 8586
Joined: May 28, 2005 3:28
Contact:

Re: libtcc 0.9.26 dynamic

Post by D.J.Peters »

Yes it's a powerful runtime tool.

math expressions:
functions plotter
...

runtime language:
scripting engine (games, physics engine, graphics apps, GUI's, ...)
self optimising neuronal networks
sound generators
simulation of electronic circuits (analog, digital)
user defined hardware I/O
runtime generated apps or libraries (*.dll, *.so, *.exe )
dynamic syntax highlighting
...

it's a complete C compiler and can be used as a backend for your own funky new language

the usage I can imagine are countless

Joshy
gothon
Posts: 225
Joined: Apr 11, 2011 22:22

Re: libtcc 0.9.26 dynamic Windows Linux 32/64-bit.

Post by gothon »

Thank you D.J.Peters! I have been using this, and I can say that it is a very powerful tool. There are however 4 [err 3] minor issues I have with the bindings you made 'tcc_dynamic.bi'.

1) Memory leak!
Line 133 is

Code: Select all

    if tcc_new then state=tcc_new()
Every call to tcc_new should be paired with a corresponding call to tcc_delete to free the allocated memory.

2) Incorrect pointer type
Line 64-66

Code: Select all

  ' add a symbol to the compiled program
  tcc_add_symbol          as function cdecl(byval s as TCCState ptr, _
                                            byval name_ as const zstring ptr, byval value as const zstring ptr) as long
the value parameter of tcc_addsymbol is actually an untyped 'void*' or 'Any Ptr' in FB. In your example code you have to cast '@myAdd' to an Any Ptr to pass it to this function:

Code: Select all

tcc.tcc_add_symbol(tcc.state, "add",cptr(any ptr,@myAdd))
however with the type fixed you don't need any casting to suppress compiler warnings.

Code: Select all

tcc.tcc_add_symbol(tcc.state, "add",@myAdd)
3) You are using type Long instead of type Integer for what is actually the C type 'int' in the original header. The size of Long is always 32 bits, but the size of FB's 'Integer' and C's 'int' will become 64 bits in a 64 bit build. This type is only used as a return value except in the functions 'tcc_run' and 'tcc_set_output_type', so this problem would likely go undetected until someone called 'tcc_run' with the 64bit build.

4) You have placed code definitions for 'constructor TCC_DYNAMIC', 'destructor TCC_DYNAMIC', and 'function TCC_DYNAMIC.IsAvailable as boolean' inside the header, this makes it difficult to use the header in a project with multiple independently compiled source files, since you may need the declarations in multiple files but must only compile the definitions once to prevent linker collisions.

I think you added the TCC_DYNAMIC object so that you could manually control linking at run time. Doing this prevents the pain of trying to make linux able to locate the '.so' shared object file at run time. As I have learned is a real pain myself http://tldp.org/HOWTO/Program-Library-H ... aries.html

To address these issues I have made my own translation of the libtcc.h header you can copy from the code box below, which is free of any mistakes I'm aware of:
"libtcc.bi" (0.9.26 version)

Code: Select all

#IfNDef LIBTCC_BI
#Define LIBTCC_BI

#IfNDef LIBTCCAPI
 #Define LIBTCCAPI
#EndIf

Extern "C" Lib "tcc"

Type TCCState As Any

/' create a new TCC compilation context '/
Declare Function tcc_new LIBTCCAPI() As TCCState Ptr

/' free a TCC compilation context '/
Declare Sub tcc_delete LIBTCCAPI(s As TCCState Ptr)

/' set CONFIG_TCCDIR at runtime '/
Declare Sub tcc_set_lib_path LIBTCCAPI(s As TCCState Ptr, path As Const ZString Ptr)

/' set error/warning display callback '/
Type tcc_error_proc As Sub CDecl (opaque As Any Ptr, msg As Const ZString Ptr)
Declare Sub tcc_set_error_func LIBTCCAPI(s As TCCState Ptr, error_opaque As Any Ptr, error_sub As tcc_error_proc)

/' set options as from command line (multiple supported) '/
Declare Function tcc_set_options LIBTCCAPI(s As TCCState Ptr, str_ As Const ZString Ptr) As Long

'/'''''''''''''''''''''''''''''/
/' preprocessor '/

/' add include path '/
Declare Function tcc_add_include_path LIBTCCAPI(s As TCCState Ptr, pathname As Const ZString Ptr) As Long

/' add in system include path '/
Declare Function tcc_add_sysinclude_path LIBTCCAPI(s As TCCState Ptr, pathname As Const ZString Ptr) As Long

'/' define preprocessor symbol 'sym'. Can put optional value '/
Declare Sub tcc_define_symbol LIBTCCAPI(s As TCCState Ptr, sym As Const ZString Ptr, value As Const ZString Ptr)

'/' undefine preprocess symbol 'sym' '/
Declare Sub tcc_undefine_symbol LIBTCCAPI(s As TCCState Ptr, sym As Const ZString Ptr)

'/'''''''''''''''''''''''''''''/
/' compiling '/

/' add a file (C file, dll, object, library, ld script). Return -1 if error. '/
Declare Function tcc_add_file LIBTCCAPI(s As TCCState Ptr, filename As Const ZString Ptr) As Long

/' compile a string containing a C source. Return -1 if error. '/
Declare Function tcc_compile_string LIBTCCAPI(s As TCCState Ptr, buf As Const ZString Ptr) As Long

'/'''''''''''''''''''''''''''''/
/' linking commands '/

/' set output type. MUST BE CALLED before any compilation '/
Declare Function tcc_set_output_type LIBTCCAPI(s As TCCState Ptr, output_type As Long) As Long
#Define TCC_OUTPUT_MEMORY   0 /' output will be run in memory (default) '/
#Define TCC_OUTPUT_EXE      1 /' executable file '/
#Define TCC_OUTPUT_DLL      2 /' dynamic library '/
#Define TCC_OUTPUT_OBJ      3 /' object file '/
#Define TCC_OUTPUT_PREPROCESS 4 /' only preprocess (used internally) '/

/' equivalent to -Lpath option '/
Declare Function tcc_add_library_path LIBTCCAPI(s As TCCState Ptr, pathname As Const ZString Ptr) As Long

'/' the library name is the same as the argument of the '-l' option '/
Declare Function tcc_add_library LIBTCCAPI(s As TCCState Ptr, libraryname As Const ZString Ptr) As Long

/' add a symbol to the compiled program '/
Declare Function tcc_add_symbol LIBTCCAPI(s As TCCState Ptr, name_ As Const ZString Ptr, val_ As Const Any Ptr) As Long

/' output an executable, library or object file. DO NOT call
   tcc_relocate() before. '/
Declare Function tcc_output_file LIBTCCAPI(s As TCCState Ptr, filename As Const ZString Ptr) As Long

/' link and run main() function and return its value. DO NOT call
   tcc_relocate() before. '/
Declare Function tcc_run LIBTCCAPI(s As TCCState Ptr, argc As Long, argv As ZString Ptr Ptr) As Long

/' do all relocations (needed before using tcc_get_symbol()) '/
Declare Function tcc_relocate LIBTCCAPI(s1 As TCCState Ptr, ptr_ As Any Ptr) As Long
/' possible values for 'ptr':
   - TCC_RELOCATE_AUTO : Allocate and manage memory internally
   - NULL              : return required memory size for the step below
   - memory address    : copy code to memory passed by the caller
   returns -1 if error. '/
#Define TCC_RELOCATE_AUTO CPtr(Any Ptr, 1)

/' return symbol value or NULL if not found '/
Declare Function tcc_get_symbol LIBTCCAPI(s As TCCState Ptr, name_ As Const ZString Ptr) As Any Ptr

End Extern

#EndIf 'LIBTCC_BI
Also, I noticed that a version 0.9.27 of libtcc is out. I do not know what the differences are to 0.9.26 however the only difference I notice in the header is that the constants for the function 'tcc_set_output_type' are +1 greater than they were in 0.9.27.
"libtcc.bi" (0.9.27 version)

Code: Select all

#IfNDef LIBTCC_BI
#Define LIBTCC_BI

#IfNDef LIBTCCAPI
 #Define LIBTCCAPI
#EndIf

Extern "C" Lib "tcc"

Type TCCState As Any

/' create a new TCC compilation context '/
Declare Function tcc_new LIBTCCAPI() As TCCState Ptr

/' free a TCC compilation context '/
Declare Sub tcc_delete LIBTCCAPI(s As TCCState Ptr)

/' set CONFIG_TCCDIR at runtime '/
Declare Sub tcc_set_lib_path LIBTCCAPI(s As TCCState Ptr, path As Const ZString Ptr)

/' set error/warning display callback '/
Type tcc_error_proc As Sub CDecl (opaque As Any Ptr, msg As Const ZString Ptr)
Declare Sub tcc_set_error_func LIBTCCAPI(s As TCCState Ptr, error_opaque As Any Ptr, error_sub As tcc_error_proc)

/' set options as from command line (multiple supported) '/
Declare Function tcc_set_options LIBTCCAPI(s As TCCState Ptr, str_ As Const ZString Ptr) As Long

'/'''''''''''''''''''''''''''''/
/' preprocessor '/

/' add include path '/
Declare Function tcc_add_include_path LIBTCCAPI(s As TCCState Ptr, pathname As Const ZString Ptr) As Long

/' add in system include path '/
Declare Function tcc_add_sysinclude_path LIBTCCAPI(s As TCCState Ptr, pathname As Const ZString Ptr) As Long

'/' define preprocessor symbol 'sym'. Can put optional value '/
Declare Sub tcc_define_symbol LIBTCCAPI(s As TCCState Ptr, sym As Const ZString Ptr, value As Const ZString Ptr)

'/' undefine preprocess symbol 'sym' '/
Declare Sub tcc_undefine_symbol LIBTCCAPI(s As TCCState Ptr, sym As Const ZString Ptr)

'/'''''''''''''''''''''''''''''/
/' compiling '/

/' add a file (C file, dll, object, library, ld script). Return -1 if error. '/
Declare Function tcc_add_file LIBTCCAPI(s As TCCState Ptr, filename As Const ZString Ptr) As Long

/' compile a string containing a C source. Return -1 if error. '/
Declare Function tcc_compile_string LIBTCCAPI(s As TCCState Ptr, buf As Const ZString Ptr) As Long

'/'''''''''''''''''''''''''''''/
/' linking commands '/

/' set output type. MUST BE CALLED before any compilation '/
Declare Function tcc_set_output_type LIBTCCAPI(s As TCCState Ptr, output_type As Long) As Long
#Define TCC_OUTPUT_MEMORY   1 /' output will be run in memory (default) '/
#Define TCC_OUTPUT_EXE      2 /' executable file '/
#Define TCC_OUTPUT_DLL      3 /' dynamic library '/
#Define TCC_OUTPUT_OBJ      4 /' object file '/
#Define TCC_OUTPUT_PREPROCESS 5 /' only preprocess (used internally) '/

/' equivalent to -Lpath option '/
Declare Function tcc_add_library_path LIBTCCAPI(s As TCCState Ptr, pathname As Const ZString Ptr) As Long

'/' the library name is the same as the argument of the '-l' option '/
Declare Function tcc_add_library LIBTCCAPI(s As TCCState Ptr, libraryname As Const ZString Ptr) As Long

/' add a symbol to the compiled program '/
Declare Function tcc_add_symbol LIBTCCAPI(s As TCCState Ptr, name_ As Const ZString Ptr, val_ As Const Any Ptr) As Long

/' output an executable, library or object file. DO NOT call
   tcc_relocate() before. '/
Declare Function tcc_output_file LIBTCCAPI(s As TCCState Ptr, filename As Const ZString Ptr) As Long

/' link and run main() function and return its value. DO NOT call
   tcc_relocate() before. '/
Declare Function tcc_run LIBTCCAPI(s As TCCState Ptr, argc As Long, argv As ZString Ptr Ptr) As Long

/' do all relocations (needed before using tcc_get_symbol()) '/
Declare Function tcc_relocate LIBTCCAPI(s1 As TCCState Ptr, ptr_ As Any Ptr) As Long
/' possible values for 'ptr':
   - TCC_RELOCATE_AUTO : Allocate and manage memory internally
   - NULL              : return required memory size for the step below
   - memory address    : copy code to memory passed by the caller
   returns -1 if error. '/
#Define TCC_RELOCATE_AUTO CPtr(Any Ptr, 1)

/' return symbol value or NULL if not found '/
Declare Function tcc_get_symbol LIBTCCAPI(s As TCCState Ptr, name_ As Const ZString Ptr) As Any Ptr

End Extern

#EndIf 'LIBTCC_BI
Last edited by gothon on Feb 04, 2019 22:56, edited 1 time in total.
gothon
Posts: 225
Joined: Apr 11, 2011 22:22

Re: libtcc 0.9.26 dynamic Windows Linux 32/64-bit.

Post by gothon »

Also, does anyone know of a way to prevent libtcc from trying to locate and link the file 'libtcc1.a' to my memory compiled string at runtime? If I could just stop it from doing that, the build would be entirely in memory and have no need to read the disk at all once my program is running.
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: libtcc 0.9.26 dynamic Windows Linux 32/64-bit.

Post by MrSwiss »

@gothon,

your criticism below, in point 3) has the facts 'the wrong way around', because:

C's 'int' = FB's 'Long' (both 32 bit, fixed size) and,
C's 'long' = FB's 'Integer' (both dynamic sizing, aka: Ptr size), exception is: WIN64 (API)

See also: (data-type) comparison table, in the FB-Manual
gothon
Posts: 225
Joined: Apr 11, 2011 22:22

Re: libtcc 0.9.26 dynamic Windows Linux 32/64-bit.

Post by gothon »

@MrSwiss
Thank you for catching that. I was aware that the FB Integer type changes size to match pointer size, but the C end of things is harder to track down because of more compilers and variation between them including the common practice of 'int' being 16bits in 16bit builds.

I have edited my earlier post and corrected the header files in that post!
Post Reply