Integrate TinyC libtcc.lib into PureBasic

Just starting out? Need help? Post your questions and find answers here.
JoeC4281
User
User
Posts: 32
Joined: Fri Aug 06, 2021 4:47 pm

Integrate TinyC libtcc.lib into PureBasic

Post by JoeC4281 »

I am running;
PureBasic 6.00 LTS (Windows - x64)
Windows 10 [Version 10.0.19044.3086]
I am a non-expert with many things PureBasic.

I would like to integrate the Tiny C (https://bellard.org/tcc/)
libtcc.lib (https://bellard.org/tcc/tcc-doc.html#Libtcc)
into PureBasic.

A search of the PureBasic forums returned one match for libtcc.

idle said on 2022/01/13 that he was looking into libtcc to see if it was usable.

My goal is to create a simple console program that will take int main(){printf("Hello World.\n"); return 0;}
compile it in memory,
run it,
and have "Hello World" displayed on the console screen.

Yes,
I could use RunProgram (https://www.purebasic.com/documentation ... gram.html) to run TCC.EXE,
and compile the C-code using that method,
but I would like to learn how to integrate the libtcc.lib into PureBasic,
and run the code that way instead.

The following (incomplete) code is what I have cobbled together,
but it does not work,
as pointers are not my friends.

Code: Select all

EnableExplicit

Global rc.l, s.s

#TCC_OUTPUT_MEMORY     = 1
#TCC_OUTPUT_EXE        = 2
#TCC_OUTPUT_DLL        = 3
#TCC_OUTPUT_OBJ        = 4
#TCC_OUTPUT_PREPROCESS = 5

ImportC "libtcc.lib"
;   /* compile a string containing a C source. Return -1 If error. */
; LIBTCCAPI int tcc_compile_string(TCCState *s, const char *buf);  
  tcc_compile_string(*s, *buf) As "tcc_compile_string"
  
; /* create a new TCC compilation context */
; LIBTCCAPI TCCState *tcc_new(void);
  tcc_new() As "tcc_new"
  
; /* set output type. MUST BE CALLED before any compilation */
; LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type);
; #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) */  tcc_set_output_type(*s, int) As "tcc_output_type"
  tcc_set_output_type(s,i) As "tcc_set_output_type"
  
; /* link And run main() function And Return its value. DO Not call
;    tcc_relocate() before. */
; LIBTCCAPI int tcc_run(TCCState *s, int argc, char **argv);  
  tcc_run() As "tcc_run"
EndImport

rc.l = tcc_new()
rc.l = tcc_set_output_type(s, #TCC_OUTPUT_MEMORY)
rc.l = tcc_compile_string("int main(){printf("""Hello World.\n"""); return 0;}")
rc.l = tcc_run(s,argc,argv)
For the past couple of days,
I have been reading,
referencing other code I have found in the forum,
but I still cannot grasp what goes where.

I'm coming up on my 61st orbit around the sun,
so any constructive assistance would be appreciated.

Regards and Thanks,

Joe
infratec
Always Here
Always Here
Posts: 7577
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Integrate TinyC libtcc.lib into PureBasic

Post by infratec »

This works ... but with the dll, since I did not found a .lib file

Code: Select all

;
; libtcc.pbi
;


CompilerIf #PB_Compiler_IsMainFile
  EnableExplicit
CompilerEndIf


PrototypeC.i Prototype_tcc_new()
PrototypeC Prototype_tcc_delete(*s)
PrototypeC Prototype_tcc_set_lib_path(*s, path.p-Ascii)
PrototypeC Prototype_tcc_error_func(*opaque, msg.p-Ascii)
PrototypeC Prototype_tcc_set_error_func(*s, *error_opaque, error_func.Prototype_tcc_error_func)
PrototypeC Prototype_tcc_set_options(*s, str.p-Ascii)

; preprocessor
PrototypeC.i Prototype_tcc_add_include_path(*s, pathname.p-Ascii)
PrototypeC.i Prototype_tcc_add_sysinclude_path(*s, pathname.p-Ascii)
PrototypeC Prototype_tcc_define_symbol(*s, sym.p-Ascii, value.p-Ascii)
PrototypeC Prototype_tcc_undefine_symbol(*s, sym.p-Ascii)

; compiling
PrototypeC.i Prototype_tcc_add_file(*s, filename.p-Ascii)
PrototypeC.i Prototype_tcc_compile_string(*s, buf.p-Ascii)

; linking
PrototypeC.i Prototype_tcc_set_output_type(*s, output_type.l)
#tcc_OUTPUT_MEMORY     = 1
#tcc_OUTPUT_EXE        = 2
#tcc_OUTPUT_DLL        = 3
#tcc_OUTPUT_OBJ        = 4
#tcc_OUTPUT_PREPROCESS = 5

PrototypeC.i Prototype_tcc_add_library_path(*s, pathname.p-Ascii)
PrototypeC.i Prototype_tcc_add_library(*s, libraryname.p-Ascii)
PrototypeC.i Prototype_tcc_add_symbol(*s, name.p-Ascii, val.p-Ascii)
PrototypeC.i Prototype_tcc_output_file(*s, filename.p-Ascii)
PrototypeC.i Prototype_tcc_run(*s, argc.l, *argv)
PrototypeC.i Prototype_tcc_relocate(*s1, *ptr)
#tcc_RELOCATE_AUTO = 1
PrototypeC.i Prototype_tcc_get_symbol(*s, name.p-Ascii)




Global tcc_library.i

Global tcc_new.Prototype_tcc_new
Global tcc_delete.Prototype_tcc_delete
Global tcc_set_lib_path.Prototype_tcc_set_lib_path
Global tcc_set_error_func.Prototype_tcc_set_error_func
Global tcc_set_options.Prototype_tcc_set_options

Global tcc_add_include_path.Prototype_tcc_add_include_path
Global tcc_add_sysinclude_path.Prototype_tcc_add_sysinclude_path
Global tcc_define_symbol.Prototype_tcc_define_symbol
Global tcc_undefine_symbol.Prototype_tcc_undefine_symbol

Global tcc_add_file.Prototype_tcc_add_file
Global tcc_compile_string.Prototype_tcc_compile_string

Global tcc_set_output_type.Prototype_tcc_set_output_type
Global tcc_add_library_path.Prototype_tcc_add_library_path
Global tcc_add_library.Prototype_tcc_add_library
Global tcc_add_symbol.Prototype_tcc_add_symbol
Global tcc_output_file.Prototype_tcc_output_file
Global tcc_run.Prototype_tcc_run
Global tcc_relocate.Prototype_tcc_relocate
Global tcc_get_symbol.Prototype_tcc_get_symbol




Procedure.i tcc_init()
  
  If Not tcc_library
    
    CompilerIf #PB_Compiler_32Bit
      tcc_library = OpenLibrary(#PB_Any, "x86\libtcc.dll")
    CompilerElse
      tcc_library = OpenLibrary(#PB_Any, "x64\libtcc.dll")
    CompilerEndIf
    
    If tcc_library
      tcc_new = GetFunction(tcc_library, "tcc_new")
      tcc_delete = GetFunction(tcc_library, "tcc_delete")
      tcc_set_lib_path = GetFunction(tcc_library, "tcc_set_lib_path")
      tcc_set_error_func = GetFunction(tcc_library, "tcc_set_error_func")
      tcc_set_options = GetFunction(tcc_library, "tcc_set_options")
      
      tcc_add_include_path = GetFunction(tcc_library, "tcc_add_include_path")
      tcc_add_sysinclude_path = GetFunction(tcc_library, "tcc_add_sysinclude_path")
      tcc_define_symbol = GetFunction(tcc_library, "tcc_define_symbol")
      tcc_undefine_symbol = GetFunction(tcc_library, "tcc_undefine_symbol")
      
      tcc_add_file = GetFunction(tcc_library, "tcc_add_file")
      tcc_compile_string = GetFunction(tcc_library, "tcc_compile_string")
      
      tcc_set_output_type = GetFunction(tcc_library, "tcc_set_output_type")
      tcc_add_library_path = GetFunction(tcc_library, "tcc_add_library_path")
      tcc_add_symbol = GetFunction(tcc_library, "tcc_add_symbol")
      tcc_output_file = GetFunction(tcc_library, "tcc_output_file")
      tcc_run = GetFunction(tcc_library, "tcc_run")
      tcc_relocate = GetFunction(tcc_library, "tcc_relocate")
      tcc_get_symbol = GetFunction(tcc_library, "tcc_get_symbol")
    EndIf
    
  EndIf
  
  ProcedureReturn tcc_library
  
EndProcedure


Procedure tcc_free()
  If tcc_library
    CloseLibrary(tcc_library)
    tcc_library = 0
  EndIf
EndProcedure



CompilerIf #PB_Compiler_IsMainFile
  
  CompilerIf #PB_Compiler_ExecutableFormat <> #PB_Compiler_Console
    CompilerError "You need to set the executable format to console in compiler options"
  CompilerEndIf
  
  ProcedureC error_func(*opaque, *msg)
    Debug PeekS(*msg, -1, #PB_Ascii)
  EndProcedure
  
  
  Define *s, ReturnValue.i
  
  OpenConsole()
  
  If tcc_Init()
    *s = tcc_new()
    If *s
      tcc_set_output_type(*s, #tcc_OUTPUT_MEMORY)
      
      tcc_set_error_func(*s, 0, @error_func())
      
      tcc_add_library_path(*s, "lib")
      tcc_add_include_path(*s, "include")
      
      If tcc_compile_string(*s, ~"#include <tcclib.h>\n int main(){\n printf(\"Hello World.\n\");\n return 0;\n}\n") <> -1
        ReturnValue =  tcc_run(*s, 0, #Null)
        Debug "Returned: " + Str(ReturnValue)
      EndIf
      tcc_delete(*s)
    Else
      Debug "Could not create tcc state"
    EndIf
    
    tcc_free()
  Else
    Debug "Not able to load dll"
  EndIf
  
  PrintN(#LF$ + "Press RETURN to end")
  Input()
  
CompilerEndIf
If you create the directories lib and include and put the reqired files inside,
it compiles and run without errors.

You have to compile it as Console application, then you can see the output in the console window.
infratec
Always Here
Always Here
Posts: 7577
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Integrate TinyC libtcc.lib into PureBasic

Post by infratec »

To be clear:

The directory structure should look like this:

[include] -> tcclib.h, stddef.h, stdarg.h, ...
[lib] -> libtcc1-32.a, libtcc1-64.a
[x64] -> libtcc.dll
[x86] -> libtcc.dll
libtcc.pbi
User avatar
chi
Addict
Addict
Posts: 1087
Joined: Sat May 05, 2007 5:31 pm
Location: Austria

Re: Integrate TinyC libtcc.lib into PureBasic

Post by chi »

Great work, infratec! You could also create an import lib from the def file and use it like this...

Code: Select all

; polib.exe /MACHINE:x64 /DEF:libtcc.def /OUT:libtcc.lib

CompilerIf #PB_Compiler_ExecutableFormat <> #PB_Compiler_Console
  CompilerError "You need to set the executable format to console in compiler options"
CompilerEndIf

ImportC "libtcc.lib"
  tcc_new.i()
  tcc_set_output_type.i(*s, output_type.l)
  tcc_compile_string.i(*s, buf.p-Ascii)
  tcc_run.i(*s, argc.l, *argv)
  tcc_delete(*s)
EndImport

*s = tcc_new()
tcc_set_output_type(*s, 1)
tcc_compile_string(*s, ~"int printf(const char *format, ...);\n\n int main(){\n printf(\"Hello World.\n\");\n return 0;\n}\n")
tcc_run(*s, 0, #Null)
tcc_delete(*s)

CallDebugger
Et cetera is my worst enemy
infratec
Always Here
Always Here
Posts: 7577
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Integrate TinyC libtcc.lib into PureBasic

Post by infratec »

But then you need to copy the right dll in the main directory.

Code: Select all

;
; libtcc_lib.pbi
;
; you have to use the correct libtcc.def file
; x86>c:polib.exe /MACHINE:x86 /DEF:libtcc.def /OUT:libtcc.lib
; x64>c:polib.exe /MACHINE:x64 /DEF:libtcc.def /OUT:libtcc.lib
;


CompilerIf #PB_Compiler_IsMainFile
  EnableExplicit
CompilerEndIf

#tcc_OUTPUT_MEMORY     = 1
#tcc_OUTPUT_EXE        = 2
#tcc_OUTPUT_DLL        = 3
#tcc_OUTPUT_OBJ        = 4
#tcc_OUTPUT_PREPROCESS = 5

#tcc_RELOCATE_AUTO = 1


PrototypeC Prototype_tcc_error_func(*opaque, msg.p-Ascii)


CompilerIf #PB_Compiler_32Bit
  ImportC "x86\libtcc.lib"
  CompilerElse
    ImportC "x64\libtcc.lib"
    CompilerEndIf
    
    tcc_new.i()
    tcc_delete(*s)
    tcc_set_lib_path(*s, path.p-Ascii)
    tcc_set_error_func(*s, *error_opaque, error_func.Prototype_tcc_error_func)
    tcc_set_options(*s, str.p-Ascii)
    
    ; preprocessor
    tcc_add_include_path.i(*s, pathname.p-Ascii)
    tcc_add_sysinclude_path.i(*s, pathname.p-Ascii)
    tcc_define_symbol(*s, sym.p-Ascii, value.p-Ascii)
    tcc_undefine_symbol(*s, sym.p-Ascii)
    
    ; compiling
    tcc_add_file.i(*s, filename.p-Ascii)
    tcc_compile_string.i(*s, buf.p-Ascii)
    
    ; linking
    tcc_set_output_type.i(*s, output_type.l)
    
    tcc_add_library_path.i(*s, pathname.p-Ascii)
    tcc_add_library.i(*s, libraryname.p-Ascii)
    tcc_add_symbol.i(*s, name.p-Ascii, val.p-Ascii)
    tcc_output_file.i(*s, filename.p-Ascii)
    tcc_run.i(*s, argc.l, *argv)
    tcc_relocate.i(*s1, *ptr)
    
    tcc_get_symbol.i(*s, name.p-Ascii)
    
  EndImport
  
  
  
  
  CompilerIf #PB_Compiler_IsMainFile
    
    CompilerIf #PB_Compiler_ExecutableFormat <> #PB_Compiler_Console
      CompilerError "You need to set the executable format to console in compiler options"
    CompilerEndIf
    
    ProcedureC error_func(*opaque, *msg)
      Debug PeekS(*msg, -1, #PB_Ascii)
    EndProcedure
    
    
    Define *s, ReturnValue.i
    
    OpenConsole()
    
    
    *s = tcc_new()
    If *s
      tcc_set_output_type(*s, #tcc_OUTPUT_MEMORY)
      
      tcc_set_error_func(*s, 0, @error_func())
      
      tcc_add_library_path(*s, "lib")
      tcc_add_include_path(*s, "include")
      
      If tcc_compile_string(*s, ~"#include <tcclib.h>\n int main(){\n printf(\"Hello World.\n\");\n return 0;\n}\n") <> -1
        ReturnValue =  tcc_run(*s, 0, #Null)
        Debug "Returned: " + Str(ReturnValue)
      EndIf
      tcc_delete(*s)
    Else
      Debug "Could not create tcc state"
    EndIf
    
    PrintN(#LF$ + "Press RETURN to end")
    Input()
    
  CompilerEndIf
JoeC4281
User
User
Posts: 32
Joined: Fri Aug 06, 2021 4:47 pm

Re: Integrate TinyC libtcc.lib into PureBasic

Post by JoeC4281 »

chi wrote: Thu Sep 21, 2023 12:39 pm Great work, infratec! You could also create an import lib from the def file and use it like this...

Code: Select all

; polib.exe /MACHINE:x64 /DEF:libtcc.def /OUT:libtcc.lib
Instead of creating my own libtcc.lib,
I used the .lib that comes with Tiny C,
compiled your code, and success.

Thankyou, chi, for your help.

Thanks also to infratec for his alternate method, using the .dll

Joe
Little John
Addict
Addict
Posts: 4777
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: Integrate TinyC libtcc.lib into PureBasic

Post by Little John »

Hi, I've got a question just out of curiosity:
Since version 6.0 PureBasic has a C backend, which AFAIK also can be used directly. What is the advantage of using another C compiler, such as TinyC?
Jeromyal
Enthusiast
Enthusiast
Posts: 216
Joined: Wed Jul 17, 2013 8:49 am

Re: Integrate TinyC libtcc.lib into PureBasic

Post by Jeromyal »

Little John wrote: Thu Sep 21, 2023 2:19 pm Hi, I've got a question just out of curiosity:
Since version 6.0 PureBasic has a C backend, which AFAIK also can be used directly. What is the advantage of using another C compiler, such as TinyC?
I was wondering that myself, however TCC has the ability to compile and run code directly in memory. That is how CToy works with TCC.
So, I myself would create TCC inegration with my own CToy like editor in PureBasic. Edit > Run in ram > or compile as application from a nice interface.

That being said, I do not know if gcc can't also compile and execute in ram. I have not bothered to look it up yet.

edit:
Actually I may be wrong about compiling and running c code in memory. There is more like a runtime involved. But CToy has some sort of ability for the user to create persistent memory space to preserve information between code changes. TCC is a fast little compiler so it is understandable that CToy was thus birthed.
infratec
Always Here
Always Here
Posts: 7577
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Integrate TinyC libtcc.lib into PureBasic

Post by infratec »

PB code is fixed, you can not change it after compile time.

With libtcc or lua or ... you can modify and run the code at runtime.
Or read it from a file or use code from an EditorGadget()
Or ...
User avatar
chi
Addict
Addict
Posts: 1087
Joined: Sat May 05, 2007 5:31 pm
Location: Austria

Re: Integrate TinyC libtcc.lib into PureBasic

Post by chi »

JoeC4281 wrote: Thu Sep 21, 2023 1:28 pm Instead of creating my own libtcc.lib,
I used the .lib that comes with Tiny C
There is no .lib in tcc-0.9.27-win64-bin.zip ;)
Little John wrote: Thu Sep 21, 2023 2:19 pm Hi, I've got a question just out of curiosity:
Since version 6.0 PureBasic has a C backend, which AFAIK also can be used directly. What is the advantage of using another C compiler, such as TinyC?
Different compilers have different optimizations... It's quite fun to play around, compare and finally deliver the best performing exe.
Et cetera is my worst enemy
JoeC4281
User
User
Posts: 32
Joined: Fri Aug 06, 2021 4:47 pm

Re: Integrate TinyC libtcc.lib into PureBasic

Post by JoeC4281 »

chi wrote: Thu Sep 21, 2023 6:46 pm There is no .lib in tcc-0.9.27-win64-bin.zip ;)
You are correct.

I checked the date on libtcc.lib,
and it would appear that I created libtcc.lib a while back.

Now that I have a working console app,
I hope to create a plugin (https://jpsoft.com/all-downloads/tcc-plugins.html),
integrating TinyC into Take Command Console,
so that it is usable from the console for C one-liners,
or simple scripts that can be made hybrid with .BTMs

Joe
User avatar
idle
Always Here
Always Here
Posts: 5836
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: Integrate TinyC libtcc.lib into PureBasic

Post by idle »

@ infratec and @chi
You're both legends.
Patrice Terrier
User
User
Posts: 21
Joined: Sun Aug 10, 2003 11:45 am
Location: France
Contact:

Re: Integrate TinyC libtcc.lib into PureBasic

Post by Patrice Terrier »

Hello

I am not a PureBasic programmer, however I have used TClib.lib with success, and I was able to produce very small binary executable using it.
There is a dedicated section on my private forum here
http://www.objreader.com/index.php?board=19.0

anf here is a C++ 64-bit GDImage tutor producing a binary of only 27 Kb using TCLib.lib
http://www.objreader.com/index.php?topi ... 75#msg6375
Patrice Terrier
objreader@gmail.com
http://www.objreader.com
Addon: WinLIFT (Skin Engine), GDImage (Graphic library), ObjReader (3D engine)
User avatar
idle
Always Here
Always Here
Posts: 5836
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: Integrate TinyC libtcc.lib into PureBasic

Post by idle »

Hi Patrice
We're not stopping you from becoming a purebasic programmer. :wink:
(Didn't you make opengl tlb for vb6 back in the day?)
Patrice Terrier
User
User
Posts: 21
Joined: Sun Aug 10, 2003 11:45 am
Location: France
Contact:

Re: Integrate TinyC libtcc.lib into PureBasic

Post by Patrice Terrier »

idle

No, I don't want to become a purebasic programmer, because I am using only the low level procedural SDK API, that is the only common denominator understood with the different languages I am using.
I never worked with VB6.
About OpenGL I wrote my own 3D engine, and many audio visual plugins.
Here is my Behance page showing some wavefront .obj 3D models designed specifically for my ObjReader freeware.
https://www.behance.net/pterrier948d
All models have been created or reworked with Maxon C4D, to use my specific ObjReader shader.
Patrice Terrier
objreader@gmail.com
http://www.objreader.com
Addon: WinLIFT (Skin Engine), GDImage (Graphic library), ObjReader (3D engine)
Post Reply