tuxedo12.1.1.0 libtux导出函数的错误

来源:互联网 发布:阿里云服务器怎么镜像 编辑:程序博客网 时间:2024/05/17 01:31

      最近在学习tuxedo,想在以前用MFC写的系统中运用tuxedo,虽然tuxedo一般用在linux系统中,但其实在开发使用tuxedo中间件的三层架构应用系统中,表示层也经常采用windows风格的程序,由于tuxedo的跨平台特性,便可以把后台应用逻辑运行在unix平台下。

     于是在oracle官网上下载了tuxedo12110_64_win_2k8_x86_VS2010.exe,这个是windows上最新的版本,安装好后,便开始使用里面的那个simpapp的例子测试下是否可以使用。

    例子中客户端源程序如下:    

#include<stdio.h>#include<string.h>#include<stdlib.h>#include "atmi.h"/* TUXEDO  Header File */int main(int argc,char *argv[]){char *sendbuf, *rcvbuf;long sendlen, rcvlen;int ret;if(argc != 2) {(void) fprintf(stderr, "Usage: simpcl string\n");exit(1);}/* Attach to System/T as a Client Process */if (tpinit((TPINIT *) NULL) == -1) {(void) fprintf(stderr, "Tpinit failed\n");exit(1);}sendlen = strlen(argv[1]);/* Allocate STRING buffers for the request and the reply */if((sendbuf = (char *) tpalloc("STRING", NULL, sendlen+1)) == NULL) {(void) fprintf(stderr,"Error allocating send buffer\n");tpterm();exit(1);}if((rcvbuf = (char *) tpalloc("STRING", NULL, sendlen+1)) == NULL) {(void) fprintf(stderr,"Error allocating receive buffer\n");tpfree(sendbuf);tpterm();exit(1);}(void) strcpy(sendbuf, argv[1]);/* Request the service TOUPPER, waiting for a reply */ret = tpcall("TOUPPER", (char *)sendbuf, 0, (char **)&rcvbuf, &rcvlen, (long)0);if(ret == -1) {(void) fprintf(stderr, "Can't send request to service TOUPPER\n");(void) fprintf(stderr, "Tperrno = %d\n", tperrno);tpfree(sendbuf);tpfree(rcvbuf);tpterm();exit(1);}(void) fprintf(stdout, "Returned string is: %s\n", rcvbuf);/* Free Buffers & Detach from System/T */tpfree(sendbuf);tpfree(rcvbuf);tpterm();return(0); }
   

    可是在使用buildclient命令生成可执行程序时却出现如下错误:

    

    

      从编译输出的信息看,tuxedo使用了自带的静态函数库,

       C:\bea\tuxedo12.1.1.0_VS2010\lib\libtux.lib

       C:\bea\tuxedo12.1.1.0_VS2010\lib\libbuft.lib

       C:\bea\tuxedo12.1.1.0_VS2010\lib\libfml.lib

       C:\bea\tuxedo12.1.1.0_VS2010\lib\libfml32.lib

       C:\bea\tuxedo12.1.1.0_VS2010\lib\libengine.lib

       由于buildclient在windows上是调用VS的cl编译器,所以当然也使用了windows的几个静态输出库wsock32.lib、kernel32.lib、advapi32.lib、user32.lib、gdi32.lib、comdlg32.lib、winspool.lib。

       可是为什么会出现simpcl.obj :error LNK2019: unresolved external symbol _tpalloc@12 referenced in function_main 这样的错误呢,我们知道,就是因为编译器在连接阶段找不到tpcall的实现,我们不是包含了libtux.lib等库文件吗?

       首先了,当然是检查配置文件和系统环境变量,在反复核实了之后,确定不是配置的问题,所以从理论上来说,使用这个buildclient应该是没有问题的。

      然后,在百度和谷歌上用unresolvedexternal symbol _tpalloc@12 referenced in function _main搜索,结果,没有一个链接是与这个有_tpalloc@12(当然也可以是其他的函数)关的。这个结果说明,要么这个问题是个很傻逼的问题,要么是个史无前例的问题。

      后来请教同事,同事是玩linux c++的,由于gcc 在指定源文件和库文件的时候一般是有先后顺序的,就建议我libfml.lib和libfml32.lib在链接时放在最后面,以免是文件依赖导致的。本来呢这个链接顺序是buildclient自动指定的,但是我还是用buildclient –l 指定了一下,结果还是一样。

      一个问题捣鼓了几个小时,还没解决,我一般会放一放,说不定什么时候灵感就来了。果然,在吃晚饭的时候,我突然想起来_tpalloc@12这个字符串,当时出现问题的时候总是在找路径啊,配置的原因,这下子突然反应过来,为什么是_tpalloc@12而不是_tpalloc呢,或者是其他的呢?显然tpalloc函数名被cl编译器改编为为_tpalloc@12说明了tpalloc的调用约定是标准调用约定_stdcall,同时编译的是C源程序而不是C++源程序。于是在tuxedo的include目录的atmi.h头文件中搜索tpalloc,发现其声明为:

      extern char      _TM_FAR * _TMDLLENTRY tpalloc _((char_TM_FAR *, char _TM_FAR *, long)); 然后在tmenv.h 中查找到 _TMDLLENTRY的定义为:

   #define     _TM_FAR

   #define _TM_NEAR

   #ifdefined(__BORLANDC__) && !defined(__cplusplus)

   #define     _TMDLLENTRY         __declspec(dllexport)__stdcall

   #else

   #define     _TMDLLENTRY         __stdcall

   #endif


     从这段代码中可以看出来,tuxedo在导出静态库库的时候应该使用了这个atmi.h头文件,因为__declspec(dllexport)的存在可以说明。同时更加重要的是,_TMDLLENTRY    不管在哪种情况下都被定义为__stdcall,也就是说,tpalloc确实是使用标准调用约定。那么难倒tuxedo提供的静态库中不存在tpalloc的函数实现吗?也就是说没有从tpalloc导出一个叫_tpalloc@12的函数符号吗?windows下可以使用VS提供的一个工具dumpbin工具查看导出的符号名称:

     那么先从libtux.lib看起,

    c:\bea_64\tuxedo12.1.1.0_VS2010\lib>dumpbin–exports libtux.lib>>libtux_exports.txt

    由于导出的符号很多,将输出信息写进libtux_exports.txt中便于查看。搜索tpcall便可以查看到:

           433      tpabort

           434      tpacall

           435      tpadvertise

           436      tpalloc

           1180    tpappthrinit

           1181    tpappthrterm

          1255     tpatz

           437      tpbegin

     由此可以看出,libtux.lib导出的函数名即为tpcall,而编译器将其在目标文件的符号表中解释为_tpcall@24,当然找不到了。接着导出其他几个库的符号信息,用tpcall关键字搜索均没有搜到,也就是说,tpcall确实是在libtux.lib中导出的。同时,可以知道,tuxedo在导出库的时候,并没有使用atmi.h头文件,而是使用了一种模块定义文件直接指定了导出函数的名称:

   LIBRARY libtux.lib

   EXPORTS

       ……

       tpcall

      …….

      也就是说,根本原因就是tuxedo提供的libtux.lib库有问题。

      而且这个是静态链接库,不能使用动态加载,如果是动态链接库,我们到可以直接使用tpcall。

      

    HINSTANCE hInst=LoadLibrary((LPCWSTR)"libtux.dll");//如果是dll    typedef char* (*ADDRPROC)(char *,char*,long);    ADDRPROCAddProc=(ADDRPROC)GetProcAddress(hInst,"tpalloc");    if(AddProc!=NULL){        sendbuf=AddProc("STRING",NULL, sendlen+1);    }

      后来,我下载了个32位的tuxedo111120_32_win_2k8_x86_VS2008.exe,装上之后直接看libtux.lib的导出库,果然是

    

      

        然后进行测试,就没问题了。

      

       后来,我把64位的又安装了一遍,还是之前的那个错误,并不是安装的问题。

        突然想起光耀的一句话,跟Java有关的软件都很扯淡。

        如你所见,确实很扯淡。

        这篇文章发表之后,使用tuxedo12110_64_win_2k8_x86_VS2010和_tpalloc@12 等关键字就可以在百度上搜索出该问题了,之前,是没有任何链接可以参考的。

   


原创粉丝点击