第一部分:在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 可能被放到不一样的编译单元里.
关于分开注册一个模块的信息请参阅: 分开注册 章节.