Project1

标题: 【应该是XP/VX/VA通用】TCC for RGSS [打印本页]

作者: gjz010    时间: 2020-5-5 15:23
标题: 【应该是XP/VX/VA通用】TCC for RGSS
本帖最后由 gjz010 于 2020-5-5 15:35 编辑

因为前两天有群友提出“Ruby和C交互太麻烦了”(又是pack struct又是dll),
想到“和C交互最容易的当然还是C”,突然就做了个这玩意。
把Bellard大手子的libtcc魔改了一份,正好塞进一个dll里(见附件)。
经过tcc加持以后,可以在运行时编译/连接/运行C代码片段。
应该也可以当单独的连接器使用(编译出静态库然后在RGSS里重定位,而非编译成DLL),感觉比Win32API调DLL要舒服一些。

完整脚本:
RUBY 代码复制下载
  1. =begin
  2. ###############################################################
  3. TCC Compiler for RGSS, v0.0.1
  4. TCC original author: Fabrice Bellard
  5. Porting: gjz010
  6.  
  7. Modified TCC source: [url]https://github.com/gjz010/tcc-nofs[/url]]https://github.com/gjz010/tcc-nofs
  8. UVFS source: [url]https://github.com/gjz010/uvfs-tcc[/url]]https://github.com/gjz010/uvfs-tcc
  9. ###############################################################
  10. API Document
  11. ###############################################################
  12. TCC::Compiler
  13. -----------------
  14. The main wrapper class for using compiler.
  15.  
  16. Methods:
  17.  
  18. logs, set_options, add_include_path, add_library_path, add_library,
  19. compile, define_macro, undef_macro, add_symbol, relocate,
  20. get_symbol, get_cwp_symbol, dispose
  21.  
  22. CallWndProc
  23. -----------------
  24. Three variants of CallWndProc are provided:
  25. TCC::call_window_proc_pl(addr, a, b=0)  # Call with one buffer and one integer.
  26. TCC::call_window_proc(addr, a=0, b=0)   # Call with two integers.
  27. TCC::call_window_proc_pp(addr, a, b)    # Call with two buffers.
  28.  
  29. On stdlib
  30. -----------------
  31. The porting provides under a virtual internal filesystem called UVFS.
  32. In most time you don't need to care about how UVFS works.
  33.  
  34. The stdlib provides tcc-libraries as-is:
  35. tcc@uvfs://include
  36. tcc@uvfs://include/winapi
  37. tcc@uvfs://lib/{gdi32.def, kernel32.def, libtcc1.a, msvcrt.def, user32.def}
  38. tcc@uvfs://lib/libtcc # Dangerous! Not the same as this libtcc, and not recommended.
  39.  
  40.  
  41. On relocation
  42. -----------------
  43. Imported data may require dllimport to work. See libtcc examples.
  44. CallWndProc-supported callback results in name-mangling.
  45. Use get_cwp_symbol instead.
  46.  
  47. TCC::TCC_Raw
  48. -----------------
  49.  
  50. Raw APIs for TCC. Use this if you are confident.
  51. All methods are prefixed with "r_".
  52.  
  53. ###############################################################
  54. Usage
  55. ###############################################################
  56.  
  57. # The C source code.
  58. SCRIPT= <<EOF
  59. #include <windows.h>
  60. #include <stdio.h>
  61. #include <stdlib.h>
  62. LRESULT CALLBACK foo(HWND a, UINT b, WPARAM c, LPARAM d){
  63.     char* buf=malloc(1024);
  64.     sprintf(buf, "Warm welcome from TCC!, %d+%d=%d\n", c, d, c+d);
  65.     MessageBox(0, buf, "Hi!", MB_OK);
  66.     free(buf);
  67.     return 0;
  68. }
  69.  
  70. EOF
  71.  
  72. # Compiler options.
  73. compiler=TCC::Compiler.new.set_options("-O2 -Wall -pedantic -Werror").
  74.           add_library("user32"). # Add user32 for MessageBox.
  75.           compile(SCRIPT). # Compile the string.
  76.           relocate # And then relocate.
  77.           
  78. # Call the compiled function with CallWindowProc.
  79. TCC::call_window_proc(compiler.get_cwp_symbol("foo"), 1, 2)
  80.  
  81. # Dispose the compiler.
  82. compiler.dispose
  83. ###############################################################
  84. Known Issues
  85. ###############################################################
  86.  
  87. 1. "-Werror" not working.
  88. 2. Bad options into set_options will cause a silent exit.
  89.  
  90. ###############################################################
  91. =end
  92. module TCC
  93.   # Raw calls to TCC Compiler.
  94.   module TCC_Raw
  95.     TCC_CALLS_TABLE =
  96.     [
  97.       ["L",:r_tcc_new, "V"],
  98.       ["V",:r_tcc_delete, "L"],
  99.       ["V",:r_tcc_set_lib_path, "LP"],
  100.       ["V",:r_tcc_set_error_func, "LLL"],
  101.       ["V",:r_tcc_set_options, "LP"],
  102.       ["L",:r_tcc_add_include_path, "LP"],
  103.       ["L",:r_tcc_add_sysinclude_path, "LP"],
  104.       ["V",:r_tcc_define_symbol, "LPP"],
  105.       ["V",:r_tcc_undefine_symbol, "LP"],
  106.       ["L",:r_tcc_add_file, "LP"],
  107.       ["L",:r_tcc_compile_string, "LP"],
  108.       ["L",:r_tcc_set_output_type, "LL"],
  109.       ["L",:r_tcc_add_library_path, "LP"],
  110.       ["L",:r_tcc_add_library, "LP"],
  111.       ["L",:r_tcc_add_symbol, "LPL"],
  112.       ["L",:r_tcc_output_file, "LP"],
  113.       ["L",:r_tcc_run, "LLP"],
  114.       ["L",:r_tcc_relocate, "LL"],
  115.       ["L",:r_tcc_get_symbol, "LP"],
  116.       ["V",:initialize_uvfs, "V"]
  117.     ]
  118.     for v in TCC_CALLS_TABLE
  119.       begin
  120.         api=Win32API.new "libtcc.dll",v[1].to_s,v[2],v[0]
  121.         lambda {|a| define_method(v[1]) do |*args| a.call(*args) end}.call(api)
  122.       end
  123.     end
  124.     TCC_OUTPUT_MEMORY = 1
  125.     TCC_OUTPUT_EXE = 2
  126.     TCC_OUTPUT_DLL = 3
  127.     TCC_OUTPUT_OBJ = 4
  128.     TCC_OUTPUT_PREPROCESS = 5
  129.  
  130.     TCC_RELOCATE_AUTO = 1
  131.     # CWP for calling into function.
  132.     CallWindowProc = Win32API.new 'user32', 'CallWindowProcW', 'pLLLL', 'L'
  133.     CallWindowProcPL = Win32API.new 'user32', 'CallWindowProcW', 'pLLPL', 'L'
  134.     CallWindowProcPP = Win32API.new 'user32', 'CallWindowProcW', 'pLLPP', 'L'
  135.     extend self
  136.   end
  137.   TCC_Raw::initialize_uvfs()
  138.  
  139.   class IllegalStateError  < StandardError
  140.   end
  141.   class CompileError  < StandardError
  142.     attr_reader :log
  143.     def initialize(log)
  144.       @log=log
  145.     end
  146.     def to_s
  147.       @log.to_s
  148.     end
  149.   end
  150.   class RelocationError  < StandardError
  151.     attr_reader :log
  152.     def initialize(log)
  153.       @log=log
  154.     end
  155.     def to_s
  156.       @log.to_s
  157.     end
  158.   end
  159.   class Compiler
  160.     STATE_IDLE=0
  161.     STATE_COMPILED=1
  162.     STATE_RELOCATED=2
  163.     STATE_READY=3
  164.     def initialize
  165.       @s=TCC_Raw::r_tcc_new()
  166.       @state=0
  167.       initialize_error_handler
  168.       TCC_Raw::r_tcc_set_lib_path(@s, "nul@uvfs://")
  169.       add_include_path("tcc@uvfs://include").
  170.           add_include_path("tcc@uvfs://include/winapi").
  171.           add_library_path("tcc@uvfs://lib")
  172.       TCC_Raw::r_tcc_set_output_type(@s, TCC_Raw::TCC_OUTPUT_MEMORY)
  173.       @buffer=[]
  174.     end
  175.     def logs
  176.       @buffer
  177.     end
  178.     def initialize_error_handler
  179.       # Do nothing.
  180.     end
  181.     def fetch_log
  182.       # Do nothing
  183.     end
  184.     def add_include_path(path)
  185.       if @state!=STATE_IDLE
  186.         raise IllegalStateError.new
  187.       end
  188.       TCC_Raw::r_tcc_add_include_path(@s, path)
  189.  
  190.       return self
  191.     end
  192.     def add_library_path(path)
  193.       if @state!=STATE_IDLE
  194.         raise IllegalStateError.new
  195.       end
  196.       TCC_Raw::r_tcc_add_library_path(@s, path)
  197.       return self
  198.     end
  199.     def add_library(lib)
  200.       if @state!=STATE_IDLE
  201.         raise IllegalStateError.new
  202.       end
  203.       TCC_Raw::r_tcc_add_library(@s, lib)
  204.       return self
  205.     end
  206.     def set_options(options)
  207.       if @state!=STATE_IDLE
  208.         raise IllegalStateError.new
  209.       end
  210.       TCC_Raw::r_tcc_set_options(@s, options)
  211.       return self
  212.     end
  213.     def compile(script)
  214.       if @state!=STATE_IDLE
  215.         raise IllegalStateError.new
  216.       end
  217.       ret=TCC_Raw::r_tcc_compile_string(@s, script)
  218.       fetch_log
  219.       if ret==-1
  220.         raise (CompileError.new(@buffer))
  221.       end
  222.       @state=STATE_COMPILED
  223.       return self
  224.     end
  225.     def define_macro(sym, v)
  226.       if @state!=STATE_IDLE
  227.         raise IllegalStateError.new
  228.       end
  229.       TCC_Raw::r_tcc_add_symbol(@s, sym, v)
  230.       return self
  231.     end
  232.     def undef_macro(sym)
  233.       if @state!=STATE_IDLE
  234.         raise IllegalStateError.new
  235.       end
  236.       TCC_Raw::r_tcc_undefine_symbol(@s, sym)
  237.       return self
  238.     end
  239.     def add_symbol(sym, addr)
  240.       if @state!=STATE_COMPILED
  241.         raise IllegalStateError.new
  242.       end
  243.       TCC_Raw::r_tcc_add_symbol(@s, sym, addr)
  244.       return self
  245.     end
  246.     def relocate
  247.       if @state!=STATE_COMPILED
  248.         raise IllegalStateError.new
  249.       end
  250.       ret=TCC_Raw::r_tcc_relocate(@s, TCC_Raw::TCC_RELOCATE_AUTO)
  251.       fetch_log
  252.       if ret<0
  253.         raise (RelocationError.new(@buffer))
  254.       end
  255.       @state=STATE_READY
  256.       return self
  257.     end
  258.     def dispose
  259.       TCC_Raw::r_tcc_delete(@s)
  260.     end
  261.     def get_symbol(sym)
  262.       if @state!=STATE_READY
  263.         raise IllegalStateError.new
  264.       end
  265.       s=TCC_Raw::r_tcc_get_symbol(@s, sym)
  266.       s
  267.     end
  268.     def get_cwp_symbol(sym)
  269.       get_symbol("_"+sym+"@16")
  270.     end
  271.   end
  272.   def call_window_proc(addr, a=0, b=0)
  273.     TCC_Raw::CallWindowProc.call addr,0,0,a,b
  274.   end
  275.   def call_window_proc_pl(addr, a, b=0)
  276.     TCC_Raw::CallWindowProcPL.call addr,0,0,a,b
  277.   end
  278.   def call_window_proc_pp(addr, a, b)
  279.     TCC_Raw::CallWindowProcPP.call addr,0,0,a,b
  280.   end
  281.  
  282.  
  283.   def log_handler
  284.     tcc=TCC::Compiler.new.compile( <<EOF
  285. #include <windows.h>
  286. #include <stdio.h>
  287. #include <stdlib.h>
  288. #include <string.h>
  289. const char* buffer=0;
  290. void tcc_error_handler(void* arg, const char* msg){
  291.  
  292.     int n=0;
  293.     if(buffer==0){
  294.       n=strlen(msg)+2;
  295.       buffer=malloc(n);
  296.       strcpy(buffer, msg);
  297.       buffer[n-2]='\n';
  298.       buffer[n-1]=0;
  299.     }else{
  300.       n=strlen(msg)+2+strlen(buffer);
  301.       buffer=realloc(buffer, n);
  302.       strcat(buffer, msg);
  303.       buffer[n-2]='\n';
  304.       buffer[n-1]=0;
  305.     }
  306.  
  307.  
  308. }
  309.  
  310. LRESULT CALLBACK move_tcc_log(HWND a, UINT b, WPARAM addrlog, LPARAM d){
  311.     if(buffer==0) return 0;
  312.     if(addrlog==0){
  313.         return strlen(buffer)+1;
  314.     }else{
  315.         strcpy(addrlog, buffer);
  316.         free(buffer);
  317.         int l=strlen(buffer)+1;
  318.         buffer=0;
  319.         return l;
  320.     }
  321. }
  322. EOF
  323.     ).relocate
  324.     handler=tcc.get_symbol("tcc_error_handler")
  325.     moveback=tcc.get_cwp_symbol("move_tcc_log")
  326.     {:handler=>handler, :moveback=>moveback}
  327.   end
  328.   extend self
  329.  
  330.   LOG_HANDLER = TCC::log_handler
  331.  
  332.   class Compiler
  333.     def initialize_error_handler
  334.       TCC_Raw::r_tcc_set_error_func(@s, 0, LOG_HANDLER[:handler])
  335.     end
  336.     def fetch_log
  337.       len=TCC::call_window_proc(LOG_HANDLER[:moveback])
  338.       if len==0
  339.         return false
  340.       end
  341.       buffer = 0.chr * len
  342.       TCC::call_window_proc_pl(LOG_HANDLER[:moveback], buffer)
  343.       @buffer+=(buffer.split "\n")
  344.       return true
  345.     end
  346.   end
  347.  
  348. end


需要libtcc.dll:
libtcc.7z (1.26 MB, 下载次数: 48)


作者: 有丘直方    时间: 2020-5-5 15:28
螃蟹公 nb
作者: zyf722    时间: 2020-5-5 20:51
tql 前排
作者: 574656549    时间: 2020-6-6 14:48
提示: 作者被禁止或删除 内容自动屏蔽




欢迎光临 Project1 (https://rpg.blue/) Powered by Discuz! X3.1