赞 | 3 |
VIP | 1 |
好人卡 | 0 |
积分 | 16 |
经验 | 1887 |
最后登录 | 2024-3-14 |
在线时间 | 277 小时 |
Lv3.寻梦者
- 梦石
- 1
- 星屑
- 644
- 在线时间
- 277 小时
- 注册时间
- 2008-3-30
- 帖子
- 77
|
加入我们,或者,欢迎回来。
您需要 登录 才可以下载或查看,没有帐号?注册会员
x
本帖最后由 gjz010 于 2020-5-5 15:35 编辑
因为前两天有群友提出“Ruby和C交互太麻烦了”(又是pack struct又是dll),
想到“和C交互最容易的当然还是C”,突然就做了个这玩意。
把Bellard大手子的libtcc魔改了一份,正好塞进一个dll里(见附件)。
经过tcc加持以后,可以在运行时编译/连接/运行C代码片段。
应该也可以当单独的连接器使用(编译出静态库然后在RGSS里重定位,而非编译成DLL),感觉比Win32API调DLL要舒服一些。
完整脚本:
=begin ############################################################### TCC Compiler for RGSS, v0.0.1 TCC original author: Fabrice Bellard Porting: gjz010 Modified TCC source: [url]https://github.com/gjz010/tcc-nofs[/url]]https://github.com/gjz010/tcc-nofs UVFS source: [url]https://github.com/gjz010/uvfs-tcc[/url]]https://github.com/gjz010/uvfs-tcc ############################################################### API Document ############################################################### TCC::Compiler ----------------- The main wrapper class for using compiler. Methods: logs, set_options, add_include_path, add_library_path, add_library, compile, define_macro, undef_macro, add_symbol, relocate, get_symbol, get_cwp_symbol, dispose CallWndProc ----------------- Three variants of CallWndProc are provided: TCC::call_window_proc_pl(addr, a, b=0) # Call with one buffer and one integer. TCC::call_window_proc(addr, a=0, b=0) # Call with two integers. TCC::call_window_proc_pp(addr, a, b) # Call with two buffers. On stdlib ----------------- The porting provides under a virtual internal filesystem called UVFS. In most time you don't need to care about how UVFS works. The stdlib provides tcc-libraries as-is: tcc@uvfs://include tcc@uvfs://include/winapi tcc@uvfs://lib/{gdi32.def, kernel32.def, libtcc1.a, msvcrt.def, user32.def} tcc@uvfs://lib/libtcc # Dangerous! Not the same as this libtcc, and not recommended. On relocation ----------------- Imported data may require dllimport to work. See libtcc examples. CallWndProc-supported callback results in name-mangling. Use get_cwp_symbol instead. TCC::TCC_Raw ----------------- Raw APIs for TCC. Use this if you are confident. All methods are prefixed with "r_". ############################################################### Usage ############################################################### # The C source code. SCRIPT= <<EOF #include <windows.h> #include <stdio.h> #include <stdlib.h> LRESULT CALLBACK foo(HWND a, UINT b, WPARAM c, LPARAM d){ char* buf=malloc(1024); sprintf(buf, "Warm welcome from TCC!, %d+%d=%d\n", c, d, c+d); MessageBox(0, buf, "Hi!", MB_OK); free(buf); return 0; } EOF # Compiler options. compiler=TCC::Compiler.new.set_options("-O2 -Wall -pedantic -Werror"). add_library("user32"). # Add user32 for MessageBox. compile(SCRIPT). # Compile the string. relocate # And then relocate. # Call the compiled function with CallWindowProc. TCC::call_window_proc(compiler.get_cwp_symbol("foo"), 1, 2) # Dispose the compiler. compiler.dispose ############################################################### Known Issues ############################################################### 1. "-Werror" not working. 2. Bad options into set_options will cause a silent exit. ############################################################### =end module TCC # Raw calls to TCC Compiler. module TCC_Raw TCC_CALLS_TABLE = [ ["L",:r_tcc_new, "V"], ["V",:r_tcc_delete, "L"], ["V",:r_tcc_set_lib_path, "LP"], ["V",:r_tcc_set_error_func, "LLL"], ["V",:r_tcc_set_options, "LP"], ["L",:r_tcc_add_include_path, "LP"], ["L",:r_tcc_add_sysinclude_path, "LP"], ["V",:r_tcc_define_symbol, "LPP"], ["V",:r_tcc_undefine_symbol, "LP"], ["L",:r_tcc_add_file, "LP"], ["L",:r_tcc_compile_string, "LP"], ["L",:r_tcc_set_output_type, "LL"], ["L",:r_tcc_add_library_path, "LP"], ["L",:r_tcc_add_library, "LP"], ["L",:r_tcc_add_symbol, "LPL"], ["L",:r_tcc_output_file, "LP"], ["L",:r_tcc_run, "LLP"], ["L",:r_tcc_relocate, "LL"], ["L",:r_tcc_get_symbol, "LP"], ["V",:initialize_uvfs, "V"] ] for v in TCC_CALLS_TABLE begin api=Win32API.new "libtcc.dll",v[1].to_s,v[2],v[0] lambda {|a| define_method(v[1]) do |*args| a.call(*args) end}.call(api) end end TCC_OUTPUT_MEMORY = 1 TCC_OUTPUT_EXE = 2 TCC_OUTPUT_DLL = 3 TCC_OUTPUT_OBJ = 4 TCC_OUTPUT_PREPROCESS = 5 TCC_RELOCATE_AUTO = 1 # CWP for calling into function. CallWindowProc = Win32API.new 'user32', 'CallWindowProcW', 'pLLLL', 'L' CallWindowProcPL = Win32API.new 'user32', 'CallWindowProcW', 'pLLPL', 'L' CallWindowProcPP = Win32API.new 'user32', 'CallWindowProcW', 'pLLPP', 'L' extend self end TCC_Raw::initialize_uvfs() class IllegalStateError < StandardError end class CompileError < StandardError attr_reader :log def initialize(log) @log=log end def to_s @log.to_s end end class RelocationError < StandardError attr_reader :log def initialize(log) @log=log end def to_s @log.to_s end end class Compiler STATE_IDLE=0 STATE_COMPILED=1 STATE_RELOCATED=2 STATE_READY=3 def initialize @s=TCC_Raw::r_tcc_new() @state=0 initialize_error_handler TCC_Raw::r_tcc_set_lib_path(@s, "nul@uvfs://") add_include_path("tcc@uvfs://include"). add_include_path("tcc@uvfs://include/winapi"). add_library_path("tcc@uvfs://lib") TCC_Raw::r_tcc_set_output_type(@s, TCC_Raw::TCC_OUTPUT_MEMORY) @buffer=[] end def logs @buffer end def initialize_error_handler # Do nothing. end def fetch_log # Do nothing end def add_include_path(path) if @state!=STATE_IDLE raise IllegalStateError.new end TCC_Raw::r_tcc_add_include_path(@s, path) return self end def add_library_path(path) if @state!=STATE_IDLE raise IllegalStateError.new end TCC_Raw::r_tcc_add_library_path(@s, path) return self end def add_library(lib) if @state!=STATE_IDLE raise IllegalStateError.new end TCC_Raw::r_tcc_add_library(@s, lib) return self end def set_options(options) if @state!=STATE_IDLE raise IllegalStateError.new end TCC_Raw::r_tcc_set_options(@s, options) return self end def compile(script) if @state!=STATE_IDLE raise IllegalStateError.new end ret=TCC_Raw::r_tcc_compile_string(@s, script) fetch_log if ret==-1 raise (CompileError.new(@buffer)) end @state=STATE_COMPILED return self end def define_macro(sym, v) if @state!=STATE_IDLE raise IllegalStateError.new end TCC_Raw::r_tcc_add_symbol(@s, sym, v) return self end def undef_macro(sym) if @state!=STATE_IDLE raise IllegalStateError.new end TCC_Raw::r_tcc_undefine_symbol(@s, sym) return self end def add_symbol(sym, addr) if @state!=STATE_COMPILED raise IllegalStateError.new end TCC_Raw::r_tcc_add_symbol(@s, sym, addr) return self end def relocate if @state!=STATE_COMPILED raise IllegalStateError.new end ret=TCC_Raw::r_tcc_relocate(@s, TCC_Raw::TCC_RELOCATE_AUTO) fetch_log if ret<0 raise (RelocationError.new(@buffer)) end @state=STATE_READY return self end def dispose TCC_Raw::r_tcc_delete(@s) end def get_symbol(sym) if @state!=STATE_READY raise IllegalStateError.new end s=TCC_Raw::r_tcc_get_symbol(@s, sym) s end def get_cwp_symbol(sym) get_symbol("_"+sym+"@16") end end def call_window_proc(addr, a=0, b=0) TCC_Raw::CallWindowProc.call addr,0,0,a,b end def call_window_proc_pl(addr, a, b=0) TCC_Raw::CallWindowProcPL.call addr,0,0,a,b end def call_window_proc_pp(addr, a, b) TCC_Raw::CallWindowProcPP.call addr,0,0,a,b end def log_handler tcc=TCC::Compiler.new.compile( <<EOF #include <windows.h> #include <stdio.h> #include <stdlib.h> #include <string.h> const char* buffer=0; void tcc_error_handler(void* arg, const char* msg){ int n=0; if(buffer==0){ n=strlen(msg)+2; buffer=malloc(n); strcpy(buffer, msg); buffer[n-2]='\n'; buffer[n-1]=0; }else{ n=strlen(msg)+2+strlen(buffer); buffer=realloc(buffer, n); strcat(buffer, msg); buffer[n-2]='\n'; buffer[n-1]=0; } } LRESULT CALLBACK move_tcc_log(HWND a, UINT b, WPARAM addrlog, LPARAM d){ if(buffer==0) return 0; if(addrlog==0){ return strlen(buffer)+1; }else{ strcpy(addrlog, buffer); free(buffer); int l=strlen(buffer)+1; buffer=0; return l; } } EOF ).relocate handler=tcc.get_symbol("tcc_error_handler") moveback=tcc.get_cwp_symbol("move_tcc_log") {:handler=>handler, :moveback=>moveback} end extend self LOG_HANDLER = TCC::log_handler class Compiler def initialize_error_handler TCC_Raw::r_tcc_set_error_func(@s, 0, LOG_HANDLER[:handler]) end def fetch_log len=TCC::call_window_proc(LOG_HANDLER[:moveback]) if len==0 return false end buffer = 0.chr * len TCC::call_window_proc_pl(LOG_HANDLER[:moveback], buffer) @buffer+=(buffer.split "\n") return true end end end
=begin
###############################################################
TCC Compiler for RGSS, v0.0.1
TCC original author: Fabrice Bellard
Porting: gjz010
Modified TCC source: [url]https://github.com/gjz010/tcc-nofs[/url]]https://github.com/gjz010/tcc-nofs
UVFS source: [url]https://github.com/gjz010/uvfs-tcc[/url]]https://github.com/gjz010/uvfs-tcc
###############################################################
API Document
###############################################################
TCC::Compiler
-----------------
The main wrapper class for using compiler.
Methods:
logs, set_options, add_include_path, add_library_path, add_library,
compile, define_macro, undef_macro, add_symbol, relocate,
get_symbol, get_cwp_symbol, dispose
CallWndProc
-----------------
Three variants of CallWndProc are provided:
TCC::call_window_proc_pl(addr, a, b=0) # Call with one buffer and one integer.
TCC::call_window_proc(addr, a=0, b=0) # Call with two integers.
TCC::call_window_proc_pp(addr, a, b) # Call with two buffers.
On stdlib
-----------------
The porting provides under a virtual internal filesystem called UVFS.
In most time you don't need to care about how UVFS works.
The stdlib provides tcc-libraries as-is:
tcc@uvfs://include
tcc@uvfs://include/winapi
tcc@uvfs://lib/{gdi32.def, kernel32.def, libtcc1.a, msvcrt.def, user32.def}
tcc@uvfs://lib/libtcc # Dangerous! Not the same as this libtcc, and not recommended.
On relocation
-----------------
Imported data may require dllimport to work. See libtcc examples.
CallWndProc-supported callback results in name-mangling.
Use get_cwp_symbol instead.
TCC::TCC_Raw
-----------------
Raw APIs for TCC. Use this if you are confident.
All methods are prefixed with "r_".
###############################################################
Usage
###############################################################
# The C source code.
SCRIPT= <<EOF
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
LRESULT CALLBACK foo(HWND a, UINT b, WPARAM c, LPARAM d){
char* buf=malloc(1024);
sprintf(buf, "Warm welcome from TCC!, %d+%d=%d\n", c, d, c+d);
MessageBox(0, buf, "Hi!", MB_OK);
free(buf);
return 0;
}
EOF
# Compiler options.
compiler=TCC::Compiler.new.set_options("-O2 -Wall -pedantic -Werror").
add_library("user32"). # Add user32 for MessageBox.
compile(SCRIPT). # Compile the string.
relocate # And then relocate.
# Call the compiled function with CallWindowProc.
TCC::call_window_proc(compiler.get_cwp_symbol("foo"), 1, 2)
# Dispose the compiler.
compiler.dispose
###############################################################
Known Issues
###############################################################
1. "-Werror" not working.
2. Bad options into set_options will cause a silent exit.
###############################################################
=end
module TCC
# Raw calls to TCC Compiler.
module TCC_Raw
TCC_CALLS_TABLE =
[
["L",:r_tcc_new, "V"],
["V",:r_tcc_delete, "L"],
["V",:r_tcc_set_lib_path, "LP"],
["V",:r_tcc_set_error_func, "LLL"],
["V",:r_tcc_set_options, "LP"],
["L",:r_tcc_add_include_path, "LP"],
["L",:r_tcc_add_sysinclude_path, "LP"],
["V",:r_tcc_define_symbol, "LPP"],
["V",:r_tcc_undefine_symbol, "LP"],
["L",:r_tcc_add_file, "LP"],
["L",:r_tcc_compile_string, "LP"],
["L",:r_tcc_set_output_type, "LL"],
["L",:r_tcc_add_library_path, "LP"],
["L",:r_tcc_add_library, "LP"],
["L",:r_tcc_add_symbol, "LPL"],
["L",:r_tcc_output_file, "LP"],
["L",:r_tcc_run, "LLP"],
["L",:r_tcc_relocate, "LL"],
["L",:r_tcc_get_symbol, "LP"],
["V",:initialize_uvfs, "V"]
]
for v in TCC_CALLS_TABLE
begin
api=Win32API.new "libtcc.dll",v[1].to_s,v[2],v[0]
lambda {|a| define_method(v[1]) do |*args| a.call(*args) end}.call(api)
end
end
TCC_OUTPUT_MEMORY = 1
TCC_OUTPUT_EXE = 2
TCC_OUTPUT_DLL = 3
TCC_OUTPUT_OBJ = 4
TCC_OUTPUT_PREPROCESS = 5
TCC_RELOCATE_AUTO = 1
# CWP for calling into function.
CallWindowProc = Win32API.new 'user32', 'CallWindowProcW', 'pLLLL', 'L'
CallWindowProcPL = Win32API.new 'user32', 'CallWindowProcW', 'pLLPL', 'L'
CallWindowProcPP = Win32API.new 'user32', 'CallWindowProcW', 'pLLPP', 'L'
extend self
end
TCC_Raw::initialize_uvfs()
class IllegalStateError < StandardError
end
class CompileError < StandardError
attr_reader :log
def initialize(log)
@log=log
end
def to_s
@log.to_s
end
end
class RelocationError < StandardError
attr_reader :log
def initialize(log)
@log=log
end
def to_s
@log.to_s
end
end
class Compiler
STATE_IDLE=0
STATE_COMPILED=1
STATE_RELOCATED=2
STATE_READY=3
def initialize
@s=TCC_Raw::r_tcc_new()
@state=0
initialize_error_handler
TCC_Raw::r_tcc_set_lib_path(@s, "nul@uvfs://")
add_include_path("tcc@uvfs://include").
add_include_path("tcc@uvfs://include/winapi").
add_library_path("tcc@uvfs://lib")
TCC_Raw::r_tcc_set_output_type(@s, TCC_Raw::TCC_OUTPUT_MEMORY)
@buffer=[]
end
def logs
@buffer
end
def initialize_error_handler
# Do nothing.
end
def fetch_log
# Do nothing
end
def add_include_path(path)
if @state!=STATE_IDLE
raise IllegalStateError.new
end
TCC_Raw::r_tcc_add_include_path(@s, path)
return self
end
def add_library_path(path)
if @state!=STATE_IDLE
raise IllegalStateError.new
end
TCC_Raw::r_tcc_add_library_path(@s, path)
return self
end
def add_library(lib)
if @state!=STATE_IDLE
raise IllegalStateError.new
end
TCC_Raw::r_tcc_add_library(@s, lib)
return self
end
def set_options(options)
if @state!=STATE_IDLE
raise IllegalStateError.new
end
TCC_Raw::r_tcc_set_options(@s, options)
return self
end
def compile(script)
if @state!=STATE_IDLE
raise IllegalStateError.new
end
ret=TCC_Raw::r_tcc_compile_string(@s, script)
fetch_log
if ret==-1
raise (CompileError.new(@buffer))
end
@state=STATE_COMPILED
return self
end
def define_macro(sym, v)
if @state!=STATE_IDLE
raise IllegalStateError.new
end
TCC_Raw::r_tcc_add_symbol(@s, sym, v)
return self
end
def undef_macro(sym)
if @state!=STATE_IDLE
raise IllegalStateError.new
end
TCC_Raw::r_tcc_undefine_symbol(@s, sym)
return self
end
def add_symbol(sym, addr)
if @state!=STATE_COMPILED
raise IllegalStateError.new
end
TCC_Raw::r_tcc_add_symbol(@s, sym, addr)
return self
end
def relocate
if @state!=STATE_COMPILED
raise IllegalStateError.new
end
ret=TCC_Raw::r_tcc_relocate(@s, TCC_Raw::TCC_RELOCATE_AUTO)
fetch_log
if ret<0
raise (RelocationError.new(@buffer))
end
@state=STATE_READY
return self
end
def dispose
TCC_Raw::r_tcc_delete(@s)
end
def get_symbol(sym)
if @state!=STATE_READY
raise IllegalStateError.new
end
s=TCC_Raw::r_tcc_get_symbol(@s, sym)
s
end
def get_cwp_symbol(sym)
get_symbol("_"+sym+"@16")
end
end
def call_window_proc(addr, a=0, b=0)
TCC_Raw::CallWindowProc.call addr,0,0,a,b
end
def call_window_proc_pl(addr, a, b=0)
TCC_Raw::CallWindowProcPL.call addr,0,0,a,b
end
def call_window_proc_pp(addr, a, b)
TCC_Raw::CallWindowProcPP.call addr,0,0,a,b
end
def log_handler
tcc=TCC::Compiler.new.compile( <<EOF
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const char* buffer=0;
void tcc_error_handler(void* arg, const char* msg){
int n=0;
if(buffer==0){
n=strlen(msg)+2;
buffer=malloc(n);
strcpy(buffer, msg);
buffer[n-2]='\n';
buffer[n-1]=0;
}else{
n=strlen(msg)+2+strlen(buffer);
buffer=realloc(buffer, n);
strcat(buffer, msg);
buffer[n-2]='\n';
buffer[n-1]=0;
}
}
LRESULT CALLBACK move_tcc_log(HWND a, UINT b, WPARAM addrlog, LPARAM d){
if(buffer==0) return 0;
if(addrlog==0){
return strlen(buffer)+1;
}else{
strcpy(addrlog, buffer);
free(buffer);
int l=strlen(buffer)+1;
buffer=0;
return l;
}
}
EOF
).relocate
handler=tcc.get_symbol("tcc_error_handler")
moveback=tcc.get_cwp_symbol("move_tcc_log")
{:handler=>handler, :moveback=>moveback}
end
extend self
LOG_HANDLER = TCC::log_handler
class Compiler
def initialize_error_handler
TCC_Raw::r_tcc_set_error_func(@s, 0, LOG_HANDLER[:handler])
end
def fetch_log
len=TCC::call_window_proc(LOG_HANDLER[:moveback])
if len==0
return false
end
buffer = 0.chr * len
TCC::call_window_proc_pl(LOG_HANDLER[:moveback], buffer)
@buffer+=(buffer.split "\n")
return true
end
end
end
需要libtcc.dll:
libtcc.7z
(1.26 MB, 下载次数: 45)
|
评分
-
查看全部评分
|