Search code examples
c++macosboostmacports

Boost.Log linker error with MacPorts on OS X 10.7


I am trying to build my C++ library on OS X 10.7, but it fails due to a linker error with the following message.

/usr/bin/c++   -std=c++11 -stdlib=libc++ -Wall -O2 -dynamiclib -Wl,-headerpad_max_install_names   -o libCHEC.dylib -install_name /Users/oxon/libCHEC_build/libCHEC.dylib CMakeFiles/CHEC.dir/src/BasePacket.cc.o CMakeFiles/CHEC.dir/src/Buffer.cc.o CMakeFiles/CHEC.dir/src/CommandPacket.cc.o CMakeFiles/CHEC.dir/src/DataPacket.cc.o CMakeFiles/CHEC.dir/src/Event.cc.o CMakeFiles/CHEC.dir/src/Logger.cc.o CMakeFiles/CHEC.dir/src/ResponsePacket.cc.o  -L/opt/local/lib -lcfitsio /opt/local/lib/libboost_log-mt.dylib /opt/local/lib/libboost_thread-mt.dylib /opt/local/lib/libboost_system-mt.dylib /opt/local/lib/libboost_unit_test_framework-mt.dylib -Wl,-rpath,/opt/local/lib 
Undefined symbols for architecture x86_64:
  "void boost::log::v2_mt_posix::aux::put_integer<char>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, unsigned int, unsigned int, char)", referenced from:
      boost::log::v2_mt_posix::aux::date_time_formatter<boost::log::v2_mt_posix::aux::decomposed_time_wrapper<boost::posix_time::ptime>, char>::format_fractional_seconds(boost::log::v2_mt_posix::aux::date_time_formatter<boost::log::v2_mt_posix::aux::decomposed_time_wrapper<boost::posix_time::ptime>, char>::context&) in Logger.cc.o
      boost::log::v2_mt_posix::aux::date_time_formatter<boost::log::v2_mt_posix::aux::decomposed_time_wrapper<boost::posix_time::ptime>, char>::format_seconds(boost::log::v2_mt_posix::aux::date_time_formatter<boost::log::v2_mt_posix::aux::decomposed_time_wrapper<boost::posix_time::ptime>, char>::context&) in Logger.cc.o
      boost::log::v2_mt_posix::aux::date_time_formatter<boost::log::v2_mt_posix::aux::decomposed_time_wrapper<boost::posix_time::ptime>, char>::format_minutes(boost::log::v2_mt_posix::aux::date_time_formatter<boost::log::v2_mt_posix::aux::decomposed_time_wrapper<boost::posix_time::ptime>, char>::context&) in Logger.cc.o
  void boost::log::v2_mt_posix::aux::date_time_formatter<boost::log::v2_mt_posix::aux::decomposed_time_wrapper<boost::posix_time::ptime>, char>::format_hours_12<(char)48>(boost::log::v2_mt_posix::aux::date_time_formatter<boost::log::v2_mt_posix::aux::decomposed_time_wrapper<boost::posix_time::ptime>, char>::context&) in Logger.cc.o
  void boost::log::v2_mt_posix::aux::date_time_formatter<boost::log::v2_mt_posix::aux::decomposed_time_wrapper<boost::posix_time::ptime>, char>::format_hours_12<(char)32>(boost::log::v2_mt_posix::aux::date_time_formatter<boost::log::v2_mt_posix::aux::decomposed_time_wrapper<boost::posix_time::ptime>, char>::context&) in Logger.cc.o
  void boost::log::v2_mt_posix::aux::date_time_formatter<boost::log::v2_mt_posix::aux::decomposed_time_wrapper<boost::posix_time::ptime>, char>::format_hours<(char)48>(boost::log::v2_mt_posix::aux::date_time_formatter<boost::log::v2_mt_posix::aux::decomposed_time_wrapper<boost::posix_time::ptime>, char>::context&) in Logger.cc.o
  void boost::log::v2_mt_posix::aux::date_time_formatter<boost::log::v2_mt_posix::aux::decomposed_time_wrapper<boost::posix_time::ptime>, char>::format_hours<(char)32>(boost::log::v2_mt_posix::aux::date_time_formatter<boost::log::v2_mt_posix::aux::decomposed_time_wrapper<boost::posix_time::ptime>, char>::context&) in Logger.cc.o
  ...
  "boost::log::v2_mt_posix::aux::code_convert(wchar_t const*, unsigned long, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, std::__1::locale const&)", referenced from:
  boost::log::v2_mt_posix::basic_formatting_ostream<char, std::__1::char_traits<char>, std::__1::allocator<char> >& boost::log::v2_mt_posix::basic_formatting_ostream<char, std::__1::char_traits<char>, std::__1::allocator<char> >::formatted_write<wchar_t>(wchar_t const*, long) in Logger.cc.o
  void boost::log::v2_mt_posix::basic_formatting_ostream<char, std::__1::char_traits<char>, std::__1::allocator<char> >::aligned_write<wchar_t>(wchar_t const*, long) in Logger.cc.o
  "boost::log::v2_mt_posix::sinks::basic_text_ostream_backend<char>::add_stream(boost::shared_ptr<std::__1::basic_ostream<char, std::__1::char_traits<char> > > const&)", referenced from:
  CTA::SST::CHEC::Logger::Logger(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) in Logger.cc.o
  "boost::log::v2_mt_posix::sinks::basic_text_ostream_backend<char>::consume(boost::log::v2_mt_posix::record_view const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)", referenced from:
  void boost::log::v2_mt_posix::sinks::basic_formatting_sink_frontend<char>::feed_record<boost::log::v2_mt_posix::aux::fake_mutex, boost::log::v2_mt_posix::sinks::basic_text_ostream_backend<char> >(boost::log::v2_mt_posix::record_view const&, boost::log::v2_mt_posix::aux::fake_mutex&, boost::log::v2_mt_posix::sinks::basic_text_ostream_backend<char>&) in Logger.cc.o
      void boost::log::v2_mt_posix::sinks::basic_formatting_sink_frontend<char>::feed_record<boost::recursive_mutex, boost::log::v2_mt_posix::sinks::basic_text_ostream_backend<char> >(boost::log::v2_mt_posix::record_view const&, boost::recursive_mutex&, boost::log::v2_mt_posix::sinks::basic_text_ostream_backend<char>&) in Logger.cc.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make[2]: *** [libCHEC.dylib] Error 1
make[1]: *** [CMakeFiles/CHEC.dir/all] Error 2
make: *** [all] Error 2

As you can see, I use CMake, C++11, Clang, and Boost.Log to build this library. I do not get this error on OS X 10.9 on which I use very similar software settings.

In my CMakeLists.txt, I added a definition of 'BOOST_ALL_DYN_LINK', so I do not think this is caused by a Boost.Log namespace problem explained here http://www.boost.org/doc/libs/1_54_0_beta1/libs/log/doc/html/log/rationale/namespace_mangling.html

find_package(Boost 1.5.5 COMPONENTS log thread system unit_test_framework REQUIRED)
ADD_DEFINITIONS(-DBOOST_ALL_DYN_LINK)

Software versions I use on OS X 10.7 and 10.9 are

10.7

  • CMake 2.8.12 (MacPorts)
  • boost @1.56.0_1+no_single+no_static+python27 (MacPorts)
  • Clang 4.2 (Xcode 4.6.3)

10.9

  • CMake 2.8.12 (MacPorts)
  • boost @1.56.0_1+no_single+no_static+python27 (MacPorts)
  • Clang 5.1 (Xcode 5.1.1)

I found that symbol names in /opt/local/lib/libboost_log-mt.dylib on OS X 10.7 and 10.9 are different. It seems that this is the root cause of my problem.

10.7

$ nm -a /opt/local/lib/libboost_log-mt.dylib | grep put_integer
000000000004c1a0 T __ZN5boost3log11v2_mt_posix3aux11put_integerIcEEvRSbIT_St11char_traitsIS4_ESaIS4_EEjjS4_
000000000004c1a0 - 01 0000   FUN __ZN5boost3log11v2_mt_posix3aux11put_integerIcEEvRSbIT_St11char_traitsIS4_ESaIS4_EEjjS4_
000000000004c900 - 01 0000   FUN __ZN5boost3log11v2_mt_posix3aux11put_integerIwEEvRSbIT_St11char_traitsIS4_ESaIS4_EEjjS4_
000000000004c900 T __ZN5boost3log11v2_mt_posix3aux11put_integerIwEEvRSbIT_St11char_traitsIS4_ESaIS4_EEjjS4_

10.9

$ nm -a /opt/local/lib/libboost_log-mt.dylib | grep put_integer
0000000000048a00 - 01 0000   FUN __ZN5boost3log11v2_mt_posix3aux11put_integerIcEEvRNSt3__112basic_stringIT_NS4_11char_traitsIS6_EENS4_9allocatorIS6_EEEEjjS6_
0000000000048a00 T __ZN5boost3log11v2_mt_posix3aux11put_integerIcEEvRNSt3__112basic_stringIT_NS4_11char_traitsIS6_EENS4_9allocatorIS6_EEEEjjS6_
0000000000049000 - 01 0000   FUN __ZN5boost3log11v2_mt_posix3aux11put_integerIwEEvRNSt3__112basic_stringIT_NS4_11char_traitsIS6_EENS4_9allocatorIS6_EEEEjjS6_
0000000000049000 T __ZN5boost3log11v2_mt_posix3aux11put_integerIwEEvRNSt3__112basic_stringIT_NS4_11char_traitsIS6_EENS4_9allocatorIS6_EEEEjjS6_

Could anyone help me to solve this problem, please?


Solution

  • the newer version of xcode defaults to using -stdlib=libc++ for everything that is compiled, which means that boost on 10.9 gets compiled with these flags which means that everything links happily.

    We can verify this by feeding one of the symbols through c++filt, which shows for the 10.9 compiled boost:

    $ c++filt __ZN5boost3log11v2_mt_posix3aux11put_integerIcEEvRNSt3__112basic_stringIT_NS4_11char_traitsIS6_EENS4_9allocatorIS6_EEEEjjS6_
    void boost::log::v2_mt_posix::aux::put_integer<char>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, unsigned int, unsigned int, char)
    

    The presense of std::__1::basic_string is the damning evidence there.

    However, your version of boost on 10.7 is compiled with libstdc++ which is evidenced by the name mangling in that case:

    $ c++filt __ZN5boost3log11v2_mt_posix3aux11put_integerIcEEvRSbIT_St11char_traitsIS4_ESaIS4_EEjjS4_
    void boost::log::v2_mt_posix::aux::put_integer<char>(std::basic_string<char, std::char_traits<char>, std::allocator<char> >&, unsigned int, unsigned int, char)
    

    The presence of the simpler std::basic_string tells us that this is the case.

    What this implies is that when boost was built by MacPorts it was built against the other standard.

    A few solutions are: 1. edit the portfile for boost to get it recompiled with -std=libc++, so that it can now be linked with your other code 2. change your own code to build with -std=libstdc++ when being compiled in 10.7 rather than with -std=libc++ 3. compile a private copy of boost for use with your code that is built with the -std=libc++ on 10.7.

    There are advantages and disadvantages to all of these. If you rebuild macports boost with libc++, then anything that uses it will also have to be compiled with libc++, which could be a neverending circle of hell.

    changing your own code is probably the easiest, this means no futzing around with boost builds and interfering with the portfiles, but if you depend on the facilities provided by libc++ you're kind of out of luck.

    building a private copy of boost just means that you follow the build instructions and when it comes to compiling it with b2 you add: cxxflags=-stdlib=libc++, which causes it to build with that c++ library and then you link with the copy built from that rather than the copy from MacPorts.

    My order or preference is private boost, change my flags, futz with the boost Portfile.