Search code examples
c++boostmakefilec++14

Boost::Log Symbol not found for architecture on macOS


I really hate to ask this basic question, but I'm trying to build a system that uses websocketpp that will hopefully be deployed to an Ubuntu server at some point, and I want to use Boost Logging for the application. I figured since websocketpp already requires boost, i might as well use its logging.

I'm currently testing the setup on a mac, because that's all I have. My project is still only a main.cpp file, it follows this tutorial. it looks like this:

main.cpp

#include <iostream>

#include <boost/log/core.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/utility/setup/file.hpp>
#include <boost/log/expressions.hpp>

namespace logging = boost::log;

void init_logging(const char * logger_filename)
{
    logging::add_file_log(logger_filename);

    logging::core::get()->set_filter(logging::trivial::severity >= logging::trivial::info);
}


int main(int, char*[]) {
    init_logging("titan_logger.log");
    BOOST_LOG_TRIVIAL(trace) << "This is a trace severity message";
    BOOST_LOG_TRIVIAL(debug) << "This is a debug severity message";
    BOOST_LOG_TRIVIAL(info) << "This is an informational severity message";
    BOOST_LOG_TRIVIAL(warning) << "This is a warning severity message";
    BOOST_LOG_TRIVIAL(error) << "This is an error severity message";
    BOOST_LOG_TRIVIAL(fatal) << "and this is a fatal severity message";
    std::cin.get();
    return 0;
} 

I was following the tutorial successfully until I wanted to use the file logger. Then I started getting an error that ends like this:

...
traits<wchar_t>, std::__1::allocator<wchar_t> > >, boost::log::v2s_mt_posix::fallback_to_none>::operator()<boost::log::v2s_mt_posix::binder1st<boost::log::v2s_mt_posix::output_fun, boost::log::v2s_mt_posix::expressions::aux::stream_ref<boost::log::v2s_mt_posix::basic_formatting_ostream<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&> >(boost::log::v2s_mt_posix::attribute_name const&, boost::log::v2s_mt_posix::attribute_value_set const&, boost::log::v2s_mt_posix::binder1st<boost::log::v2s_mt_posix::output_fun, boost::log::v2s_mt_posix::expressions::aux::stream_ref<boost::log::v2s_mt_posix::basic_formatting_ostream<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&>) const in main.o
      boost::log::v2s_mt_posix::value_extractor<boost::log::v2s_mt_posix::trivial::severity_level, boost::log::v2s_mt_posix::fallback_to_none, boost::log::v2s_mt_posix::trivial::tag::severity>::operator()(boost::log::v2s_mt_posix::attribute_name const&, boost::log::v2s_mt_posix::attribute_value_set const&) const in main.o
  "boost::log::v2s_mt_posix::aux::once_block_sentry::enter_once_block() const", referenced from:
      boost::log::v2s_mt_posix::aux::once_block_sentry::executed() const in main.o
  "boost::log::v2s_mt_posix::core::get_logging_enabled() const", referenced from:
      boost::log::v2s_mt_posix::record boost::log::v2s_mt_posix::sources::basic_composite_logger<char, boost::log::v2s_mt_posix::sources::severity_logger_mt<boost::log::v2s_mt_posix::trivial::severity_level>, boost::log::v2s_mt_posix::sources::multi_thread_model<boost::log::v2s_mt_posix::aux::light_rw_mutex>, boost::log::v2s_mt_posix::sources::features<boost::log::v2s_mt_posix::sources::severity<boost::log::v2s_mt_posix::trivial::severity_level> > >::open_record<boost::parameter::aux::tagged_argument_list_of_1<boost::parameter::aux::tagged_argument<boost::log::v2s_mt_posix::keywords::tag::severity, boost::log::v2s_mt_posix::trivial::severity_level const> > >(boost::parameter::aux::tagged_argument_list_of_1<boost::parameter::aux::tagged_argument<boost::log::v2s_mt_posix::keywords::tag::severity, boost::log::v2s_mt_posix::trivial::severity_level const> > const&) in main.o
ld: symbol(s) not found for architecture x86_64

My guess is that I'm using the boost library that I linked using a brew install boost I ran a few days ago. Now that I need the built boost libraries for Boost::Log, it's failing.

How I built boost

I built boost using this tutorial but with g++-10 and std=c++14

I downloaded boost_1_75_0 and put it in my project dir, then the full commands I ran (from the project dir) are:

cd boost_1_75_0

./bootstrap.sh

./b2 -link=static toolset=gcc cxxflags=-std=c++14 --build-dir=../build --with-log --with-regex --with-random --with-system --with-thread --with-filesystem --with-date_time

I followed the advice of this comment's second suggestions, and put all static libraries in their own folder called lib_boost. The application is called Titan so that's what that means in the command below.

make command:

g++ -Wall -I/Users/QuantumHoneybees/Desktop/Titan/Titan/boost_1_75_0 -std=c++14 -lpthread main.cpp -o titan -L./lib_boost  -lboost_log_setup-mt   -lboost_log-mt -lboost_filesystem-mt  -lboost_thread-mt -lboost_system-mt

My Hunch

This SO thread seems to have the same issue but using cmake. The thing is though... i do have the thread library linked. I just don't think it's linked properly. I think that part of the problem is that i'm using static linking... I'm trying to optimize runtime, i don't really care about binary size. So I'm intentionally using static linking.

I think i'm not linking the libraries correctly... I'm not a complete newbie with C++, but I suck at linking errors... I really don't know what may be the issue here. Any help would be appreciated. Thanks.


Update: (not a clean solution though)

so it turns out there were a few issues:

  1. Erased and unlinked homebrew installed version, that was causing some false negatives

  2. I had to link to the statically compiled .a file for the boost_log file directly.

  3. I also had to rebuild Boost using clang and switch make to use it as well

Here is the final (very ugly) command:

clang++ -Wall -I/Users/QH/Desktop/Titan/Titan/boost_1_75_0 -std=c++14 -lpthread main.cpp -o titan -L/Users/QH/Desktop/Titan/Titan/boost_1_75_0/stage/lib -lboost_system -lboost_thread -lboost_thread -lboost_filesystem /Users/QH/Desktop/Titan/Titan/boost_1_75_0/stage/lib/libboost_log.a

It works but is shows a lot of warnings about the same boost::log::v2s_mt_posix:: methods as caused the errors, but I honestly don't care about fixing them at this point.

for some reason, if i replace that last library with -lboost_log i get the same undefined reference error again. I hope that helps someone with an answer!


For future travelers, here are the full set of working steps (thanks to @AndreySemashev:

  1. Download the boost zip and cd into the directory, something like boost_1_75_0 (your version may be different)

  2. run ./bootstrap.sh

  3. run the following: ./b2 link=static cxxstd=14 --build-dir=../build --with-log --with-regex --with-random --with-system --with-thread --with-filesystem --with-date_time*

  4. to compile, run clang++ -Wall -I./boost_1_75_0 -std=c++14 -lpthread main.cpp -o titan -L./boost_1_75_0/stage/lib -lboost_system -lboost_thread -lboost_thread -lboost_filesystem -lboost_log_setup -lboost_log


Solution

  • When you specify -lboost_log, the linker tries to find a shared library by default. Only if it isn't found, it looks for a static library.

    In Boost.Log, symbols in static and shared libraries are mangled differently to make them incompatible. By default, the library assumes static linking. In order to enable dynamic linking, you must define BOOST_LOG_DYN_LINK or BOOST_ALL_DYN_LINK when compiling your code that uses Boost.Log (the former means that only Boost.Log is linked dynamically, the latter - that all Boost libraries are linked dynamically).


    A few other notes:

    • You must ensure that the C++ standard library used to build Boost and your application match. For example, you cannot build Boost with libc++ and your code with libstdc++ - the two standard libraries define different symbols and have different ABIs, so your code won't link with Boost.
    • You must ensure that Boost is built with the same or higher C++ version than your code. Otherwise you may not be able to link because of missing symbols (e.g. methods involving C++11 features won't be available in C++03 Boost libraries).
    • You must ensure that ABI-affecting compiler options and macros are defined the same way when you build Boost and your code. Otherwise you may have ABI incompatibility issues, which are hard to diagnose and debug.
    • In b2 command line, -link=static should be specified without a dash, and you can use cxxstd=14 instead of cxxflags=-std=c++14.
    • If you're using Boost.Log features from boost/log/utility/setup directory, you may need to link with boost_log_setup library, in addition to boost_log. boost_log_setup depends on boost_log and provides additional library setup helpers.