Linker errors when using boost serialization - c++

I am using boost serialization. I compiled with: -L/opt/local/lib -lboost_serialization -stdlib=libc++, but got several (ungooglable) errors:
Undefined symbols for architecture x86_64:
"boost::archive::text_oarchive_impl::save(std::__1::basic_string, std::__1::allocator > const&)", referenced from:
void boost::archive::save_access::save_primitive, std::__1::allocator > >(boost::archive::text_oarchive&, std::__1::basic_string, std::__1::allocator > const&) in main.o
"boost::archive::basic_text_oprimitive > >::~basic_text_oprimitive()", referenced from:
boost::archive::text_oarchive_impl::~text_oarchive_impl() in main.o
"boost::archive::text_oarchive_impl::text_oarchive_impl(std::__1::basic_ostream >&, unsigned int)", referenced from:
boost::archive::text_oarchive::text_oarchive(std::__1::basic_ostream >&, unsigned int) in main.o
ld: symbol(s) not found for architecture x86_64
I am serializing an std::vector<std::string>:
boost::archive::text_oarchive oa(std::cout);
oa << tasks;
Is there a problem with my installation of boost?
The boost libraries are universal binaries containing both 32-bit and 64-bit machine code (so that's not the problem I guess):
$ file libboost_serialization.dylib
libboost_serialization.dylib: Mach-O universal binary with 2 architectures
libboost_serialization.dylib (for architecture i386): Mach-O dynamically linked shared library i386
libboost_serialization.dylib (for architecture x86_64): Mach-O 64-bit dynamically linked shared library x86_64
I installed boost using sudo port install boost +universal on Mac OS X 10.7.

I could reproduce the problem using the following code:
#include "boost/archive/text_oarchive.hpp"
#include "boost/serialization/vector.hpp"
#include <vector>
#include <string>
int main()
{
std::vector<std::string> tasks;
boost::archive::text_oarchive oa(std::cout);
oa << tasks;
}
This compiles and links without problems when using g++ or clang++ with their respective default flags and linking with -lboost_serialization. However, when using clang++ with libc++ linking fails with essentially the error messages quote (I have Boost installed at /opt/boost):
clang++ -c -stdlib=libc++ -I/opt/boost -W -Wall -ansi serialize.cpp
clang++ -o serialize.tsk -L/opt/boost/stage/lib -stdlib=libc++ serialize.o -lboost_serialization
Based on this I assumed that a build with -stdlib=libc++ wants to have its own Boost build and build one using based on the Boost installation guide:
tar jxvf ~/Downloads/boost_1_48_0.tar.bz2
cd boost_1_48_0/tools/build/v2
# change the build rules to use -stdlib=libc++:
mv tools/clang-darwin.jam tools/clang-darwin.jam.orig
sed -e 's/CONFIG_COMMAND)"/CONFIG_COMMAND)" -stdlib=libc++/' < tools/clang-darwin.jam.orig > tools/clang-darwin.jam
./boostrap.sh
sudo ./b2 install --prefix=/opt/boost-clang
cd ../../..
/opt/boost-clang/bin/b2 --build-dir=/opt/tmp toolset=clang stage
sudo /opt/boost-clang/bin/b2 --build-dir=/opt/tmp toolset=clang install --prefix=/opt/boost-clang
The edits I made to clang-darwin.jam are almost certainly not those intended but they seem to do the trick: I don't know much about "bjam" and I just tried to find an appropriate location to apply the change. Some step of the installation use sudo to install things into protected directories. Obviously, you can install into some other directory where you have write permissions as well. I just installed things on my machine in a way preventing me from accidentally messing it up.
However, with this installation in place I could successfully build the program:
/opt/llvm/bin/clang++ -stdlib=libc++ -W -Wall -ansi -I/opt/boost-clang -c -o serialize.o serialize.cpp
/opt/llvm/bin/clang++ -stdlib=libc++ -L/opt/boost-clang/lib serialize.o -lboost_serialization -o serialize.tsk

It looks like your boost libraries may be 32 bit.
That's a problem you wouldn't notice until you tried to use one of the few boost utils that are not header-only.

Related

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:
Erased and unlinked homebrew installed version, that was causing some false negatives
I had to link to the statically compiled .a file
for the boost_log file directly.
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:
Download the boost zip and cd into the directory, something like boost_1_75_0 (your version may be different)
run ./bootstrap.sh
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*
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
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.

shared_timed_mutex not available on OS X 10.11.2?

I'm trying to play around with the new shared_timed_mutex structures from C++ 14 on OS X 10.11.2 using Eclipse CDT 4.5.0. Xcode is 7.2. I'm using GCC C++ with the following options:
-O0 -g3 -Wall -c -fmessage-length=0 -std=c++14
Her's what I get:
Invoking: MacOS X C++ Linker
g++ -o "MyProject" ./src/main.o
Undefined symbols for architecture x86_64:
"std::__1::shared_timed_mutex::shared_timed_mutex()", referenced from:
HashMap<int, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::hash<int> >::HashMap() in main.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Here's my clang version info:
Apple LLVM version 7.0.2 (clang-700.1.81)
Target: x86_64-apple-darwin15.2.0
Thread model: posix
I've searched my way through the web and found a couple of recommendations, for example this one on Reddit:
https://www.reddit.com/r/cpp_questions/comments/3ejfkr/is_c14s_stdshared_timed_mutex_available_on_os_x/?
This is very close to my problem, I've tried the suggestions, but I´m hoping, that I won´t have to do the manual libc++ download, but could stick with the standard libs shipped with my system.
Thank you!
For the past two years (as I write this) Apple has updated the libc++ headers for their tools releases, but not the libc++ sources. And libc++ implements std::shared_time_mutex both in <shared_mutex> and in shared_mutex.cpp.
According to Apple dev presentation the shared_timed_mutex will be available starting with macOS 10.12. See page 52

How to link in std C++ library on Mac OS X Mavericks?

I'm porting an application to OS X Darwin and am getting link errors with missing symbols like:
std::__1::basic_string<char, std::__1::char_traits<char>,
std::__1::allocator<char> >::find_last_of(char const*,
unsigned long,
unsigned long) const
operator delete[](void*)
typeinfo for std::runtime_error
std::set_unexpected(void (*)())
std::exception::~exception()
[...]
I expect these should come from libstdc++ but I don't see how to link that in using clang.
Here is my attempted link line and the resulting failure:
clang -std=c++11 -stdlib=libc++ -m64 -o ARCH.darwin_1310_i86/release/myExec ARCH.darwin_1310_i86/release/myExec.o ../../src/netcomm/ARCH.darwin_1310_i86/release/libmyExec.a ../../src/common/ARCH.darwin_1310_i86/release/libcommon.a -L../zlib -lz -L../Botan -lbotan-1.10 -lboost_thread-mt
Undefined symbols for architecture x86_64:
"std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::find_last_of(char const*, unsigned long, unsigned long) const", referenced from:
[...]
But this did not work, I'm not finding any examples of how to link it in correctly.
You need to add -lc++ to the link line like this:
clang -std=c++11 -stdlib=libc++ -lc++ -m64 -o ARCH.darwin_1310_i86/release/myExec ARCH.darwin_1310_i86/release/myExec.o ../../src/netcomm/ARCH.darwin_1310_i86/release/libmyExec.a ../../src/common/ARCH.darwin_1310_i86/release/libcommon.a -L../zlib -lz -L../Botan -lbotan-1.10 -lboost_thread-mt
After adding that, the missing symbols go away.
Using the CLang++ compiler on my MacBook Pro OS X Mavericks 9.2, within NetBeans 7.4, I have
-std=c++11 -stdlib=libc++ -Wall
I am sure that I obtained the libc++ from installing the latest Xcode Command Line Tools for Mavericks. On my system, the dynamic libc++ libraries are located in the /usr/lib directory.
Start Edit
I have just tried a basic, "Hello, World," run from Xcode, making sure the LLVM 5.0 (CLang++) compiler settings within the .xcodeproj are configured for:
C++ Language Dialect C++11 [-std=c++11]
C++ Standard Library libc++ (LLVM C++ Standard library with C++11 support)
C Language Dialect c11
All works as expected.
End Edit

Compile and use boost 1.51.0 on Mac OS X 10.8

So I've spent the last 20 hours trying to get boost working under OS X 10.8, and I have finally gotten it to compile without errors, but when I try to compile a test case that uses Boost.test, I'm back again in a world of hurt.
I should mention, the reason I compile boost myself instead of using the binary available, is because I want to use c++11 and libc++.
When I compiled boost, I called b2 like this:
./b2 toolset=clang cxxflags="-std=c++11 -stdlib=libc++" linkflags="-std=c++11 -stdlib=libc++" link=static
and it compiles all file. Then I have this piece of code
#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE Addition
#include <boost/test/unit_test.hpp>
int addition(int i, int j)
{
return i + j;
}
BOOST_AUTO_TEST_CASE(universeInOrder)
{
BOOST_CHECK(addition(2, 2) == 4);
}
which I
try to compile with
clang++ -std=c++11 -stdlib=libc++ -g -Wall -v -I/Users/cb/Downloads/boost_1_51_0 tests/arithmetic.cpp -o tests/arithmetic /Users/cb/Downloads/boost_1_51_0/stage/lib/libboost_unit_test_framework.a`
And it fails miserably, giving me this error:
"/usr/bin/ld" -demangle -dynamic -arch x86_64 -macosx_version_min 10.8.0 -o tests/arithmetic /var/folders/pg/4wcxn1j12c3188vqrv0x4w9r0000gn/T/arithmetic-UFmO1B.o /Users/cb/Downloads/boost_1_51_0/stage/lib/libboost_unit_test_framework.a -lc++ -lSystem /usr/bin/../lib/clang/4.0/lib/darwin/libclang_rt.osx.a
Undefined symbols for architecture x86_64:
"boost::unit_test::unit_test_main(bool (*)(), int, char**)", referenced from:
_main in arithmetic-UFmO1B.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
At first, I figured it was because boost was not compiled for 64bit so I tried telling b2 to do that specifically, but it made no difference, and I also think that it compiles for 64bit by default on OS X.
Any ideas as to why it is failing and how I get it working?
It looks like bad compilation of the test. You requested
#define BOOST_TEST_DYN_LINK
but than you are linking the static version of boost.test
/Users/cb/Downloads/boost_1_51_0/stage/lib/libboost_unit_test_framework.a
and IIRC there is a difference between the static and dynamic versions of this library. So either link the dynamic version of the library (the one with .so extension), or remove that define.

Linking troubles with boost::program_options on OSX using LLVM

I'm having trouble getting through the linking phase in my C++ program due to problems with Boost 1.49. I have switched to C++ (-std=c++11 -libc=libc++) which works fine for another piece of code (which also uses boost). Boost was installed using homebrew with:
brew install boost --universal --with-mpi --with-icu
The trouble starts with boost::program_options. I get the link errors like this:
"boost::program_options::validate(boost::any&, std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<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> >*, int)", referenced from:
... etc. ...
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
This is a little strange, because doing an nm on the library used reveals, that the symbol appears to be there:
nm -U /usr/local/lib/libboost_program_options-mt.dylib | grep validate
0000000000019880 - 01 0000 FUN __ZN5boost15program_options8validateERNS_3anyERKSt6vectorISbIwSt11char_traitsIwESaIwEESaIS7_EEPSsi
0000000000019880 T __ZN5boost15program_options8validateERNS_3anyERKSt6vectorISbIwSt11char_traitsIwESaIwEESaIS7_EEPSsi
00000000000199e0 - 01 0000 FUN __ZN5boost15program_options8validateERNS_3anyERKSt6vectorISbIwSt11char_traitsIwESaIwEESaIS7_EEPbi
00000000000199e0 T __ZN5boost15program_options8validateERNS_3anyERKSt6vectorISbIwSt11char_traitsIwESaIwEESaIS7_EEPbi
0000000000019930 T __ZN5boost15program_options8validateERNS_3anyERKSt6vectorISsSaISsEEPSsi
0000000000019930 - 01 0000 FUN __ZN5boost15program_options8validateERNS_3anyERKSt6vectorISsSaISsEEPSsi
0000000000019c70 - 01 0000 FUN __ZN5boost15program_options8validateERNS_3anyERKSt6vectorISsSaISsEEPbi
0000000000019c70 T __ZN5boost15program_options8validateERNS_3anyERKSt6vectorISsSaISsEEPbi
I have already tried coaxing homebrew to compile boost with clang instead of gcc by setting CXX and CXX_FLAGS accordingly prior to installation. Not sure I succeeded though.
Pointers greatly appreciated.
You will need to recompile boost with clang and std11 flags, the libc++ library is not binary compatible with the installed libstdc++ in OSX (very early version of gcc prior to changing to gpl3). If your version of clang is 3.1 or over then you can use (otherwise change c++11 to c++0x for earlier versions).
./bootstrap.sh
mkdir build
sudo ./bjam toolset=clang cxxflags="-std=c++0x -stdlib=libc++" variant=release link=static threading=multi runtime-link=shared --build-dir=Build --layout=system --without-mpi --without-python install --prefix=/usr/local
You can of course alter any of these as you wish except
toolset=clang cxxflags="-std=c++0x -stdlib=libc++"
This should work for you.
I would like to share my (moderately painful) experience of building Boost 1.54 on Mac OS X 10.8.5 with clang 5.0.0 as supplied by Xcode 5.0 . If you want the C++11 features it is very important to compile and link with clang++, not with clang.
Illustration: take the following simple program:
#include <iostream>
#include <string>
int main(int argc, char *argv[]) {
std::string str = "OK";
std::cout << str << std::endl;
return 0;
}
Can be built with the following command:
clang++ -std=c++11 -stdlib=libc++ clangstr.cc -o clangstr
however, if you try this instead:
clang -std=c++11 -stdlib=libc++ clangstr.cc -o clangstr
then you get linker errors. Note that the clang manpage says that the language is selected by the -std= option, but this is clearly not enough.
The lesson is that we have to tell bjam to explicitly use clang++ when compiling Boost with C++11 support.
Following this very useful post, I put the following into my tools/build/v2/user-config.jam:
using clang : 11
: "/usr/bin/clang++"
: <cxxflags>"-std=c++11 -stdlib=libc++ -ftemplate-depth=512" <linkflags>"-stdlib=libc++"
;
Then I ran ./b2 clean, then I built Boost with the following command:
mkdir -p build/clangstage/
./b2 -j8 --build-dir=build --stagedir=build/clangstage toolset=clang-11 define=BOOST_SYSTEM_NO_DEPRECATED variant=release threading=multi address-model=64 stage
This builds the 64-bit static and dynamic libraries with multithreading support. If you need a different set then change the command above accordingly.