Search code examples
c++linkerg++shared-librariesundefined-symbol

MAGICS - undefined symbol: _ZTIN5eckit9ExceptionE


I'm stuck on a runtime error "undefined symbol: _ZTIN5eckit9ExceptionE" like this

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

There was no error while building shared libaray libMagPlus.so. The error just was raised at runtime when Python module loading it.

Checked with nm, the undefined symbol '_ZTIN5eckit9ExceptionE' is from a static library libOdb.a, like this

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

But there was no any complaint about undefined symbol '_ZTIN5eckit9ExceptionE' for the excutables which linked against the static library libOdb.a directly at the both of complation time and runtime time. All C, Fortran codes also worked well with the static library libOdb.a, except the shared library libMagPlus.so.

The library LibMagPlus.so was linked like this

/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 \
... ...

The library libOdb.a was built like this

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

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

Searched the FAQ and Googled, little help with my problem. I knew little about C++, and have no idea how to get this fixed.

[ In response to Jorge's inputs, updated these ]

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 "eckit::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

I also tried to unpack all object files from libOdb.a and relink libMagPlus.so with all of them with option '-fvisibility=default -rdynamic', like this

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  \
... ...

But still got these undefined symbols

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

Wondering if needs to touch Exceptions.h and how to touch it ?

Anybody can help ?

Appreciating your time

Regards


Solution

  • Take a look at Exceptions.h file. Note how all your undefined symbols belong to functions that are declared but not defined.

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

    eckit::Exception::~Exception() is your destructor (declared in Exceptions.h:108 but not defined). The same applies to eckit::Exception::print(std::ostream&) const.

    In the case of typeinfo for eckit::Exception, the problem here is that you have virtual functions that are not declared as pure virtual (in abstract classes), but are neither defined, so the type is not complete.

    If I'm not wrong, as eckit::Exception class is meant to be superclass for other derived classes, its destructor should be declared virtual too.

    Check where are those missing functions declared. They should be either in an object file skipped/missed by the archiver (if missing functions are defined in a .cpp file) or in a header file that you didn't include (if they are defined in a .hpp file).

    See also: g++ undefined reference to typeinfo