Undefined reference when linking with Boost using g++-4.9 on a g++-5-ish distribution - gcc

I've written the following groundbreaking application:
#include <boost/program_options.hpp>
int main(int argc, char** argv)
{
boost::program_options::options_description generic_options("foo");
return 0;
}
I am trying to build this on Debian Stretch, on which the default compiler is GCC 5.3.1-5, and the installed version of Boost is 1.58.0.
However, for reasons which I will not go into here (which would be apparent had this not been a MCVE), I need to compile and link the binary using g++-4.9, not g++-5.3. Compiling works fine, but when I try to link, this is what happens:
/usr/bin/g++-4.9 -Wall -std=c++11 CMakeFiles/tester3.dir/src/altmain2.cpp.o -o bin/tester3 -rdynamic -lboost_log -lboost_system -lboost_program_options
CMakeFiles/tester3.dir/src/altmain2.cpp.o: In function `main':
altmain2.cpp:(.text+0x61): undefined reference to `boost::program_options::options_description::options_description(std::string const&, unsigned int, unsigned int)'
Is this due to some ABI incompatibility between gcc 4 and 5?
If so, is there any way to get around it other than building my own version of Boost?
If not, what could cause this?

Is this due to some ABI incompatibility between gcc 4 and 5?
Looks like it is. By default GCC 5 uses a new ABI for several important standard library classes, including std::basic_string template (and thus also std::string). Unfortunately it would be impossible to make std::string fully conform to C++11 and later without breaking the ABI.
libstdc++ implements dual ABI, so that binaries compiled with older versions of GCC will link (and work correctly) with the new library. See this post by Jason Merrill (the maintainer of GCC's C++ front end) for details.
If so, is there any way to get around it other than building my own
version of Boost?
Probably not. Boost depends on the new implementation of std::string and does not provide backward compatibility (unlike libstdc++). This problem is mentioned in Debian bugtracker.

Related

Undocumented ABI changes of std::function between GCC-4 and GCC-5/6/7/8/9, how to make a .so working with devtoolset-4/6/7/8/9?

with _GLIBCXX_USE_CXX11_ABI=0
std::function of GCC-4 is different of GCC-5 and follwing versions.
The following code show you the fact:
==> lib.cc <==
#include <functional>
std::function<int(const void*p)> holder;
int run_holder(const void *p)
{
return holder(p);
}
==> main.cc <==
#include <stdio.h>
#include <functional>
extern int run_holder(const void*p);
extern std::function<int(const void*p)> holder;
int foo(const void* p)
{
printf("p=%p\n", p);
return 0;
}
int main()
{
holder = foo;
foo((void*)0x12345678);
holder((void*)0x12345678);
run_holder((void*)0x12345678);
}
==> make.sh <==
#!/bin/bash
GCC4=/usr/bin/g++
GCCN="scl enable devtoolset-5 -- g++"
$GCC4 -std=c++11 -c -g lib.cc -shared -o libfoo.so &&
$GCCN -std=c++11 -L. -lfoo -g main.cc -o a.out &&
LD_LIBRARY_PATH=. ./a.out
expected result, something like:
p=0x12345678
p=0x12345678
p=0x12345678
actual result:
p=0x12345678
./make.sh: line 6: 973 Segmentation fault LD_LIBRARY_PATH=. ./a.out
The reason is the implementation of std::function changes without document.
gcc4: /usr/include/c++/4.8.2/functional:2430
typedef _Res (*_Invoker_type)(const _Any_data&, _ArgTypes...);
gcc5: /opt/rh/devtoolset-4/root/usr/include/c++/5.3.1/functional:2226
gcc8: /opt/rh/devtoolset-8/root/usr/include/c++/8/bits/std_function.h:609
using _Invoker_type = _Res (*)(const _Any_data&, _ArgTypes&&...);
So I can not write a .so using std::function compiled by gcc4 and used by gcc5/6/7/8. There is no macro like _GLIBCXX_USE_CXX11_ABI can control the behavior.
So I can not write a .so using std::function compiled by gcc4 and used by gcc5/6/7/8.
Correct. Neither Red Hat nor the GCC project has ever claimed that's possible, quite the opposite. C++11 support in GCC 4.x was incomplete and unstable, and subject to ABI changes and API changes. What you're trying to do was never supported.
I've explained this in more detail at https://stackoverflow.com/a/49119902/981959
The Developer Toolset documentation covers it too (emphasis mine):
"A compiler in C++11 or C++14 mode is only guaranteed to be compatible with another compiler in C++11 or C++14 mode if they are from the same release series (for example from Red Hat Developer Toolset 6.x).
...
"Using the C++14 language version is supported in Red Hat Developer Toolset when all C++ objects compiled with the respective flag have been built using Red Hat Developer Toolset 6 or later. Objects compiled by the system GCC in its default mode of C++98 are also compatible, but objects compiled with the system GCC in C++11 or C++14 mode are not compatible."
There is no macro like _GLIBCXX_USE_CXX11_ABI can control the behavior.
We do not provide macros to control things that are unsupported and cannot work.
If you want to use C++11 with a mix of GCC versions you need to use a release that has stable, non-experimental support for C++11. So not GCC 4.x.

How do I cross compile a static library built on the target with static linkage using c++11 utilities

**Edit: Found my problem. As explained by the following answer, I was not actually doing any linking when making the static library. Instead, I made a shared library and linked libstdc++ statically.
Compile a static library link with standard library (static)**
I am trying to create a method to use c++11 on an ancient arm platform running kernel (2.6.37). Unfortunately the latest cross compile our BSP contains is GCC 4.5.3, which does not support all the c++11 utilites we need.
Initially I tried to use old versions of crosstool-ng to build a cross compiler, but the older versions were too broken. The newer versions did not support the 2.6.37 kernel. I was able to complete one build, however the g++ binary was not built, making the whole endeavor useless (I did check that c++ was enabled in the menuconfig).
Thus my last option was to build gcc natively at version 4.9.4 and create a statically linked library to have my gcc 4.5.3 cross compiler link against. This seems to work for the most part. I create my library on the target with the following:
g++ -std=c++11 --static -c main2.cpp
ar -cvq libmain2.a main2.o
I then copy over the files and try build on the host machine with gcc 4.5.3 and get the following:
arm-angstrom-linux-gnueabi-g++ simple.cpp -lmain2 -L.
(I cleaned up some of the output)
undefined reference to `std::_Hash_bytes(void const*, unsigned int, unsigned int)'
undefined reference to
std::__throw_regex_error(std::regex_constants::error_type)'
However, when I use nm, I get the following:
$ arm-angstrom-linux-gnueabi-nm libmain2.a | grep Hash_bytes
U _ZSt11_Hash_bytesPKvjj
U _ZSt11_Hash_bytesPKvjj
$ arm-angstrom-linux-gnueabi-nm libmain2.a | grep throw_regex
U _ZSt19__throw_regex_errorNSt15regex_constants10error_typeE
U _ZSt19__throw_regex_errorNSt15regex_constants10error_typeE
Does anyone know what the heck is going on? Unfortunately we need to be able to use our cross compiler on the host system for most work, but we are also needing to integrate this specific library which uses c++11.
Also note that if I take out the regex and hash functionality from my code but leave other c++11 concepts like nullptr, type inference, delegation etc, the code compiles and runs on the target fine.
Edit: Okay, so after a little more investigation, it looks like the functions _Hash_bytes and __throw_regex_error are not being statically linked into the static library. I guess I need to know why this is the case in order to fix the issue.

gcc 5.40 doesn't include standard include files?

gcc 5.4.0
cygwin 2.8.0
Win10
I've been been knocking my head around this problem.When I compile a simple program, see below, I get an error in one of the gcc include files. I checked the cygwin mailing list and no one has reported an error in the gcc download so I think it's a misunderstanding on my part but I can't figure what I did wrong. Prior to this point all the gcc include fileswere included automatically. Oh, and the compile is correct for other libraries.
The code is:
gcc -std=c++11 test.cpp or gcc test.cpp
include iostream
using namespace std;
int main(int argc, char** argv) { }
and the error message is:
/tmp/ccfBvaqg.o:test.cpp:(.text+0x44): undefined reference to std::ios_base::Init::Init()'
/tmp/ccfBvaqg.o:test.cpp:(.text+0x44): relocation truncated to fit: R_X86_64_PC32 against undefined symbolstd::ios_base::Init::Init()'
/tmp/ccfBvaqg.o:test.cpp:(.rdata$.refptr._ZNSt8ios_base4InitD1Ev[.refptr._ZNSt8ios_base4InitD1Ev]+0x0): undefined reference to `std::ios_base::Init::~Init()'
gcc is the C compiler driver. The compiler automatically detects the language based on the file name; that is why the compilation succeeded. However, the linker is not affected by the names of the source files. By default, the C compiler driver does not link with the C++ standard library.
Since you used the standard library (<iostream> is a bit atypical header file in such a way that merely including it causes a standard library function to be called at the start of the program), but did not link it, the linker fails. The solution is to link with the C++ standard library. The simplest way to do that is to use the C++ compiler driver (g++) which links the standard library by default.

Can I use C++11 in the .cu-files (CUDA5.5) in Windows7x64 (MSVC) and Linux64 (GCC4.8.2)?

When I compile the following code containing the design C++11, in Windows7x64 (MSVS2012 + Nsight 2.0 + CUDA5.5), then I do not get errors, and everything compiles and works well:
#include <thrust/device_vector.h>
int main() {
thrust::device_vector<int> dv(10);
auto iter = dv.begin();
return 0;
}
But when I try to compile it under the Linux64 (Debian 7 Wheezey + Nsight Eclipse from CUDA5.5), I get errors:
../src/CudaCpp11.cu(5): error: explicit type is missing ("int"
assumed)
../src/CudaCpp11.cu(5): error: no suitable conversion function from
"thrust::detail::normal_iterator>" to "int"
exists
2 errors detected in the compilation of
"/tmp/tmpxft_00001520_00000000-6_CudaCpp11.cpp1.ii". make: *
[src/CudaCpp11.o] Error 2
When I added line:-stdc++11
in Properties-> Build-> Settings-> Tool Settings-> Build Stages-> Preprocessor options (-Xcompiler)
I get more errors:
/usr/lib/gcc/x86_64-linux-gnu/4.8/include/stddef.h(432): error:
identifier "nullptr" is undefined
/usr/lib/gcc/x86_64-linux-gnu/4.8/include/stddef.h(432): error:
expected a ";"
...
/usr/include/c++/4.8/bits/cpp_type_traits.h(314): error: namespace
"std::__gnu_cxx" has no member
"__normal_iterator"
/usr/include/c++/4.8/bits/cpp_type_traits.h(314): error: expected a
">"
nvcc error : 'cudafe' died due to signal 11 (Invalid memory
reference) make: * [src/CudaCpp11.o] Error 11
Only when I use thrust::device_vector<int>::iterator iter = dv.begin(); in Linux-GCC then I do not get an error. But in Windows MSVS2012 all c++11 features works fine!
Can I use C++11 in the .cu-files (CUDA5.5) in Windows7x64 (MSVC) and Linux64 (GCC4.8.2)?
You will probably have to split the main.cpp from your others.cu like this:
others.hpp:
void others();
others.cu:
#include "others.hpp"
#include <boost/typeof/std/utility.hpp>
#include <thrust/device_vector.h>
void others() {
thrust::device_vector<int> dv(10);
BOOST_AUTO(iter, dv.begin()); // regular C++
}
main.cpp:
#include "others.hpp"
int main() {
others();
return 0;
}
This particular answer shows that compiling with an officially supported gcc version (as Robert Crovella stated correctly) should work out at least for c++11 code in the main.cpp file:
g++ -std=c++0x -c main.cpp
nvcc -arch=sm_20 -c others.cu
nvcc -lcudart -o test main.o others.o
(tested on Debian 8 with nvcc 5.5 and gcc 4.7.3).
To answer your underlying question: I am not aware that one can use C++11 in .cu files with CUDA 5.5 in Linux (and I was not aware the shown example with host-side C++11 gets properly de-cluttered under MSVC). I even filed a feature request for constexpr support which is still open.
The CUDA programming guide for CUDA 5.5 states:
For the host code, nvcc supports whatever part of the C++ ISO/IEC
14882:2003 specification the host c++ compiler supports.
For the device code, nvcc supports the features illustrated in Code
Samples with some restrictions described in Restrictions; it does not
support run time type information (RTTI), exception handling, and the
C++ Standard Library.
Anyway, it is possible to use some of the C++11 features like auto in kernels, e.g. with boost::auto.
As an outlook, other C++11 features like threads may be quite unlikely to end up in CUDA and I heard no official plans about them yet (as of supercomputing 2013).
Shameless plug: If you are interested in more of these tweeks, feel free to have a look in our library libPMacc which provides multi-GPU grid and particle abstractions for simulations. We implemented lambda, a STL-like access concept for 1-3D matrices and other useful stuff there.
All the best,
Axel
Update: Since CUDA 7.0 C++11 support in kernels has been added officially. As BenC pointed our correctly, parts of this feature were already silently added in CUDA 6.5.
According to Jared Hoberock (Thrust developer), it seems that C++11 support has been added to CUDA 6.5 (although it is still experimental and undocumented). This may make things easier when starting to use C++11 in very large C++/CUDA projects, since splitting everything can be quite cumbersome for large projects when you use CMake for instance.

Clang OS X Lion, cannot find cstdint

I'm trying to compile an application that utilizes cstdint. Since Apple deprecated the gcc, I wanted to try compiling it with clang, but i get the error:
fatal error: 'cstdint' file not found
I know that the gcc 4.6.2 version has the option for -std=c++0x, to include the library, but since the os x version is 4.2 that's not much of an option here. Any suggestions on how I can move forward? I have tried to install 4.6.2, but ran into a variety of issues when compiling some of the needed libraries before building gcc.
Presumably, you have the source code to this application, so you can modify the headers to include the correct cstdint header, as Clang 3.0 (which Lion's tools come with) does have the header.
Quick Solution
The header is under the tr1 directory, so you will want to do either of these includes:
#include <tr1/cstdint>
Or
#include <stdint.h> // which will use the C99 header
Longer, boring explanation
After doing some additional reading since I remember you can do this without the tr1 directory:
By default, you are going to be including C++ headers from /usr/include/c++/4.2.1, which are the GNU GCC headers. /usr/include/c++/4.2.1/tr1 includes the TR1 header files, like cstdint.
The alternative method is to compile using the Clang++ frontend and passing the -stdlib=libc++ flag, which will use the headers from /usr/include/c++/v1, which are Clang's C++ header implementations. It has cstdint.
Example:
// file called example.cxx
#include <tr1/cstdint>
int main() {
// whatever...
}
Compile this with:
g++ example.cxx
or
clang++ example.cxx
And it will do what you want.
If you don't want to use the tr1 version (which is roughly the same, if not exactly):
// file called example.cxx
#include <cstdint>
int main() {
// stuff
}
This is compiled like this:
clang++ -stdlib=libc++ example.cxx
Though if you use -stdlib=libc++, it means you're linking to Clang's C++ library libc++, rather than GCC's libstdc++.

Resources