[ Extending Lua with c/c++ ] & [ Embedding Lua in c/c++ ]

动态库/静态库
================================================================================================
转自: http://www.360doc.com/content/09/0421/19/36491_3216558.shtml
静态库
       在linux环境中, 使用ar命令创建静态库文件.如下是命令的选项:
          d -----从指定的静态库文件中删除文件
          m -----把文件移动到指定的静态库文件中
          p -----把静态库文件中指定的文件输出到标准输出
          q -----快速地把文件追加到静态库文件中
          r -----把文件插入到静态库文件中
          t -----显示静态库文件中文件的列表
          x -----从静态库文件中提取文件
      还有多个修饰符修改以上基本选项,详细请man ar 以下列出三个:
          a -----把新的目标文件(*.o)添加到静态库文件中现有文件之后
          b -----***************************************之前
          v -----使用详细模式
ar 命令的命令行格式如下:
    ar [-]{dmpqrtx}[abcfilNoPsSuvV] [membername] [count] archive files...
参数archive定义库的名称, files是库文件中包含的目标文件的清单, 用空格分隔每个文件.
比如创建一个静态库文件的命令如下:
    ar r libapue.a error.o errorlog.o lockreg.o
这样就了libapue.a静态库文件, 可以用 t 选项显示包含在库中的文件

创建库文件之后,可以创建这个静态库文件的索引来帮助提高和库连接的其他程序的编译速度.使用ranlib程序创建库的索引,索引存放在库文件内部.
    ranlib libapue.a
用nm程序显示存档文件的索引,它可以显示目标文件的符号(.a .so .o)
nm libapue.a | more
如果是显示目标文件的符号:

nm error.o | more
如何使用呢?如下所示:
gcc -o test test.c libapue.a
这样就可以在test.c中调用在libapue.a中的函数了.
动态库http://www.cprogramming.com/tutorial/shared-libraries-linux-gcc.html
1.创建共享库
     gcc -shared -o libapue.so error.o errorlog.o
这样就创建了共享库!
2.编译共享库
    假设共享库位于当前目录(即跟程序文件相同的目录中)
gcc -o test -L. -lapue test.c
这样就编译出了不包含函数代码可执行文件了,但是但你运行时会发现linux动态加载器找不到libapue.so文件.
可以用ldd 命令查看可执行文件依赖什么共享库:
ldd test
如何才能让动态加载器发现库文件呢?有两种方法可以解决:
    LD_LIBRARY_PATH 环境变量  
    /etc/ld.so.conf文件
    1.环境变量
    export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:."
    2.修改/etc/ld.so.conf文件.位于/etc/ld.so.conf
一般应用程序的库文件不与系统库文件放在同一个目录下,一般把应用程序的共享库文件放在/usr/local/lib下,新建一个属于自己的目录apue,然后把刚才libapue.so复制过去就行了,同时在/etc/ld.so.conf中新增一行:
/usr/local/lib/apue
以后在编译程序时加上编译选项:
-L/usr/local/lib/apue -lapue
这样就可以使用这个libapue.so共享库了!!
写此文章参考了:<<Professional Assembly Language>>. 这是一本好书!如果是学习AT&T汇编语法,建议阅读此书!!
================================================================================================
1.buld & install lua:
download lua source: http://www.lua.org/ftp/
tar zvxf lua-5.1.5.tar.gz
cd lua-5.1.5
make linux
(sudo yum install readline-devel -y)
make install INSTALL_TOP=/home/dongsong/liblua
2.compile lua_tinker:
(sudo yum install glibc-devel -y)
[dongsong@localhost LuaTinker-master]$ ar -t /home/dongsong/liblua/lib/liblua.a 
lapi.o lcode.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o lmem.o lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o ltm.o lundump.o lvm.o lzio.o lauxlib.o lbaselib.o ldblib.o liolib.o lmathlib.o loslib.o ltablib.o lstrlib.o loadlib.o linit.o
[dongsong@localhost LuaTinker-master]$ cp /home/dongsong/liblua/lib/liblua.a ./libluatinker.a
[dongsong@localhost LuaTinker-master]$ g++ -c lua_tinker.cpp 
[dongsong@localhost LuaTinker-master]$ ar r libluatinker.a lua_tinker.o 
[dongsong@localhost LuaTinker-master]$ ar t libluatinker.a 
lapi.o lcode.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o lmem.o lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o ltm.o lundump.o lvm.o lzio.o lauxlib.o lbaselib.o ldblib.o liolib.o lmathlib.o loslib.o ltablib.o lstrlib.o loadlib.o linit.o lua_tinker.o
[dongsong@localhost LuaTinker-master]$ g++ sample1.cpp -I/home/dongsong/liblua/include -I. -L. -lluatinker -o sample1
[dongsong@localhost LuaTinker-master]$ ./sample1 
cpp_func(1,2) = 3
lua_func(3,4) = 7

================================================================================================

1.sample1

lua环境如何调用c++的函数

c++如何调用lua环境的函数

[dongsong@localhost LuaTinker-master]$ cat sample1.cpp 
#include <iostream>

extern "C" 
{
        #include "lua.h"
        #include "lualib.h"
        #include "lauxlib.h"
};

#include "lua_tinker.h"
int cpp_func(int arg1, int arg2)
{
        return arg1 + arg2;
}

int main()
{
        lua_State* L = lua_open();
        luaopen_base(L);
        lua_tinker::def(L, "cpp_func", cpp_func);//把C++中的cpp_func函数打入到Lua环境中,以符号cpp_func标识
        lua_tinker::dofile(L, "sample1.lua"); //luaL_loadfile+lua_pcall,编译并执行lua脚本,lua脚本内调用C++中的cpp_func函数
        int result = lua_tinker::call<int>(L, "lua_func", 3, 4);//c++调用lua中的lua_func函数
		//有个小问题是lua_tinker.h中只定义了函数名后面有零个/一个/两个/三个参数的模板函数,如果用这种方式调用四个参数的lua函数就会报错
		//错误:对‘call(lua_State*&, const char [9], int, int, int, int)’的调用没有匹配的函数
        printf("lua_func(3,4) = %d\n", result);
        lua_close(L);
        return 0;
}
[dongsong@localhost LuaTinker-master]$ 
[dongsong@localhost LuaTinker-master]$ cat sample1.lua 
result = cpp_func(1, 2)
print("cpp_func(1,2) = "..result)

function lua_func(arg1, arg2)
        return arg1 + arg2
end
[dongsong@localhost LuaTinker-master]$ 
[dongsong@localhost LuaTinker-master]$ g++ -o sample1 sample1.cpp libluatinker.a 
[dongsong@localhost LuaTinker-master]$ ./sample1 
cpp_func(1,2) = 3
lua_func(3,4) = 7

2.sample2

如何在c++中为Lua环境添加全局变量(整数)

如何在c++中获取Lua环境的全局变量的值

[dongsong@localhost LuaTinker-master]$ cat sample2.lua
print("cpp_int = "..cpp_int)
lua_int = 200
[dongsong@localhost LuaTinker-master]$ cat sample2.cpp 
extern "C" 
{
        #include "lua.h"
        #include "lualib.h"
        #include "lauxlib.h"
};

#include "lua_tinker.h"
static int cpp_int = 100;

int main()
{
        lua_State* L = lua_open();
        luaopen_base(L);
        lua_tinker::set(L, "cpp_int", cpp_int); //往Lua环境导入一个全局变量cpp_int,赋值100
        lua_tinker::dofile(L, "sample2.lua"); //编译并执行lua脚本
        int lua_int = lua_tinker::get<int>(L, "lua_int"); //获取Lua环境中的全局变量lua_int
        printf("lua_int = %d\n", lua_int);
        lua_close(L);
        return 0;
}
[dongsong@localhost LuaTinker-master]$ g++ -o sample2 sample2.cpp libluatinker.a 
[dongsong@localhost LuaTinker-master]$ ./sample2 
cpp_int = 100
lua_int = 200

3.sample3

如何把C++中定义的类打入lua环境供Lua代码使用

如何在C++中为Lua环境添加全局变量(类实例对象)

报错:

[dongsong@localhost LuaTinker-master]$ g++ -o sample3 sample3.cpp libluatinker.a                  
In file included from sample3.cpp:8:
lua_tinker.h: In member function ‘void lua_tinker::mem_var<T, V>::get(lua_State*) [with T = test, V = int]’:
sample3.cpp:68:   instantiated from here
lua_tinker.h:450: 错误:依赖名‘lua_tinker::if_::type’被解析为非类型,但实例化却产生了一个类型
lua_tinker.h:450: 附注:如果您想指定类型,请使用‘typename lua_tinker::if_::type’
修改lua_tinker.h:

    template<typename T, typename V>
    struct mem_var : var_base
    {   
        V T::*_var;
        mem_var(V T::*val) : _var(val) {}
        //void get(lua_State *L)  { push<if_<is_obj<V>::value,V&,V>::type>(L, read<T*>(L,1)->*(_var));    }
        void get(lua_State *L)  { push(L, read<T*>(L,1)->*(_var));  }
        void set(lua_State *L)  { read<T*>(L,1)->*(_var) = read<V>(L, 3);   }   
    };  
[dongsong@localhost LuaTinker-master]$ cat sample3.lua 
print(g_test._test)
print(g_test:is_test())
print(g_test:ret_int())
temp = test(4)
print(temp._test)
a = g_test:get()
temp:set(a)
print(temp._test)
print(temp:is_base())
print(temp:is_test())
-------------------------------------------------------------------------------
function objinfo(obj)

        local meta = getmetatable(obj)
        if meta ~= nil then
                metainfo(meta)
        else
                print("no object infomation !!")
        end
end
function metainfo(meta)

        if meta ~= nil then
                local name = meta["__name"]
                if name ~= nil then
                        metainfo(meta["__parent"])
                        print("<"..name..">")
                        for key,value in pairs(meta) do 
                                if not string.find(key, "__..") then 
                                        if type(value) == "function" then
                                                print("\t[f] "..name..":"..key.."()") 
                                        elseif type(value) == "userdata" then
                                                print("\t[v] "..name..":"..key)
                                        end
                                end
                        end
                end
        end
end
-------------------------------------------------------------------------------
print("g_test   -> ", g_test)
print("temp     -> ", temp)
print("a        -> ", a)

print("objinfo(g_test)")
objinfo(g_test)

print("objinfo(temp)")
objinfo(temp)

print("objinfo(a)")
objinfo(a)

[dongsong@localhost LuaTinker-master]$ cat sample3.cpp 
extern "C" 
{
        #include "lua.h"
        #include "lualib.h"
        #include "lauxlib.h"
};
#include "lua_tinker.h"
struct A
{
        A(int v) : value(v) {}
        int value;
};

struct base
{
        base() {}
        const char* is_base(){ return "this is base"; }
};

class test : public base
{
public:
        test(int val) : _test(val) {}
        ~test() {}
        const char* is_test(){ return "this is test"; }
        void ret_void() {}
        int ret_int()                           { return _test;                 }
        int ret_mul(int m) const        { return _test * m;             }
        A get()                                         { return A(_test);              }
        void set(A a)                           { _test = a.value;              }
        int _test;
};
test g_test(11);

int main()
{
        lua_State* L = lua_open();
        luaopen_base(L);
        luaopen_string(L);

        lua_tinker::class_add<base>(L, "base");
        lua_tinker::class_def<base>(L, "is_base", &base::is_base);

        lua_tinker::class_add<test>(L, "test");
        lua_tinker::class_inh<test, base>(L);
        lua_tinker::class_con<test>(L, lua_tinker::constructor<test,int>);
        lua_tinker::class_def<test>(L, "is_test", &test::is_test);
        lua_tinker::class_def<test>(L, "ret_void", &test::ret_void);
        lua_tinker::class_def<test>(L, "ret_int", &test::ret_int);
        lua_tinker::class_def<test>(L, "ret_mul", &test::ret_mul);
        lua_tinker::class_def<test>(L, "get", &test::get);
        lua_tinker::class_def<test>(L, "set", &test::set);
        lua_tinker::class_mem<test>(L, "_test", &test::_test);

        lua_tinker::set(L, "g_test", &g_test);

        lua_tinker::dofile(L, "sample3.lua");

        lua_close(L);
        return 0;
}

[dongsong@localhost LuaTinker-master]$ g++ -o sample3 sample3.cpp libluatinker.a                  
[dongsong@localhost LuaTinker-master]$ ./sample3 
11
this is test
11
4
11
this is base
this is test
g_test  ->      userdata: 0x233ec38
temp    ->      userdata: 0x2342728
a       ->      userdata: 0x2342828
objinfo(g_test)
<base>
        [f] base:is_base()
<test>
        [v] test:_test
        [f] test:ret_mul()
        [f] test:set()
        [f] test:ret_void()
        [f] test:ret_int()
        [f] test:is_test()
        [f] test:get()
objinfo(temp)
<base>
        [f] base:is_base()
<test>
        [v] test:_test
        [f] test:ret_mul()
        [f] test:set()
        [f] test:ret_void()
        [f] test:ret_int()
        [f] test:is_test()
        [f] test:get()
objinfo(a)
no object infomation !!

4.sampl4

如何在C++中创建Lua环境的table,并被C++和Lua环境操作

[dongsong@localhost LuaTinker-master]$ cat sample4.lua 
print(haha)
print(haha.value)
print(haha.inside)
print(haha.inside.value)
haha.test = "input from lua"
function print_table(arg)
        print("arg = ", arg)
        print("arg.name = ", arg.name)
end

function return_table(arg)
        local ret = {}
        ret.name = arg
        return ret
end
[dongsong@localhost LuaTinker-master]$ cat sample4.cpp 
extern "C" 
{
        #include "lua.h"
        #include "lualib.h"
        #include "lauxlib.h"
};

#include "lua_tinker.h"
int main()
{
        lua_State* L = lua_open();
        luaopen_base(L);
        lua_tinker::table haha(L, "haha");
        haha.set("value", 1);
        haha.set("inside", lua_tinker::table(L));
        lua_tinker::table inside = haha.get<lua_tinker::table>("inside");
        inside.set("value", 2);
        lua_tinker::dofile(L, "sample4.lua");
        const char* test = haha.get<const char*>("test");
        printf("haha.test = %s\n", test);
        lua_tinker::table temp(L);
        temp.set("name", "local table !!");
        lua_tinker::call<void>(L, "print_table", temp);
        lua_tinker::table ret = lua_tinker::call<lua_tinker::table>(L, "return_table", "give me a table !!");
        printf("ret.name =\t%s\n", ret.get<const char*>("name"));
        lua_close(L);
        return 0;
}

[dongsong@localhost LuaTinker-master]$ g++ -o sample4 sample4.cpp libluatinker.a 
[dongsong@localhost LuaTinker-master]$ ./sample4 
table: 0x22159c0
1
table: 0x2215aa0
2
haha.test = input from lua
arg =   table: 0x2215b50
arg.name =      local table !!
ret.name =      give me a table !!

5.sample5

C++设置Lua环境错误处理

用Lua_Tinker从C++环境往Lua环境注入错误处理函数,以_ALERT为函数标识

[dongsong@localhost LuaTinker-master]$ cat sample5.lua 
function test_error()
        print("test_error() called !!")
        test_error_1()
end

function test_error_1()
        print("test_error_1() called !!")
        test_error_2()
end

function test_error_2()
        print("test_error_2() called !!")
        test_error_3()
end

[dongsong@localhost LuaTinker-master]$ cat sample5.cpp 
extern "C" 
{
        #include "lua.h"
        #include "lualib.h"
        #include "lauxlib.h"
};
#include "lua_tinker.h"
void show_error(const char* error)
{
        printf("_ALERT -> %s\n", error);
}
int main()
{
        lua_State* L = lua_open();
        luaopen_base(L);

        printf("%s\n","-------------------------- current stack");
        lua_tinker::enum_stack(L);

        lua_pushnumber(L, 1);

        printf("%s\n","-------------------------- stack after push '1'");
        lua_tinker::enum_stack(L);

        lua_tinker::dofile(L, "sample5.lua");

        printf("%s\n","-------------------------- calling test_error()");
        lua_tinker::call<void>(L, "test_error");

        printf("%s\n","-------------------------- calling test_error_3()");
        lua_tinker::call<void>(L, "test_error_3");

        lua_tinker::def(L, "_ALERT", show_error);

        lua_tinker::call<void>(L, "_ALERT", "test !!!");

        printf("%s\n","-------------------------- calling test_error()");
        lua_tinker::call<void>(L, "test_error");

        lua_close(L);
        return 0;
}

[dongsong@localhost LuaTinker-master]$ g++ -o sample5 sample5.cpp libluatinker.a 
[dongsong@localhost LuaTinker-master]$ ./sample5
-------------------------- current stack
Type:2
        table   0x0x140b6b0
        table   0x0x140d580
-------------------------- stack after push '1'
Type:3
        table   0x0x140b6b0
        table   0x0x140d580
        number  1.000000
-------------------------- calling test_error()
test_error() called !!
test_error_1() called !!
test_error_2() called !!
sample5.lua:13: attempt to call global 'test_error_3' (a nil value)
        <call stack>
->      test_error_3() : line -1 [=[C] : line -1]
        test_error_2() : line 13 [@sample5.lua : line 11]
        test_error_1() : line 8 [@sample5.lua : line 6]
        unknown : line 3 [@sample5.lua : line 1]
-------------------------- calling test_error_3()
lua_tinker::call() attempt to call global `test_error_3' (not a function)
_ALERT -> test !!!
-------------------------- calling test_error()
test_error() called !!
test_error_1() called !!
test_error_2() called !!
_ALERT -> sample5.lua:13: attempt to call global 'test_error_3' (a nil value)
_ALERT ->       <call stack>
_ALERT -> ->    test_error_3() : line -1 [=[C] : line -1]
_ALERT ->       test_error_2() : line 13 [@sample5.lua : line 11]
_ALERT ->       test_error_1() : line 8 [@sample5.lua : line 6]
_ALERT ->       unknown : line 3 [@sample5.lua : line 1]

6.sample6

协程(coroutine): http://www.lua.org/manual/5.1/manual.html#lua_resume

Python中也有类似概念:见yield实现迭代器(http://docs.python.org/2/reference/expressions.html#yieldexpr)和python并行编程库concurrence(http://blog.csdn.net/xiarendeniao/article/details/9143059)

[dongsong@localhost LuaTinker-master]$ cat sample6.lua
function ThreadTest()
        print("ThreadTest ")

        print("TestFunc ")
        TestFunc()
        TestFunc2(1.2)
        print("TestFunc ")

        print("g_test::TestFunc() ")
        g_test:TestFunc()
        g_test:TestFunc2(2.3)
        print("g_test::TestFunc() ")

        print("ThreadTest ")
end
[dongsong@localhost LuaTinker-master]$ cat sample6.cpp
extern "C" 
{
        #include "lua.h"
        #include "lualib.h"
        #include "lauxlib.h"
};
#include "lua_tinker.h"

int TestFunc(lua_State* L)
{
        printf("# TestFunc \n");
        return lua_yield(L, 0); //协程挂起
}

int TestFunc2(lua_State* L, float a)
{
        printf("# TestFunc2(L,%f) \n", a);
        return lua_yield(L, 0);
}

class TestClass
{
public:
        int TestFunc(lua_State* L) {
                printf("# TestClass::TestFunc \n");
                return lua_yield(L, 0);
        }

        int TestFunc2(lua_State* L, float a) {
                printf("# TestClass::TestFunc2(L,%f) \n", a);
                return lua_yield(L, 0);
        }
};

int main()
{
        lua_State* L = lua_open();

        luaopen_base(L);
        luaopen_string(L);

        lua_tinker::def(L, "TestFunc", &TestFunc);
        lua_tinker::def(L, "TestFunc2", &TestFunc2);

        lua_tinker::class_add<TestClass>(L, "TestClass");
        lua_tinker::class_def<TestClass>(L, "TestFunc", &TestClass::TestFunc);
        lua_tinker::class_def<TestClass>(L, "TestFunc2", &TestClass::TestFunc2);

        TestClass g_test;
        lua_tinker::set(L, "g_test", &g_test);

        lua_tinker::dofile(L, "sample6.lua");

        //To start a coroutine, you first create a new thread (see lua_newthread); then you push onto its stack the main function plus any arguments; then you call lua_resume, with narg being the number of arguments.
        lua_newthread(L); //创建线程
        lua_pushstring(L, "ThreadTest"); //把线程的main函数压入栈中
        lua_gettable(L, LUA_GLOBALSINDEX);

        printf("* lua_resume() \n");
        //线程main函数的参数个数为0
        //lua_resume返回后,Lua栈中记录lua_yield的返回值或mian函数的返回值
        //lua_resume返回值:LUA_YIELD 协程被挂起; 0 mian函数顺利结束;errorcode main函数运行出错
        lua_resume(L, 0);

        printf("* lua_resume() \n");
        lua_resume(L, 0);

        printf("* lua_resume() \n");
        lua_resume(L, 0);

        printf("* lua_resume() \n");
        lua_resume(L, 0);

        printf("* lua_resume() \n");
        lua_resume(L, 0);

        lua_close(L);
        return 0;
}

[dongsong@localhost LuaTinker-master]$ g++ -o sample6 sample6.cpp libluatinker.a 
[dongsong@localhost LuaTinker-master]$ ./sample6 
* lua_resume() 
ThreadTest 
TestFunc 
# TestFunc 
* lua_resume() 
# TestFunc2(L,1.200000) 
* lua_resume() 
TestFunc 
g_test::TestFunc() 
# TestClass::TestFunc 
* lua_resume() 
# TestClass::TestFunc2(L,2.300000) 
* lua_resume() 
g_test::TestFunc() 
ThreadTest 
================================================================================================

Extending Lua with C/C++ (编写lua的so扩展库)

http://www.lua.org/manual/5.2/readme.html

to dynamically load C libraries for Lua you'll need to know how to create dynamic libraries and you'll need to make sure that the Lua API functions are accessible to those dynamic libraries — but don't link the Lua library into each dynamic library.

[dongsong@localhost worldpacket]$ g++ -c -fPIC external.cpp lua_tinker.cpp -I/home/dongsong/liblua/include
[dongsong@localhost worldpacket]$ ls -lhrt
total 208K
-rw-r--r--. 1 dongsong dongsong 4.1K Aug 14 11:29 WorldPacket.h
-rw-r--r--. 1 dongsong dongsong  11K Aug 14 11:29 ByteBuffer.h
-rw-rw-r--. 1 dongsong dongsong 2.9K Aug 14 11:35 main.cpp
-rw-rw-r--. 1 dongsong dongsong   42 Aug 14 17:49 hello.cpp
-rwxrwxr-x. 1 dongsong dongsong  31K Aug 14 18:04 main
-rw-rw-r--. 1 dongsong dongsong  28K Aug 14 19:55 lua_tinker.h
-rw-rw-r--. 1 dongsong dongsong  17K Aug 14 19:55 lua_tinker.cpp
-rw-rw-r--. 1 dongsong dongsong 5.8K Aug 14 20:04 external.cpp
-rw-rw-r--. 1 dongsong dongsong  59K Aug 14 20:54 external.o
-rw-rw-r--. 1 dongsong dongsong  30K Aug 14 20:54 lua_tinker.o
[dongsong@localhost worldpacket]$ g++ -shared -o external.so external.o lua_tinker.o
[dongsong@localhost worldpacket]$ ls -lhrt
total 276K
-rw-r--r--. 1 dongsong dongsong 4.1K Aug 14 11:29 WorldPacket.h
-rw-r--r--. 1 dongsong dongsong  11K Aug 14 11:29 ByteBuffer.h
-rw-rw-r--. 1 dongsong dongsong 2.9K Aug 14 11:35 main.cpp
-rw-rw-r--. 1 dongsong dongsong   42 Aug 14 17:49 hello.cpp
-rwxrwxr-x. 1 dongsong dongsong  31K Aug 14 18:04 main
-rw-rw-r--. 1 dongsong dongsong  28K Aug 14 19:55 lua_tinker.h
-rw-rw-r--. 1 dongsong dongsong  17K Aug 14 19:55 lua_tinker.cpp
-rw-rw-r--. 1 dongsong dongsong 5.8K Aug 14 20:04 external.cpp
-rw-rw-r--. 1 dongsong dongsong  59K Aug 14 20:54 external.o
-rw-rw-r--. 1 dongsong dongsong  30K Aug 14 20:54 lua_tinker.o
-rwxrwxr-x. 1 dongsong dongsong  68K Aug 14 20:54 external.so
[dongsong@localhost worldpacket]$ lua
Lua 5.2.3  Copyright (C) 1994-2013 Lua.org, PUC-Rio
> =package.cpath
/usr/local/lib/lua/5.2/?.so;/usr/local/lib/lua/5.2/loadall.so;./?.so
> external=require "external"
error loading module 'external' from file './external.so':
        ./external.so: undefined symbol: luaopen_external
stack traceback:
        [C]: in ?
        [C]: in function 'require'
        stdin:1: in main chunk
        [C]: in ?
---->

---->用nm external.so查看动态库中的符号,发现确实没有"luaopen_external",只有一个"_Z16luaopen_externalP9lua_State"

在lua中用require "xxx"加载c动态库时会驱使lua vm加载xxx.so并寻找luaopen_xxx符号,执行此函数以返回table作为xxx库的功能函数表

For instance,if the C path is the string

     "./?.so;./?.dll;/usr/local/?/init.so"

the searcher for module foowill try to open the files ./foo.so,./foo.dll,and/usr/local/foo/init.so, in that order.Once it finds a C library,this searcher first uses a dynamic link facility to link theapplication with the library.Then it tries to find a C function inside the library tobe used as the loader.The name of this C function is the string "luaopen_"concatenated with a copy of the module name where each dotis replaced by an underscore.Moreover, if the module name has a hyphen,its prefix up to (and including) the first hyphen is removed.For instance, if the module name is a.v1-b.c,the function name will beluaopen_b_c.

The fourth searcher tries an all-in-one loader.It searches the C path for a library forthe root name of the given module.For instance, when requiringa.b.c,it will search for a C library fora.If found, it looks into it for an open function forthe submodule;in our example, that would beluaopen_a_b_c.With this facility, a package can pack several C submodulesinto one single library,with each submodule keeping its original open function.

这里就是一个需要使用extern的活生生的例子,把luaopen_external函数用extern "C" 括起来就ok了

[dongsong@localhost worldpacket]$ lua 
Lua 5.2.3  Copyright (C) 1994-2013 Lua.org, PUC-Rio
> require "external"
attempt to index a string value
stack traceback:
        [C]: in ?
        [C]: in function 'require'
        stdin:1: in main chunk
        [C]: in ?
> 
---->

----> 果然!错误不一样了!特么的...

luaL_newlibtable(L, l);

luaL_setfuncs(L,l,0); //没有要导入的upvalue放在栈顶,所以第三个参数应该是0;这里笔误写成1所以才导致上面的错误(貌似是在栈里面访问了不该访问的条目)

还有一个导致"attempt to index a string value"的错误是对LUA_RIDX_GLOBALS的使用(lua_settable(L, LUA_RIDX_GLOBALS);)

5.2去掉了LUA_GLOBALSINDEX(lua_settable(L, LUA_GLOBALSINDEX); 以-2为key、-1为value设置到全局_G表中),引入了LUA_RIDX_GLOBALS

我想当然的以为lua_settable(L, LUA_RIDX_GLOBALS)会实现5.1中设置修改_G表的功能(registry table中有registry[2] = _G table这个条目)

这个问题没找到解决办法,只好把改用lua_setglobal(l, const char* name)来替换

extern "C" {
    int luaopen_external(lua_State *L) {
        //lua_pushstring(L, "xds_key");
        lua_pushstring(L, "xds_value");
        //lua_settable(L, LUA_RIDX_GLOBALS);    //error: attempt to index a string value
        //lua_settable(L, LUA_REGISTRYINDEX);   //right! registry["xds_key"] = "xds_value"
        lua_setglobal(L, "xds_key");            //right! _G["xds_key"] = "xds_value"
		...
        return 1;
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值