【问题标题】:MAGICS - undefined symbol: _ZTIN5eckit9ExceptionE魔法 - 未定义的符号:_ZTIN5ekit9ExceptionE
【发布时间】:2016-10-18 14:42:59
【问题描述】:

我遇到了类似这样的运行时错误“未定义符号:_ZTIN5ekit9ExceptionE”

Start  2: basic_python
2: Test command: /usr/local/Python/2.7.10/bin/python "coast.py"
2: Environment variables:
2:  PYTHONPATH=/opt/src/ecmwf/Magics-2.29.4-Source/build/python
2:  LD_LIBRARY_PATH=/opt/src/ecmwf/Magics-2.29.4-Source/build/lib
2:  MAGPLUS_HOME=/opt/src/ecmwf/Magics-2.29.4-Source/test/..
2:  OMP_NUM_THREADS=1
2: Test timeout computed to be: 1500
2: Traceback (most recent call last):
2:   File "coast.py", line 11, in <module>
2:     from Magics.macro import *
2:   File "/opt/src/ecmwf/Magics-2.29.4-Source/build/python/Magics/__init__.py", line 32, in <module>
2:     _Magics = swig_import_helper()
2:   File "/opt/src/ecmwf/Magics-2.29.4-Source/build/python/Magics/__init__.py", line 28, in swig_import_helper
2:     _mod = imp.load_module('_Magics', fp, pathname, description)
2: ImportError: /usr/local/Magics/2.29.4/gnu/4.4.7/lib/libMagPlus.so: undefined symbol: _ZTIN5eckit9ExceptionE

构建共享 libaray libMagPlus.so 时没有错误。该错误只是在 Python 模块加载时在运行时引发的。

用nm检查,未定义的符号'_ZTIN5ekit9ExceptionE'来自静态库libOdb.a,像这样

nm libOdb.a | grep _ZTIN5eckit9ExceptionE
                 U _ZTIN5eckit9ExceptionE
                 U _ZTIN5eckit9ExceptionE
                 U _ZTIN5eckit9ExceptionE
                 U _ZTIN5eckit9ExceptionE
                 U _ZTIN5eckit9ExceptionE
                 U _ZTIN5eckit9ExceptionE
0000000000000000 V DW.ref._ZTIN5eckit9ExceptionE
                 U _ZTIN5eckit9ExceptionE
                 U _ZTIN5eckit9ExceptionE
                 U _ZTIN5eckit9ExceptionE
                 U _ZTIN5eckit9ExceptionE
                 U _ZTIN5eckit9ExceptionE
                 U _ZTIN5eckit9ExceptionE

但是对于在编译时和运行时直接链接到静态库 libOdb.a 的可执行文件,没有任何关于未定义符号“_ZTIN5ekit9ExceptionE”的投诉。除共享库 libMagPlus.so 外,所有 C、Fortran 代码也可与静态库 libOdb.a 很好地配合使用。

LibMagPlus.so 库是这样链接的

/usr/bin/g++ -fPIC -pipe -O2 -g \
-Wl,--disable-new-dtags -shared \
-Wl,-soname,libMagPlus.so -o ../lib/libMagPlus.so \
... ...  \
-Wl,-Bstatic -L$ODB_API/lib -lOdb \
... ...

libOdb.a 库是这样构建的

usr/bin/ar qc ../../lib/libOdb.a  ... ...

/usr/bin/ranlib ../../lib/libOdb.a

搜索了常见问题解答和谷歌搜索,对我的问题帮助不大。我对 C++ 知之甚少,也不知道如何解决这个问题。

[响应豪尔赫的意见,更新了这些]

Exceptions.h

#ifndef eckit_Exceptions_h
#define eckit_Exceptions_h

#include <errno.h>

#include "eckit/eckit.h"
#include "eckit/eckit_version.h"

#include "eckit/log/CodeLocation.h"
#include "eckit/log/Log.h"
#include "eckit/log/SavedStatus.h"
#include "eckit/compat/StrStream.h"

namespace eckit {

//-----------------------------------------------------------------------------

void handle_panic(const char*);
void handle_panic(const char*, const CodeLocation&);

/// @brief General purpose exception
/// Derive other exceptions from this class and implement then in the class that throws them.
class Exception : public std::exception {

public: // methods

    /// Constructor with message
    Exception(const std::string& what, const CodeLocation& location = CodeLocation() );

    /// Destructor
    /// @throws nothing
    ~Exception() throw();

    virtual const char *what() const throw() {  return what_.c_str(); }
    virtual bool retryOnServer() const        { return false; }
    virtual bool retryOnClient() const        { return false; }
    virtual bool terminateApplication() const { return false; }

    static bool throwing();
    static void exceptionStack(std::ostream&,bool callStack = false);

    const std::string& callStack() const { return callStack_; }

protected: // methods

void reason(const std::string&);
Exception();

    virtual void print(std::ostream&) const;

private: // members

    std::string       what_;      ///< description
    std::string       callStack_; ///< call stack
    SavedStatus       save_;      ///< saved monitor status to recover after destruction
    Exception*        next_;
    CodeLocation      location_;  ///< where exception was first thrown

    friend std::ostream& operator<<(std::ostream& s,const Exception& p)
    {
        p.print(s);
        return s;
    }
};

nm -Cl $ODB_API/lib/libOdb.a | grep -i "ekit::Exception"

                 U eckit::Exception::Exception(std::string const&, eckit::CodeLocation const&)  /opt/src/OdbAPI-0.10.2-Source/eckit/src/eckit/exception/Exceptions.h:84
                 U eckit::Exception::~Exception()       /opt/src/OdbAPI-0.10.2-Source/eckit/src/eckit/exception/Exceptions.h:108
0000000000000000 W eckit::Exception::retryOnClient() const      /opt/src/OdbAPI-0.10.2-Source/eckit/src/eckit/exception/Exceptions.h:48
0000000000000000 W eckit::Exception::retryOnServer() const      /opt/src/OdbAPI-0.10.2-Source/eckit/src/eckit/exception/Exceptions.h:47
0000000000000000 W eckit::Exception::terminateApplication() const       /opt/src/OdbAPI-0.10.2-Source/eckit/src/eckit/exception/Exceptions.h:49
0000000000000000 W eckit::Exception::what() const       /opt/src/OdbAPI-0.10.2-Source/eckit/src/eckit/exception/Exceptions.h:46
                 U eckit::Exception::print(std::ostream&) const
                 U typeinfo for eckit::Exception

我还尝试从 libOdb.a 解压缩所有目标文件,并使用选项“-fvisibility=default -rdynamic”重新链接 libMagPlus.so,就像这样

ar x libOdb.a ( ./Odb ) 

/usr/bin/g++ -fvisibility=default -rdynamic -fPIC -pipe -O2 -g \
-Wl,--disable-new-dtags -shared \
-Wl,-soname,libMagPlus.so -o ../lib/libMagPlus.so \
... ...  \
./Odb/*.o  \
... ...

但还是得到了这些未定义的符号

U eckit::Exception::~Exception()       /opt/src/OdbAPI-0.10.2-Source/eckit/src/eckit/exception/Exceptions.h:108
U eckit::Exception::print(std::ostream&) const
U typeinfo for eckit::Exception

想知道是否需要触摸 Exceptions.h 以及如何触摸它?

有人可以帮忙吗?

珍惜你的时间

问候

【问题讨论】:

  • c++ 符号名称被破坏(一种支持函数重载的翻译)。考虑使用c++filt 之类的工具将其转换为可读符号:typeinfo for eckit::Exception。您可能无法链接到库或包含定义(未声明)eckit::Exception 类的标头。另一种可能性是告诉链接器隐藏该符号,以便它不会导出到符号表中,因此不会被视为未定义。
  • 谢谢你,豪尔赫!我刚刚用更多信息更新了帖子。如果可能,请看一下。 @JorgeB

标签: c++ linker g++ shared-libraries undefined-symbol


【解决方案1】:

查看Exceptions.h 文件。请注意所有未定义的符号如何属于已声明但未定义的函数。

~Exception() throw();
// [...]
virtual void print(std::ostream&) const;

eckit::Exception::~Exception() 是你的析构函数(在Exceptions.h:108 中声明但未定义)。这同样适用于eckit::Exception::print(std::ostream&amp;) const

typeinfo for eckit::Exception 的情况下,这里的问题是你有没有声明为纯虚拟的虚函数(在抽象类中),但都没有定义,所以类型不是完成。

如果我没记错的话,因为eckit::Exception 类是其他派生类的超类,它的析构函数也应该声明为virtual

检查那些缺少的函数在哪里声明。它们应该在归档程序跳过/遗漏的目标文件中(如果缺少的函数在 .cpp 文件中定义)或在您未包含的头文件中(如果它们在 .hpp 文件中定义) .

另请参阅:g++ undefined reference to typeinfo

【讨论】:

  • 感谢您的意见。使用 g++ 链接共享对象 (.so) 文件时,它不会抱怨缺少符号,并导致此问题。通过添加“-Wl,-no-undefined”,找到了所有丢失的东西并修复了问题。
猜你喜欢
  • 2013-01-31
  • 2012-11-07
  • 2016-07-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-06
  • 2019-05-13
  • 2020-01-27
相关资源
最近更新 更多