编译lua5.3扩展.so文件时遇到的一些问题总结

最近尝试在linux下写一些lua的扩展函数,即.so文件,遇到的一些问题总结一下

1.如果编译.cpp结尾的C++文件时,在那个函数函数前一定要加extern "C"

如果遇到编译时说类似如下文字的:

/usr/bin/ld: /usr/local/lib/liblua.a(lapi.o): relocation R_X86_64_32 against `luaO_nilobject_' can not be used when making a shared object; recompile with -fPIC
/usr/local/lib/liblua.a: could not read symbols: 错误的值
collect2: 错误:ld 返回 1
make: *** [mylib.so] 错误 1


这个是因为lualib.a是不支持so文件重定向的,这个问题搞了我不少时间,最后在国外的大神解答了:

地址:http://superuser.com/questions/557884/getting-error-recompile-with-fpic

At this point in asterisk, you're trying to build a dynamic lib. Since this dynamic lib can be loaded at any memory location, everything needs to be relocatable. The -fPIC flag means Position Independent Code, the code is made to be independent of load location - loaded anywhere.

As part of this asterisk dynamic lib build, it's trying to bring in the Lua interpreter. Since it's bringing into a dynamic lib, it needs everything compiled PIC. But you're using a static lib of lua, which was not built with -fPIC. It rejects this, since the lua objects in the static lib can not be relocated. 

BTW: this is why adding -fPIC to the asterisk build won't help. It's not your asterisk code objects that are incompatible (which -fPIC can affect), but liblua.a, specifically the objects carried by liblua.a (e.g lapi.o). Besides, you're building a dynamic lib at that point, and Im sure you already have relocatable code flags such as -fPIC for the asterisk objects you're trying to pull together at that point.

I see three solutions. 

•One is to drop lua from your build. If you don't need it specifically and were thinking more that "this may be fun to play with later" you may be able to and not lose wanted features.


•Another is to get a dynamic version of liblua, liblua.so, one that can be referenced in your asterisk build. I don't know your distro, so I can't say how to get it.


•The other, more pain in the ass one, is to rebuild lua, and liblua.a, with -fPIC. You'd have compatibility issues maybe from inconsistent build flags (what you made and what else is on disk), so I think finding a liblua.so to match your currently built lua is the better option. 


If you find liblua.so, you may want to look into the '-rpath' linker flag for this though, specifically '-Wl,-rpath,/path/to/lua/libs'

这位大神提供了3种解决方案,我用了第3种,即重新编译lua,并且在编译lua时加上编译选项 -fPIC,编译完后,果然就可以链接成功了(这个真心坑啊!)



重新编译完lua之后,我又尝试看怎么用C写扩张给lua使用,当我按着网上各种模版写的时候,发现lua运行程序加载我写的.so文件时,出现

Error: multiple Lua VMs detected

这个错误,后来又上网找了一下,说原因是c调用lua时已经有个一个lua虚拟机了,如果要lua里面调用扩张模块,必须链接不要链接lualib.a这个东西,真是看得我一头晕

最后他们解释说加个编译选线 -Wl,-E即可

Don't link your C module with liblua.a when you create a .so from it. For examples, see my page of Lua libraries: http://www.tecgraf.puc-rio.br/~lhf/ftp/lua/ . You can link liblua.a statically into your main program but you have to export its symbols by adding -Wl,-E at link time. That's how the Lua interpreter is built in Linux.


注意 [ -Wl,-E ] 是连在一起的,中间那个逗号不能去掉哦


附参考程序:

luatest.cpp:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <lua.hpp>

static int c_cont (lua_State *L, int status, lua_KContext ctx)
{
	printf("c_count status:%d\n",status);
	printf("c_count ctx:%d\n", ctx);
	return 0;
}

static int c_callback(lua_State *L){
  /* 使用 lua_pcallk,而不是lua_pcall */
    lua_getglobal(L, "run");
	int ret = lua_pcallk(L, 0, 0, 0, 0, c_cont);
	printf("ret = %d\n",ret);
	if(ret) {
		fprintf(stderr, "Error: %s\n", lua_tostring(L, -1));
		lua_pop(L, 1);
		exit(1);
	}
	return 0;
}

int main()
{
	struct lua_State * L;
	L = luaL_newstate();
	luaL_openlibs(L);
	int ret = luaL_dofile(L,"main.lua");
	if (ret != LUA_OK)
	{
		fprintf(stderr, "Error: %s\n", lua_tostring(L, -1));
		lua_pop(L, 1);
		return 0;
	}
	while (true)
	{
		printf("c:runing lua\n");
//		lua_getglobal(L, "run");
//		lua_pcall(L, 0, 0, 0);
		c_callback(L);
		sleep(1);
	}
	return 0;
}



mylib.cpp:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <lua.hpp>

extern "C" int add(struct lua_State * L)
{
	double op1 = luaL_checknumber(L,1);
	double op2 = luaL_checknumber(L,2);
	lua_pushnumber(L,op1 + op2);
	return 1;
}

static struct luaL_Reg libs[] = {
		{"add", add},
		{NULL, NULL}
};

extern "C" int luaopen_mylib(struct lua_State * L)
{
	luaL_newlib(L, libs);
	return 1;
}


Makefile:

all : mylib.so test

mylib.so : lib.cpp
	g++ lib.cpp -fPIC -shared -llua -o mylib.so

test : luatest.cpp
	g++ -o test luatest.cpp -llua -ldl -lm -Wl,-E

main.lua:

--package.cpath = package.cpath .. ";*.a";
local co = nil;
local mylib = require("mylib");

local function cofunc()
	for i = 1,10 do
		print(i);
		if (i < 10) then
			coroutine.yield();
		end
	end
	local file = io.open("txt","a");
	print(file:read("*all"));
	co = nil
end

function run()
	print("lua runing..");
	if (nil == co) then
		co = coroutine.create(cofunc);
	end
	print(mylib.add(5200000,1314));
	coroutine.resume(co);
end





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值