XadillaX XadillaX - 4 months ago 18
Javascript Question

undefined symbol in node.js C++ addon under Linux, why?

I'm a newbie of writing C++ addons in node.js.

And this is my module:

$ npm install simpleini


It's based on miniini-0.9. And my source is under
src/simpleIni.cc
.
I've tried this module under Windows, OS X, Linux (Debian).
It works well under Windows and OS X.

But when I ran in Linux, it appears that:

node: symbol lookup err: .../simpleIni.node: undefined symbol: _ZNK10INISection10ReadStringEPKcRS1_


Why?

Answer

After some searching this is what I've found.

Doing:

$ nm -C build/Release/simpleIni.node  | grep ReadString
                 U INISection::ReadString(char const*, char const*&) const
00000000000032b0 t INISection::ReadString(char const*, char const*&) const [clone .part.11]
0000000000003f80 W INISection::ReadString(std::string const&, std::string&) const
00000000000081a0 T INISection::ReadStrings(char const*, char const**, unsigned int) const
0000000000008f20 T INISection::ReadStrings(std::string const&, std::vector<std::string, std::allocator<std::string> >&) const
000000000000bca0 r INISection::ReadString(char const*, char const*&) const::__PRETTY_FUNCTION__
000000000000b8a0 r INISection::ReadStrings(char const*, char const**, unsigned int) const::__PRETTY_FUNCTION__

So the key is the

                 U INISection::ReadString(char const*, char const*&) const

Which appears as undefined... Although there's another copy of the symbol

00000000000032b0 t INISection::ReadString(char const*, char const*&) const [clone .part.11]

Now we can search for this method in your code:

at src/miniini-0.9/miniini/include/inisection.h

class INISection
{
...
        bool ReadString(const char * const name, const char * & out) const;
}

And in src/miniini-0.9/miniini/src/inisection.cpp

inline bool INISection::ReadString(const char * name, const char * & out) const
{
...
}

Now the key is this inline. According to the C++ FAQ How do you tell the compiler to make a member function inline?

The reason you (almost always) put the definition (the {...} part) of an inline function in a header file is to avoid “unresolved external” errors from the linker. That error will occur if you put the inline function’s definition in a .cpp file and if that function is called from some other .cpp file.

removing the inline from the inisection.cpp and rebuilding we can try again the nm

$ nm -C build/Release/simpleIni.node  | grep ReadString
00000000000069a0 T INISection::ReadString(char const*, char const*&) const
0000000000003f70 W INISection::ReadString(std::string const&, std::string&) const
00000000000080e0 T INISection::ReadStrings(char const*, char const**, unsigned int) const
0000000000008d20 T INISection::ReadStrings(std::string const&, std::vector<std::string, std::allocator<std::string> >&) const
000000000000bc20 r INISection::ReadString(char const*, char const*&) const::__PRETTY_FUNCTION__
000000000000b7e0 r INISection::ReadStrings(char const*, char const**, unsigned int) const::__PRETTY_FUNCTION__

This time there are no undefined symbols and the ReadString appears only once.

Comments