符号查找错误:在64位上组合可执行文件和库

时间:2010-11-25 20:07:03

标签: c++ linker 64-bit 32bit-64bit

我想在使用可执行文件符号的库上进行dlopen。我正在64位系统上编译gdl-0.9,我正在构建一个gdl将使用dlopen的库。问题是该库使用的gdl代码将位于可执行文件中,即使我使用 -Wl, - export-dynamic 标志,程序也会崩溃并且打印: gdl:符号查找错误:./ twwo.so:未定义符号:_ZN4EnvT6NParamEj

以下是我做事的方式:

将two.cpp编译为共享库two.so。

// two.cpp
#include "envt.hpp"

using namespace std;

template< typename T>
BaseGDL* two_fun_template( BaseGDL* p0)
{
  T* p0C = static_cast<T*>( p0);
  T* res = new T( p0C->Dim(), BaseGDL::NOZERO);
  SizeT nEl = p0->N_Elements();
  for( SizeT i=0; i<nEl; ++i)
    {
      (*res)[ i] = 2 * ((*p0C)[ i]);
    }
  return res;
}

extern "C" BaseGDL* two_fun( EnvT* e)
{

  SizeT nParam=e->NParam();
  if (nParam != 1) {
    cout << "TWO: Improper Number of Variables" << endl;
    return new DLongGDL( -1);
  }

  BaseGDL* p0 = e->GetPar( 0);//, "TWO");

  if( p0->Type() == DOUBLE)
    return two_fun_template< DDoubleGDL>( p0);
  else if( p0->Type() == FLOAT)
    return two_fun_template< DFloatGDL>( p0);
  else 
    {
      return new DLongGDL( -1);
    }
}

使用“Ubuntu 10.04.1 LTS”预构建gdl。

$ gdl
GDL - GNU Data Language, Version 0.9
For basic information type HELP,/INFO
'GDL_STARTUP'/'IDL_STARTUP' environment variables both not set.
No startup file read.
GDL> linkimage,'TWO','./two.so',1,'two_fun'
GDL> print, "TWO Loaded"
GDL> print, two(1.0)
gdl: symbol lookup error: ./two.so: undefined symbol: _ZN4EnvT6NParamEj

所以我认为问题出在执行此行时:SizeT nParam = e-&gt; NParam();

接下来,我获得了gld-0.9源代码,使用 -Wl, - export-dynamic 进行了整个编译,并发生了同样的错误。

接下来,我使用-m32标志(强制32位)和:

完成整个编译
$ ../gdl32
GDL - GNU Data Language, Version 0.9
For basic information type HELP,/INFO
'GDL_STARTUP'/'IDL_STARTUP' environment variables both not set.
No startup file read.
GDL> linkimage,'TWO','./two.so',1,'two_fun'
GDL> print, "TWO Loaded"
GDL> print, two(1.0)
      2.00000
GDL>

所以我猜这意味着它是64位问题,但为什么呢?我在网上搜索了很多,除了 -Wl, - export-dynamic 之外没找到任何其他内容,也许我不知道怎么看或者其他的东西。有人可以帮忙吗?

顺便说一句,这是我在运行“nm”工具时得到的结果。

64位:

$ nm two.so | grep NParam
                 U _ZN4EnvT6NParamEj
$ nm ../gdl64 | grep NParam
00000000006dc320 T _ZN4EnvT6NParamEy

32位:

$ nm two.so | grep NParam
         U _ZN4EnvT6NParamEj
$ nm ../gdl32 | grep NParam
0830a6a0 T _ZN4EnvT6NParamEj

3 个答案:

答案 0 :(得分:3)

_ZN4EnvT6NParamEjEnvT::NParam(unsigned int)
_ZN4EnvT6NParamEyEnvT::NParam(unsigned long long)

因此,您应该首先看看如何包含EnvT的声明。您需要查看NParam的参数类型,并找到重新定义的位置。

答案 1 :(得分:1)

我不知道您是否仍然可以使用帮助,但是为了编译这两个函数以及64位的所有其他函数,您应该在g ++命令中添加-DHAVE_64BIT_OS选项。这样预处理器就可以在typedefs.hpp中为SizeT设置正确的类型。 所以编译将是

g ++ -DHAVE_64BIT_OS -I /(gdl src的路径)-c two.cpp -fpic

所有其他命令保持不变。

答案 2 :(得分:0)

nm输出看起来类型不同 - 可执行文件有_ZN4EnvT6NParamEy,而库需要_ZN4EnvT6NParamEj。如你所见,最后一个字母不同。