日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

在windows程序中嵌入Lua脚本引擎--使用VS IDE编译Luajit脚本引擎

發(fā)布時間:2023/11/27 生活经验 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 在windows程序中嵌入Lua脚本引擎--使用VS IDE编译Luajit脚本引擎 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

? ? ? ? 前些天聽到一個需求:某業(yè)務方需要我們幫忙清理用戶電腦上的一些廢棄文件。同事完成這個邏輯的方案便是在我們程序中加入了一個很“獨立”的業(yè)務邏輯:檢索和刪除某個程序產(chǎn)生的廢棄文件。試想,該“獨立”的邏輯之后會如何?被刪掉?一直保留著?不管如何,這都意味著我們代碼需要做修改,我們生成的二進制文件將產(chǎn)生差異,我們要為了這個需求要發(fā)一次版本。想一想客戶端升級這樣一個漫長且耗流量的過程,我甚至認為為了這么一個需求去浪費這些非常不值得。那么有沒有一種比較好的辦法,讓我們不修改代碼,不發(fā)布版本就能完成這樣的“一次性”需求呢?當然有!是否記得若干年前,某個大公司和某個大公司吵架,當時那位新上任的CEO說某某公司可以“云暗殺”。且這種“暗殺”是一次性的,做完后可以銷毀證據(jù),且非常難以捕捉。我沒有考究這個說法,但是從技術層面來說,這樣的技術可以說并不復雜。那如何實現(xiàn)呢?就是本系列文章中討論的:在程序中嵌入Lua腳本引擎。(轉載請指明出于breaksoftware的csdn博客)

? ? ? ? 首先簡要介紹下Lua。它是巴西里約熱內(nèi)盧某高校發(fā)明的一種輕量級腳本語言。設計該語言的目標是:要成為一個很容易嵌入其它語言中使用的語言。由于“輕量級”和“易嵌入”這兩個特性,會減少我們內(nèi)嵌其的代價,這也是我選擇它的最主要原因。至于穩(wěn)定性,我無法評說,但是目前很多游戲中都內(nèi)嵌了lua的腳本引擎,其中不乏《魔獸世界》這樣的大作。我覺得像這樣的產(chǎn)品都選用Lua,那么至少證明Lua的安全和穩(wěn)定性還是非常可靠的。

? ? ? ?Luajit是Lua的一個即時編譯器,它就是我們要內(nèi)嵌windows程序的目標。http://luajit.org/是它的官方網(wǎng)站,我們可以從它的子頁面得到源碼。我正式準備該系列文章的時間是2012年11月份,此時2.0beta11已經(jīng)發(fā)布。我決定以這個最新的源碼作為我們的例子。

? ? ? ? 下載

? ? ? ? ?http://luajit.org/download/LuaJIT-2.0.0-beta11.zip

? ? ? ? 目錄結構

? ? ? ? 編譯

? ? ? ? 在http://luajit.org/install.html#windows里有詳細的說明,我們只要在使用VS的Command Prompt中定位到src目錄,然后執(zhí)行msvcbuild.bat。

? ? ? ?VS IDE編譯Luajit

? ? ? ? 如此便編譯成功了。但是,往往我們的工程不是用批處理文件編譯的,而是用IDE。本文主要就是說明如何將該批處理文件轉換為IDE編譯環(huán)境。這個操作的過程將拆分各個編譯和鏈接過程,在這個過程中,我們將發(fā)現(xiàn)Luajit的生成過程,這將有助于我們之后對Luajit的改造。

? ? ? ? 總體來說,Luajit的編譯和鏈接分為3個大部分:

  1. 生成minilua程序。利用minilua產(chǎn)生一些文件。
  2. 使用minilua產(chǎn)生的一些文件生成buildvm程序。使用buildvm產(chǎn)生一些文件。
  3. 使用buildvm產(chǎn)生的一些文件生成lua程序。

? ? ? ? 編譯環(huán)境準備

? ? ? ? 在msvcbuild.bat中有這么一段設置編譯環(huán)境的

@set LJCOMPILE=cl /nologo /c /MD /O2 /W3 /D_CRT_SECURE_NO_DEPRECATE

? ? ? ? 其中非常關鍵的一個選項是/02,它對應于“工程屬性”中Configuration Properties->C/C++->Optimization->Optimization的Maximize Speed(/O2)。設置該屬性后,還要設置Configuration Properties->C/C++->Debug Information Format為Program Database(/Zi)。這個設置非常重要,否則會報很多錯誤。我說的這些設置是針對All?Configurations的,這樣在debug和release下編譯和鏈接才不會有問題。
? ? ? ? 編譯MiniLua輔助程序

? ? ? ? 在批處理中有

%LJCOMPILE% host\minilua.c
@if errorlevel 1 goto :BAD
%LJLINK% /out:minilua.exe minilua.obj
@if errorlevel 1 goto :BAD
if exist minilua.exe.manifest^%LJMT% -manifest minilua.exe.manifest -outputresource:minilua.exe

? ? ? ? 于是我們要在項目中新建一個空的console工程,并命名為MiniLua。我們將該工程需要的文件host\minilua.c放入工程目錄,同時加入工程。編譯生成MiniLua.exe。

? ? ? ? Minilua是用于根據(jù)平臺來生成平臺相關的代碼。這些生成的代碼將在之后創(chuàng)建的Buildvm工程中使用到。

? ? ? ? 編譯Buildvm輔助程序

? ? ? ? 在批處理中有

%LJCOMPILE% /I "." /I %DASMDIR% host\buildvm*.c
@if errorlevel 1 goto :BAD
%LJLINK% /out:buildvm.exe buildvm*.obj
@if errorlevel 1 goto :BAD
if exist buildvm.exe.manifest^%LJMT% -manifest buildvm.exe.manifest -outputresource:buildvm.exe

? ? ? ? 我們新建一個空的Console程序,并命名為Buildvm。再將host下所有以buildvm開頭的文件拷貝進入該工程目錄(buildvm_peobj.c、buildvm_lib.c、buildvm_fold.c、buildvm_asm.c、buildvm.h、buildvm.c),并將其加入工程。
? ? ? ? 其實只有這些是不夠的,我們之前提過:MiniLua是用于生成Buildvm需要的文件。

@set DASMFLAGS=-D WIN -D JIT -D FFI -D P64
@set LJARCH=x64
@minilua
@if errorlevel 8 goto :X64
@set DASMFLAGS=-D WIN -D JIT -D FFI
@set LJARCH=x86
:X64
minilua %DASM% -LN %DASMFLAGS% -o host\buildvm_arch.h vm_x86.dasc
@if errorlevel 1 goto :BAD

? ? ? ?我們大致可以猜到minilua是使用vm_x86.dasc,在host目錄下生成buildvm_arch.h。而我為了讓工程分離,我已經(jīng)將buildvm開頭的文件搬到Buildvm工程目錄了。于是我們要在Buildvm工程的Pre-Build Event中設置(將元目錄的*.dasc文件拷貝到Buildvm工程目錄下,因為只有這個工程需要使用到它)

$(OutDir)\MiniLua.exe $(SolutionDir)dynasm/dynasm.lua -LN -D WIN -D JIT -D FFI -o $(SolutionDir)Buildvm/buildvm_arch.h archdasc/vm_x86.dasc

? ? ? ? 我們再將生成的buildvm_arch.h加入工程。

? ? ? ? 因為Buildvm編譯和Minilua生成后都要使用原目錄下的dynasm文件夾下文件。我們將dynasm文件夾拷貝到和這兩個項目同等級的目錄下(LuaProject\dynasm),在Buildvm工程中引用這些文件。

? ? ? ? buidlvm*文件還依賴原src目錄下的lj_*文件,我們將這些文件拷貝到LuaProject\Lj目錄下。并將其相關的頭文件lua.h、luaconf.h、luajit.h拷貝到LuaProject\Header中。在工程設置中設置C\C++->General->Additional Include Directories為"$(SolutionDir)Lj";"$(SolutionDir)Header"。

? ? ? ? Buildvm也是輔助程序,在它生成后,要使用它再生成一些文件。我們將?ALL_LIB中文件(lib_base.c lib_math.c lib_bit.c lib_string.c lib_table.c lib_io.c lib_os.c lib_package.c lib_debug.c lib_jit.c lib_ffi.c)從原目錄src下拷貝到LuaProject\Lualib的目錄下。

buildvm -m peobj -o lj_vm.obj
@if errorlevel 1 goto :BAD
pause
buildvm -m bcdef -o lj_bcdef.h %ALL_LIB%
@if errorlevel 1 goto :BAD
pause
buildvm -m ffdef -o lj_ffdef.h %ALL_LIB%
@if errorlevel 1 goto :BAD
buildvm -m libdef -o lj_libdef.h %ALL_LIB%
@if errorlevel 1 goto :BAD
buildvm -m recdef -o lj_recdef.h %ALL_LIB%
@if errorlevel 1 goto :BAD
buildvm -m vmdef -o jit\vmdef.lua %ALL_LIB%
@if errorlevel 1 goto :BAD
buildvm -m folddef -o lj_folddef.h lj_opt_fold.c
@if errorlevel 1 goto :BAD

? ? ? ? 我們在Buildvm的Post-Build Event事件中設置如下

@setlocal
cd /d ..\lualib
@set ALL_LIB=lib_base.c lib_math.c lib_bit.c lib_string.c lib_table.c lib_io.c lib_os.c lib_package.c lib_debug.c lib_jit.c lib_ffi.c lib_fl.c
$(OutDir)\buildvm.exe -m peobj -o $(OutDir)\lj_vm.obj
md $(SolutionDir)Builvmheader
$(OutDir)\buildvm.exe -m bcdef -o $(SolutionDir)Builvmheader\lj_bcdef.h %ALL_LIB%
$(OutDir)\buildvm.exe -m ffdef -o $(SolutionDir)Builvmheader\lj_ffdef.h %ALL_LIB%
$(OutDir)\buildvm.exe -m libdef -o $(SolutionDir)Builvmheader\lj_libdef.h %ALL_LIB%
$(OutDir)\buildvm.exe -m recdef -o $(SolutionDir)Builvmheader\lj_recdef.h %ALL_LIB%
$(OutDir)\buildvm.exe -m vmdef -o ..\jit\vmdef.lua %ALL_LIB%
cd /d ..\lj
$(OutDir)\buildvm.exe -m folddef -o $(SolutionDir)builvmheader\lj_folddef.h lj_opt_fold.c
@endlocal

? ? ? ? 將Buildvm生成為lj_*.h文件生成到LuaProject\Buildvmheader目錄下。將生成的vmdef.lua放到LuaProject\jit(從原src\jit拷貝來的)的目錄下。

? ? ? ? 生成obj文件

%LJCOMPILE% /DLUA_BUILD_AS_DLL lj_*.c lib_*.c

? ? ? ? 該處理要將原src下所有l(wèi)j_*.c和lib_*.c生成obj,以供之后不同場景進行連接。

? ? ? ?我們新建一個win32項目,將之前沒有放入LuaProject\Lualib的lib_aux.c、lib_init.c拷貝到LuaProject\OtherLualib目錄下。這樣我們Lua工程將引用LuaProject\Builvmheader、LuaProject\Lj、LuaProject\OtherLualib、LuaProject\Lualib。現(xiàn)在我們要讓我們工程只編譯不鏈接,并將生成的obj文件拷貝到LuaProject\ljobj目錄下。我們在Pre-Link Event事件中設置

md $(TargetDir)ljobj
md $(TargetDir)libobj
copy $(InputDir)$(IntDir)\lj_*.obj $(TargetDir)ljobj\lj_*.obj
copy $(InputDir)$(IntDir)\lib_*.obj $(TargetDir)libobj\lib_*.obj

? ? ? ?右擊Lua工程,選擇Tool Build Order


? ? ? ?設置如下



? ? ? ? 這樣就Lua工程就只編譯不鏈接。
? ? ? ? 生成Dll文件

%LJLINK% /DLL /out:lua51.dll lj_*.obj lib_*.obj

? ? ? ? 我們新建一個win32 dll工程LuaDllProject。并為該工程增加一個空的cpp文件。并在Linker->Input->Additional Dependencies中設置

$(TargetDir)libobj\lib_*.obj $(TargetDir)ljobj\lj_*.obj $(TargetDir)lj_vm.obj

? ? ? ? 這樣就可以生成DLL文件。

? ? ? ? 生成Lib文件

%LJLIB% /OUT:lua51.lib lj_*.obj lib_*.obj

? ? ? ? 除了我們要新建一個win32 lib工程外,其他設置和DLL一樣。

? ? ? ? 生成Exe文件

%LJCOMPILE% luajit.c
@if errorlevel 1 goto :BAD
%LJLINK% /out:luajit.exe luajit.obj lua51.lib
@if errorlevel 1 goto :BAD
if exist luajit.exe.manifest^%LJMT% -manifest luajit.exe.manifest -outputresource:luajit.exe

? ? ? ? 新建一個Win32 Exe工程LuajitExe,將luajit.c拷貝到工程中,同時設置Linker->Input->Additional Dependencies的值為$(TargetDir)LualibProject.lib。在C\C++->General->Additional Include Directories設置"$(SolutionDir)Header";"$(SolutionDir)OtherHeader";"$(SolutionDir)Lj";"$(SolutionDir)Builvmheader";"$(SolutionDir)OtherLualib";"$(SolutionDir)Lualib"。這樣Exe程序生成OK。

? ? ?
? ? ? ? 當然,不否認。將批處理生成修改成IDE生成是一個簡單到復雜的過程。但是這個過程將有助于我們熟悉luajit的生成過程。也將有助于我們之后對其的改造。

總結

以上是生活随笔為你收集整理的在windows程序中嵌入Lua脚本引擎--使用VS IDE编译Luajit脚本引擎的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。