Unable to link to shared library - c++

I'm building a shared library with g++ 3.3.4. I cannot link to the library because I am getting
./BcdFile.RHEL70.so: undefined symbol: _ZNSt8_Rb_treeIjjSt9_IdentityIjESt4lessIjESaIjEE13insert_uniqueERKj
Which c++filt describes as
std::_Rb_tree<unsigned int, unsigned int, std::_Identity<unsigned int>, std::less<unsigned int>, std::allocator<unsigned int> >::insert_unique(unsigned int const&)
I thought this might have come from using hash_map, but I've taken that all out and switched to regular std::map. I am using g++ to do the linking, which is including -lstdc++.
Does anyone know what class would be instantiating this template? Or even better, which library I need to be linking to?
EDIT: After further review, it appears adding the -frepo flag when compiling has caused this, unfortunately that flag is working around gcc3.3 bug.

std::_Rb_Tree might be a red-black tree, which would most likely be from using map. It should be part of libstdc++, unless your library is linking against a different version of libstdc++ than the application, which from what you've said so far seems unlikely.
EDIT: Just to clarify, the red-black tree is the underlying data structure in map. All that hash_map does is hash the key before using it, rather than using the raw value.

Try #include < map > in the source file where you are using map.

You seem to have 2 different incompatible versions of libstdc++.so from different versions of gcc. Check your paths.

Related

Producing a library with a recent gcc and consuming it with an older gcc - Why are there issues despite the same C++ version?

Don't ask me why I am doing what I am doing... that would be a long story.
For now, the purpose of this post is to learn and to understand why things don't work the way I expect. Possibly my expectations are wrong ?
So initially I build my own SystemC 2.3.3 library from source using a recent compiler, say gcc 10.2.0. However, to preserve backwards compatibility with older gccs, I request C++11 :
./configure CXXFLAGS="-DSC_CPLUSPLUS=201103L"
Next I want to build an application using an older gcc that supports C++11 (and the same ABI), say gcc 8.2.0, :
g++ -std=c++11 sc_main.cpp -I/path/to/systemc/include -L/path/to/systemc/lib -lsystemc -lm -o sim
To my surprise, link fails:
libsystemc.so: undefined reference to `std::__cxx11::basic_stringstream<char, std::char_traits<char>, std::allocator<char> >::basic_stringstream()
In effect, comparing the outputs of
nm --demangle `/path/to/gcc/10.2.0/bin/g++ --print-file-name libstdc++.so` | grep "std::__cxx11::basic_stringstream<char, std::char_traits<char>, std::allocator<char> >::"
and
nm --demangle `/path/to/gcc/8.2.0/bin/g++ --print-file-name libstdc++.so` | grep "std::__cxx11::basic_stringstream<char, std::char_traits<char>, std::allocator<char> >::"
reveals some differences. Indeed, the former contains std::basic_stringstream<char, std::char_traits<char>, std::allocator<char> >::basic_stringstream() whereas the latter doesn't.
Is this expected ? Does it mean that in general, it is necessary but not sufficient for the producer and the consumer of a library to use the same C++ version (and the same ABI) ? Or is there something else going on that I don't understand ?
Does it mean that in general, it is necessary but not sufficient for the
producer and the consumer of a library to use the same C++ version (and the > same ABI) ?
Correct. Backwards/forwards compatibility is not defined just by the C++ language version used when compiling source code. Backwards/forwards compatibility is a complicated topic of its own. But I'll just give a simple contrived, example that illustrates some underlying concepts.
Let's simplify what a std::string is. It's basically a pointer, and the number of characters in the string:
namespace std {
class string {
char *chars;
size_t nchars;
public:
// Constructors and other methods.
};
}
The real std::string is somewhat more complicated (and would use symbol names that are reserved for C++ implementations, but that's immaterial). This is just a simplified illustration. std::string existed even before C++11. So, things roll along, over the years, and your C++ compiler has been updated to C++20. For whatever reason its C++ library decided to change this class slightly:
namespace std {
class string {
size_t nchars;
char *chars;
public:
// Constructors and other methods.
};
}
At this point you can choose to instruct your new C++ compiler to compile only at the C++11 language revision. This will allow only C++11 language features. However the resulting binary code still will not be binary-compatible with code that was built by an older version of the C++ compiler, which was compiled with an incompatible class layout.
In general: in order for C++ code built by a new compiler to be binary compatible with code built by an older compiler, an explicit compilation/configuration option would be needed. It's certainly possible that this is this might be the option that specifies the general C++ language version, but just doing that is not generally sufficient. All that does is instruct the compiler which language version to use for compiling the C++ code. Newer language versions obsolete/deprecate features from earlier versions, and the purpose of the language option is to allow source code written for an earlier version of the C++ standard to be compiled, by the current C++ compiler. This is not the same thing as backwards/forwards compatibility.

Calling member functions with std::string params from my dylib creates "Undefined symbols" errors

When trying to link with a dynamic library I built with Xcode 6.3.2, all of my calls to class functions that have parameters of std::string refuse to link:
Undefined symbols for architecture x86_64:
“MyClass::Bogus(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, bool)”,…
The dylib’s .h file IS being included, and the public class member is prototyped as:
int Bogus(std::string& aStringRef, bool verbose);
INTERESTINGLY, if I change the type of that first std::string parameter to long (and call it with a long as the first parameter), there is no link error. So I know I am definitely linking with the dylib I built.
For my dylib, the Apple LLVM 6.1 C++ standard library is set to the default (libstdc++).
The code where I am making the call from is itself a .dylib, and is being compiled and linked not from Xcode, but entirely from a makefile. The version of c++ used to compile from that makefile is:
Apple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn)
Target: x86_64-apple-darwin14.4.0
Thread model: posix
One thing that seems suspicious to me is that the calling code is compiled using "-std=c++1y”, which may be using a standard library for C++14. Could there be a conflict between the standard library being linked for the calling program with the one I selected for building the dylib? (my dylib’s code is being compiled with compiler dialect = GNU++98)
It's hard to pass standard library objects between different binary modules, because their binary representations and implementation details are not standardized.
To make it work, you'd need to make sure all of the modules are using the same - and probably the same version of the - compiler, standard library implementation and all related compilation settings (exceptions, iterator debugging, etc)... Which basically defeats the purpose of having a dynamic library in the first place.
When passing data around, you should either stick to simple pointers (c-strings, data buffers) or introduce some custom, more transparent data types.
See the following answers for some concrete solutions:
Passing std::string in a library API
Passing reference to STL vector over dll boundary

Shared library not linking / cannot be done this way?

Here's my issue:
In my project, I have a class called Match. Now, I would like to use somebody else's code to compare their results. They, unfortunately, also have a class called Match.
OK, so I thought I'd do:
namespace MonteCarlo {
#include "monte-carlo/match.hpp"
}
I appreciate that this is not best practice, but I really just want to test the output for now rather than rewrite everything in new namespaces.
Then, I made a shared library out of his code, and linked it:
LIBPATHS = -L mysql_connector/lib/ -Lmonte-carlo/lib
LIBS = -l mysqlcppconn -l boost_date_time -l boost_iostream boost_system -l boost_filesystem -l MonteCarloTennis
But when I build, I get:
evaluator.cc:139: undefined reference to `MonteCarlo::Match::Match(double, double, double, double, bool, bool)'
evaluator.cc:140: undefined reference to `MonteCarlo::Match::play_match()'
But in the library, using nm, I see:
0000000000001286 T Match::Match(double, double, double, double, bool, bool)
0000000000001286 T Match::Match(double, double, double, double, bool, bool)
I am really new to libraries, so I could really use your advice. Am I getting this linker error because my library is not linking correctly, or because I wrapped the Match class in the namespace and thus the two functions in the library are not found?
Thank you to Joachim Pileborg for providing the answer!
Wrapping the #include in a namespace meant the linker couldn't find the corresponding function in the library. I have now fixed the issue by putting my colleague's code into namespaces.
So a very simple error, but there was so much that could have gone wrong (my first time building a library!) that it was really helpful to get Joachim's advice. Thanks again!

Adding Boost.Log to boost libraries using CMake

I am trying to add Boost.Log to the Boost libraries using CMake, but I am having trouble when trying to link into my program.
I've added a wrapper around the Boost.Log and generated a shared library called libcls_utils.so. The Boost libraries (along with Boost.Log) appear to be built and generate all the .so files properly in the correct location, and so does libcls_utils.so.
When I try to link my file, I get the following error:
/media/data/workspace/mdxdev/tmp/staging/i686-mv-linux/usr/lib/libcls_utils.so: undefined reference to `boost::log_mt_posix::sinks::basic_text_file_backend::construct(boost::fil‌​esystem2::basic_path, std::allocator >, boost::filesystem2::path_traits> const&, std::_Ios_Openmode, unsigned long long, boost::function0 const&, bool)
As far as I can tell, I'm linking against all the correct libraries. Has anyone tried this before successfully? What am I doing wrong?
I am using CMake 2.8.8, Boost-1.49.0 and Boost.Log from the svn trunk.
You might need to define BOOST_LOG_DYN_LINK:
g++ -DBOOST_LOG_DYN_LINK blog.cpp -lboost_log -lpthread

Undefined reference to operator new

I'm trying to build a simple unit test executable, using cpputest. I've built the cpputest framework into a static library, and am now trying to link that into an executable. However, I'm tied into a fairly complicated Makefile setup, because of the related code.
This is my command line:
/usr/bin/qcc -V4.2.4,gcc_ntoarmle_acpp-ne -lang-c++ -O2 -g -g -o Application/UnitTests/Tests/symbols/UnitTestExe -Wl,--start-group Application/UnitTests/Tests/../.objs/main.o Application/UnitTests/lib/libcpputest.a -Wl,--end-group -lm
I'm getting many errors like the following:
Application/UnitTests/lib/libcpputest.a(CommandLineTestRunner.o): In function `CommandLineTestRunner::parseArguments(TestPlugin*)':
Application/UnitTests/cpputest/src/CppUTest/.objs/../CommandLineTestRunner.cpp:114: undefined reference to `operator new(unsigned int, char const*, int)'
I can't figure out what's causing this. Don't I get operator new for free with C++?
You probably need to link with the C++ support runtime library. This happens automatically when you invoke g++. On Linux, this is achieved by adding the -lstdc++ flag to the linker. You have to figure out how to do the same on your platform.
Maybe you're calling gcc, the C compiler instead of g++, which is the C++ compiler.
There's very little information in your question to work from, but it looks like some code uses some form of placement new, and while that special operator new is declared (the compiler finds it and compiles the code using it), the linker can't find its definition.
(Since this old answer of mine seems to still get attention: See here for an extensive discussion on declaration vs. definition.)
You need to rebuild your code from scratch, including the library. I got this error because I inadvertently copied object files compiled on another machine (with the rest of the source) to my machine. Most likely this disturbs the linking step since there are now two types of object files, native (for modified source files) and non-native (all others). I am guessing here, but the operator 'new' means slightly different things on different architectures and that's why you are getting this error.
p.s. I know this is way too late for a useful answer but I'm still posting this for the record.
For QNX 6.5.0 I have specified flag -lang-c++ for qcc (gcc) to avoid the error.
Like the original post, in my case this error happened while trying to link a software using CppUTest framework.
In my case, the source of the problem seems to be related to the fact I disabled the MEMORY_LEAK_DETECTION compile option of CppUTest. I enabled it again, which solved the problem.
Sometimes adding -lstdc++ is not enough. You should add it to the right place. For example I had list like this, not working:
target_link_libraries(cfr2 pthread m stdc++ "${CMAKE_SOURCE_DIR}/compressor/libcompressor.a" )
But this one works fine:
target_link_libraries(cfr2 pthread m "${CMAKE_SOURCE_DIR}/compressor/libcompressor.a" stdc++)
It'd be great if someone explained it in the comment section.