现在的位置: 首页 > 综合 > 正文

从 dll 到 so 之路

2013年12月13日 ⁄ 综合 ⁄ 共 2170字 ⁄ 字号 评论关闭

在 linux 上编程,离不开 make, 自己写 makefile 文件,太麻烦!并且 dll 工程的 .vcproj 文件中保存了源代码的依赖关系和编译信息,要是能把它转换成 makefile 文件就好了。GOOGLE 一下,果然有这样的工具,选了codeproject 上的 sln2mak,具体下载地址是 http://www.codeproject.com/KB/cross-platform/sln2mak.aspx 。

这个工具很好用,但第一次转换就崩溃了,用源代码一调,原来是我的 sln 文件中保存的是 icproj 文件(Intel编译器的工程文件)信息,在 vs2005 中把它转回 vc 工程即可。

将 DllMain 改成

#ifdef WIN32

BOOL APIENTRY DllMain( HANDLE hModule, 
                       DWORD  ul_reason_for_call, 
                       LPVOID lpReserved
					 )
{
	switch (ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH:
		GLOBAL_Init();
		break;

	case DLL_THREAD_ATTACH:
		break;

	case DLL_THREAD_DETACH:
		break;

	case DLL_PROCESS_DETACH:
		GLOBAL_Uninit();
		break;
	
	default:
		;
	}
	return TRUE;
}

#else

void SO_Load() __attribute__((constructor));
void SO_Unload() __attribute__((destructor));

void SO_Load()
{
	GLOBAL_Init();
}

void SO_Unload()
{
	GLOBAL_Uninit();
}

#endif

//GLOBAL_Init、GLOBAL_Uninit 是自定义函数,做全局的初始化和释放工作。

对所有调用 windows API 和 头文件 的地方都要加上相应 linux 版本的处理,类似以上对 DllMain 的操作。

转换好后会生成一个 Makefile 文件 和一个 projectname.mak 文件,连同整个工程一起考到 linux 下。

在一个终端中进入当前工程目录,然后make,会提示“找不到 projectname.mak 文件”,打开 Makefile,把其中的 “cd && $(MAKE)” 都改成 “cd . && $(MAKE)” 或者 “$(MAKE)”。

再 make,会提示“找不到 -l -lstdc++",打开 projectname.mak 文件,把其中的 “-l -lstdc++” 都改成 “-lstdc++”,这里多了一个空 -l 。

这时如果开发环境安装完善的话(否则会提示找不到一些系统库,在 CentOS 中可以使用 “yum -y install 文件名” 来安装),应该能得到一个 projectname.dll ,它虽然叫 dll,却已是共享库了,为了规范命名,可以在 projectname.mak 文件中把 TARGET=projectname.dll 改成 TARGET=libprojectname.so。

可以用 readelf -s libprojectname.so 来查看so文件中所有的导出变量和函数。

需要注意的几个问题:

1、对 __declspec(dllexport) 和 __stdcall,在 linux 版本中要把它们定义成空。

2、linux 下对目录/文件名区分大小写,如果程序中有相对路径,需特别注意大小写正确。

3、projectname.mak 这个文件结构比较简单,它通过一个 CFG 变量来判断当前的编译版本,是 Debug、Release 或 其他,紧接着是每种编译版本对应的编译链接选项,最后是编译命令。这里很多 windows 相关的 宏、资源文件 和 dep 文件,都可以去掉。

4、如果程序中用到第三方库中的函数,并且要导入so文件,需要在链接选项中加上 -u func_name1 -u func_name2 ... -L库路径 -l库文件,否则这些函数不会被自动链接进so文件。如果有很多这样的函数,可以建立一个文本文件,比如 func_list,把所有函数名写入其中,每行一个,然后在 projectname.mak 文件中添加变量 FUNCLIST=$(addprefix -u ,$(shell grep -v '^[\#;]' "func_list")),在 “LDFLAGS=”
后加入 $(FUNCLIST) ,这样 make 的时候会自动列举文本中的函数名。

5、对 MKL,还有点特殊的地方,就是用 -lmkl_intel -lmkl_intel_thread -lmkl_core 不能做到静态链接(加 -static 也不行),只能用 -Wl,--start-group $(MKLROOT_LIB_IA32)/libmkl_intel.a $(MKLROOT_LIB_IA32)/libmkl_intel_thread.a  $(MKLROOT_LIB_IA32)/libmkl_core.a -Wl,--end-group,才能静态链接。($(MKLROOT_LIB_IA32)
是自己定义的宏,用 root 权限写入 /etc/profile,MKLROOT_LIB_IA32="/opt/intel/mkl/lib/ia32" export MKLROOT_LIB_IA32。)

抱歉!评论已关闭.