Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does Folly's shared library reference the wrong symbol from Boost? (GCC on OS X)

Tags:

c++

macos

gcc

boost

I'm trying to build & run a small sample application that uses Folly on OS X Yosemite using GCC 4.9.3. Here's the source code:

#include <folly/AtomicHashMap.h>

int main() {
    folly::AtomicHashMap<int, int> map(256);
    map.insert(std::make_pair(1, 1));
    return 0;
}

I built and installed both Boost (1.59.0) and Folly (latest GitHub head) from sources, making sure GCC was used, and now their libs and headers are available in /usr/local. GCC and other dependencies were installed using MacPorts. I can build the above sample successfully using the following command line:

$ g++-mp-4.9 main.cpp -std=c++11 -I/usr/local/include -L/opt/local/lib -lfolly -lglog

However, when I try to run it, there's the following error:

$ ./a.out
dyld: Symbol not found: __ZNK5boost15program_options22error_with_option_name23substitute_placeholdersERKSs
  Referenced from: /usr/local/lib/libfolly.57.dylib
  Expected in: flat namespace
 in /usr/local/lib/libfolly.57.dylib
Trace/BPT trap: 5

From what I understand, the way this is supposed to work is that /usr/local/lib/libfolly.57.dylib automatically pulls in libboost_program_options.dylib by reference at load time. I can see it listed as a dependency when I run otool -L:

$ otool -L /usr/local/lib/libfolly.57.dylib
/usr/local/lib/libfolly.57.dylib:
    /usr/local/lib/libfolly.57.dylib (compatibility version 58.0.0, current version 58.0.0)
    libboost_context.dylib (compatibility version 0.0.0, current version 0.0.0)
    libboost_program_options.dylib (compatibility version 0.0.0, current version 0.0.0)
    ...

libboost_program_options.dylib is located in /usr/local/lib, and if I rename it to something else, running ./a.out causes the loader to complain about not being able to find it instead ("dyld: Library not loaded: libboost_program_options.dylib"). So it seems that the loader is able to find it, at least.

I checked the symbols exported by this library using nm -gU:

$ nm -gU /usr/local/lib/libboost_program_options.dylib | grep program_options
    ...
    0000000000023560 T __ZNK5boost15program_options22error_with_option_name23substitute_placeholdersERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE
    ...

So there is a symbol very similar to the one that the loader complains is missing. The mangled name just has a different suffix.

[Edit: It's not very easy to see the names unless you scroll to the right, so here they are again:

  • nm says the library contains __ZNK5boost15program_options22error_with_option_name23substitute_placeholdersERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE
  • The "missing symbol" at load time is __ZNK5boost15program_options22error_with_option_name23substitute_placeholdersERKSs.]

I found the corresponding declaration in /usr/local/include/boost/program_options/errors.hpp:

namespace boost { namespace program_options {
...
    class BOOST_PROGRAM_OPTIONS_DECL error_with_option_name : public error {
...
    protected:
...
        virtual void substitute_placeholders(const std::string& error_template) const;

I presume this is the header file that Folly used when I built it because it's the only matching occurrence of substitute_placeholders in all of /usr/include, /usr/local/include and /opt/local/include. (Note that Folly doesn't even call this function directly, but it does #include <boost/program_options.hpp> from folly/experimental/ProgramOptions.h and use other members of boost::program_options.)

It seems to me that the longer mangled name -- the only that's actually exported from libboost_program_options.dylib -- is the correct one, since it includes the std::string argument.

So what could possibly cause libfolly.57.dylib to reference a different (shorter) mangled name instead?

Other notes:

  • I originally installed Boost from MacPorts instead of building it from sources, and it resulted in the same error.
  • If I build the sample using g++-mp-4.9 main.cpp -std=c++11 -I/usr/local/include -L/opt/local/lib /usr/local/lib/libfolly.a -lglog -- in other words, just link with Folly's static library instead -- the problem goes away, and the sample runs.
like image 435
preshing Avatar asked Nov 13 '15 04:11

preshing


1 Answers

Using c++filt (or http://demangler.com) to demangle the two symbols, the symbol in the boost library has a std::__1::basic_string prefix, while the one which is missing in folly has std::string. Some googling indicates that the __1 subnamespace is used by libc++ (clang's C++ standard library) to avoid conflicts with libstdc++ (GNU's). This indicates that boost was compiled using clang and libc++, which is default on OS X, while folly was compiled with libstdc++ (either by using g++ or specifying different flags to clang).

Since the two libraries don't have a compatible ABI, just fixing the symbol name won't help you, so your solution will have to involve recompiling either so that they both are sharing the same standard library implementation.

like image 162
yuriks Avatar answered Nov 09 '22 23:11

yuriks