从 dll 到 so 之路
在 linux 上编程,离不开 make, 自己写 makefile 文件,太麻烦!并且 dll 工程的 .vcproj 文件中保存了源代码的依赖关系和编译信息,要是能把它转换成 makefile 文件就好了。GOOGLE 一下,果然有这样的工具,选了codeproject 上的 sln2mak,具体下载地址是 http://www.codeproject.com/KB/cross-platfor
在 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。)
更多推荐
所有评论(0)