第一部分:在vs2010中生成luabind靜態庫和動態庫linux
1、前期準備 1.安裝boostios
2.下載並生成lua靜態庫bootstrap
3.下載luabind源代碼安全
2、生成靜態庫 框架
1.使用嚮導生成項目/解決方案編輯器
2.添加luabind源代碼文件svn
3.添加包含目錄函數
4.生成靜態庫工具
#include "stdafx.h" #include <iostream> extern "C" { #include "lua.h" #include "lualib.h" #include "lauxlib.h" } #include <iostream> #include <luabind/luabind.hpp> using namespace std; int _tmain(int argc, _TCHAR* argv[]) { lua_State *L = ::luaL_newstate(); /* opens Lua */ luabind::open(L); luaL_dostring(L,"function add(first,second)\n return first + second\n end\n"); try{ std::cout<<"Result:" <<luabind::call_function<int>(L,"add",2,3)<<std::endl; } catch(luabind::error& e){ std::cout<<"catch exception:"<<e.what()<<std::endl; } ::lua_close(L); }
3.添加包含目錄性能
#include "stdafx.h" #include <iostream> #include <luabind/luabind.hpp> void greet() { std::cout << "hello world!\n"; } extern "C" int __declspec(dllexport) init(lua_State* L) { using namespace luabind; open(L); module(L) [ def("greet", &greet) ]; return 0; }
注意,在Windows環境下init函數以前是要加__declspec(dllexport)才能將函數導出的,而luabind的文檔中的環境是linux,默認不用加__declspec(dllexport)也能夠導出(就由於這個折騰了我半天才把hello word成功運行)。
2. 添加靜態庫文件:將luabind.lib和lua51.lib添加到連接選項中:項目屬性->鏈接器->輸入->附加依賴文件,加入luabind.lib和lua51.lib(這裏我把luabind.lib拷貝到我工程項目根目錄下:C:\Users\Administrator\Documents\Visual Studio 2010\Projects\hello_dll_luabind\luabind_lib.lib)。
接着:在項目->屬性->VC++目錄->包含目錄和庫目錄中分別添加luabind.lib和lua51.lib所在目錄,以及代碼中包含文件的目錄。同時須要把D:\mylua\boost_1_56_0目錄引入(luabind須要用到boost庫相關頭文件)。以下圖:
3.編譯運行將在工程項目文件目錄 C:\Users\Administrator\Documents\Visual Studio 2010\Projects\hello_dll_luabind\Debug 下獲得hello_dll_luabind.dll文件。
4. 把hello_dll_luabind.dll放到lua51.dll和lua.exe所在的目錄下。打開lua命令行,鍵入:
測試成功。cheer!
module(L) [ // declarations ];
這將會註冊全部的函數或者類到 Lua 全局做用域. 若是你想要爲你的模塊設定一個名空間(相似標準模塊),
你能夠給構造函數設定一個名字,例如:module(L, "my_library") [ // declarations ];
這裏全部的申明都將被放置在 my_libary 表.
module(L, "my_library") [ // declarations namespace_("detail") [ // library-private declarations ] ];
你可能會想到,下面兩個聲明是等價的:
module(L) [ namespace_("my_library") [ // declarations ] ]; module(L, "my_library") [ // declarations ];
每個聲明必須用逗號分隔,例如:
module(L) [ def("f", &f), def("g", &g), class_<A>("A") .def(constructor<int, int>), def("h", &h) ];
更多實際的例子請參閱 綁定函數到Lua 和 綁定類到Lua 章節.
template<class F, class policies> void def(const char* name, F f, const Policies&);
* name 是該函數在Lua裏面的名字
* F 是該函數的指針module(L) [ def("sin", &std::sin) ];
7.1 重載函數
int f(const char*) 和 void f(int). module(L) [ def("f", (int(*)(const char*)) &f), def("f", (void(*)(int)) &f) ];
7.2 簽名匹配
struct A { void f(); void f() const; };
const A* create_a();全部權轉移
爲了正確處理全部權轉移問題,create_a()將用來適配返回值策略.struct B: A {}; struct C: B {}; void g(A*); void g(B*);
執行如下 Lua 代碼即結果:
a1 = create_a() a1:f() -- 常量版本被調用 a2 = A() a2:f() -- 很是量版本被調用 a = A() b = B() c = C() g(a) -- calls g(A*) g(b) -- calls g(B*) g(c) -- calls g(B*)
7.3 調用Lua函數
template<class Ret> Ret call_function(lua_State* L, const char* name, ...) template<class Ret> Ret call_function(object const& obj, ...)
call_function()函數有兩個重載版本.一個是根據函數的名字來調用函數,
另外一個是調用一個能夠做爲函數調用的Lua值.int ret = call_function<int>( L , "a_lua_function" , new complex_class() )[ adopt(_1) ];
若是你想經過引用方式傳遞參數,你必須用Boost.Ref來包裝一下.
例如:int ret = call_function(L, "fun", boost::ref(val));
若是你想給一個函數調用指定本身的錯誤捕獲處理函數(error handler),能夠參閱
pcall errorfunc 章節的 set_pcall_callback .template<class Ret> Ret resume_function(lua_State* L, const char* name, ...) template<class Ret> Ret resume_function(object const& obj, ...)
和:
template<class Ret> Ret resume(lua_State* L, ...)
第一次開始一個協程的時候,你必須給它一個入口函數. 當一個協程返回(yield)的時候,
resume_fucntion()調用的返回值是 lua_yield()的第一個傳入參數.當你想要繼續一個lua_State* thread = lua_newthread(L); object fun = get_global(thread)["my_thread_fun"]; resume_function(fun);
8 綁定類到Lua
class testclass { public: testclass(const std::string& s): m_string(s) {} void print_string() { std::cout << m_string << "\n"; } private: std::string m_string; };
爲了註冊這個類到Lua環境,能夠像下面這樣寫(假設你使用了名空間):
module(L) [ class_<testclass>("testclass") .def(constructor<const std::string&>()) .def("print_string", &testclass::print_string) ];
這將註冊 testclass 類以及接受一個string參數的構造器以及一個成員叫print_string()的函數.
Lua 5.0 Copyright (C) 1994-2003 Tecgraf, PUC-Riostruct A { int a; }; int plus(A* o, int v) { return o->a + v; }
你能夠註冊 plus() 做爲A的一個成員函數,以下:
class_<A>("A") .def("plus", &plus)
plus() 如今可以被做爲A的一個接受一個int參數的成員函數來調用.若是對象指針(this指針)是const,
這個函數也將表現的像一個常量成員函數那樣(它能夠經過常量對象來調用).return-value (class-name::*)(arg1-type, arg2-type, ...)
例如:
struct A { void f(int); void f(int, int); }; class_<A>() .def("f", (void(A::*)(int))&A::f)
A的第一個成員函數f(int)被綁定了,而第二個沒喲被綁定.
struct A { int a; };
這個類能夠這樣註冊:
module(L) [ class_<A>("A") .def_readwrite("a", &A::a) ];
這使得成員變量 A::a 得到了讀寫訪問權. 還能夠註冊一個只讀的屬性:
module(L) [ class_<A>("A") .def_readonly("a", &A::a) ];
當綁定成員是一個非原始數據類型的時候,自動生成的 getter 函數將會返回一個它引用.
這就容許你能夠鏈式使用 . 操做符.例如,當有一個結構體包含另一個結構體的時候.以下:struct A { int m; }; struct B { A a; };
當綁定B到Lua的時候,下面的表達式應該能夠工做:
b = B() b.a.m = 1 assert(b.a.m == 1)
這要求 a 屬性必須返回一個A的引用, 而不是一個拷貝. 這樣,LuaBind將會自動使用依賴策略來
確保返回值依賴於它所在的對象.因此,若是返回的引用的生命長於該對象的全部的引用(這裏是b).class A { public: void set_a(int x) { a = x; } int get_a() const { return a; } private: int a; };
能夠這樣註冊成一個公共數據成員:
class_<A>("A") .property("a", &A::get_a, &A::set_a)
這樣 set_a() 和 get_a() 將取代簡單的數據成員操做.若是你想使之只讀,你只須要省略最後一個參數.
請注意, get 函數必須是 const 的,不然不能經過編譯.module(L) [ class_<A>("A") .enum_("constants") [ value("my_enum", 4), value("my_2nd_enum", 7), value("another_enum", 6) ] ];
在Lua側,他們能夠像數據成員那樣被操做,除了它們是隻讀的並且屬於類自己而不是類的實例.
Lua 5.0 Copyright (C) 1994-2003 Tecgraf, PUC-Riostruct vec { vec operator+(int s); };
能夠這樣註冊:
module(L) [ class_<vec>("vec") .def(self + int()) ];
無論你的 + 操做符是定義在類裏面仍是自由函數均可以工做.
若是你的操做符是常量的(const)(或者,是一個自由函數, 接受一個類的常量的引用)你必須用module(L) [ class_<vec>("vec") .def(const_self + int()) ];
支持以下操做符:
+ - * / == < <=struct vec { vec operator+(std::string); };
取而代之的是,咱們用 other<> 包裝下,以下:
module(L) [ class_<vec>("vec") .def(self + other<std::string>()) ];
註冊一個應用程序操做符(函數調用):
module(L) [ class_<vec>("vec") .def( self(int()) ) ];
這裏有個特殊的操做符.在Lua裏,它叫作 __tostring,它不是一個真正的操做符.它是被用來轉換一個對象到
string的標準Lua方法.若是你註冊之,能夠經過Lua的標準函數 tostring() 來轉換你的對象到一個string.class number {}; std::ostream& operator<<(std::ostream&, number&); ... module(L) [ class_<number>("number") .def(tostring(self)) ];
8.5 嵌套做用域和靜態函數
class_<foo>("foo") .def(constructor<>() .scope [ class_<inner>("nested"), def("f", &f) ];
在上面的例子裏, f 將表現的像一個類 foo 的靜態函數,而 類 nested 將表現的像類 foo 的嵌套類.
struct A {}; struct B : A {};
能夠這樣註冊:
module(L) [ class_<A>("A"), class_<B, A>("B") ];
若是你使用了多繼承,你能夠指定多於一個的基類.若是 B 還繼承了類 C , 它能夠這樣註冊:
module(L) [ class_<B, bases<A, C> >("B") ];
注意,你能夠省去 bases<> 當你用的是單繼承的時候.
module(L) [ class_<A, boost::shared_ptr<A> >("A") ];
你還必須爲你的智能指針提供兩個函數.一個返回常量版本的智能指針類型(這裏是: boost:shared_ptr< const A >).
另外一個函數要能夠從智能指針萃取流指針(raw pointer). 之因此須要第一個函數是由於,LuaBind 容許namespace luabind { template<class T> T* get_pointer(boost::shared_ptr<T>& p) { return p.get(); } template<class A> boost::shared_ptr<const A>* get_const_holder(boost::shared_ptr<A>*) { return 0; } }
第二個函數只在編譯時用於映射 boost::shared_ptr<A>到其常量版本 boost::shared_ptr<const A>.
它歷來不會被調用,因此返回值是無所謂的(返回值的類型纔是關鍵).Source Target holder_type<A> A* holder_type<A> B* holder_type<A> A const* holder_type<A> B const* holder_type<A> holder_type<A> holder_type<A> holder_type<A const> holder_type<A const> A const* holder_type<A const> B const* holder_type<A const> holder_type<A const
從C++到Lua
Source Target holder_type<A> holder_type<A> holder_type<A const> holder_type<A const> holder_type<A> const& holder_type<A> holder_type<A const> const& holder_type<A const>
當使用持有器類型的時候,知道指針是否是合法(例如:非空)是頗有用的.例如,當使用 std::auto_ptr 的時候,
持有器經過一個參數傳遞給函數的時候將會變得無效. 爲了這個目的,全部的對象實例都有一個成員叫: __ok.struct X {}; void f(std::auto_ptr<X>); module(L) [ class_<X, std::auto_ptr<X> >("X") .def(constructor<>()), def("f", &f) ];
Lua 5.0 Copyright (C) 1994-2003 Tecgraf, PUC-Rio
> a = X()module(L) [ class_<base, boost::shared_ptr<base> >("base") .def(constructor<>()), class_<derived, base, boost::shared_ptr<base> >("base") .def(constructor<>()) ];
在內部, LuaBind 將會作必要的轉換於萃取自持有器的流指針之上.
void register_part1(class_<X>& x) { x.def(); } void register_part2(class_<X>& x) { x.def(); } void register_(lua_State* L) { class_<X> x("x"); register_part1(x); register_part2(x); module(L) [ x ]; }
這裏,類X被分兩步註冊.兩個函數 register_part 和 register_part2 可能被放到不一樣的編譯單元裏.
關於分開註冊一個模塊的信息請參閱: 分開註冊 章節.