P.S.: Unfortunately my lack of C++ skill do not allow me to produce a simple test case that would reproduce this error. The symbol has too many levels of templates for me.
Jarno On Apr 16, 2010, at 3:12 PM, ext Jarno Rajahalme wrote: > Sorry for posting this same issue multiple times, but I have a possibly > better proposal for fixing this this time. > > I faced the following linking error trying to link octave on OSX with the > stock Apple GCC 4.2 (Xcode 3.2.2) -m64: > > dyld: Symbol not found: > __ZNSt15basic_stringbufIcSt11char_traitsIcESaIcEE7seekoffElSt12_Ios_SeekdirSt13_Ios_Openmode > Referenced from: > /Users/rajahalm/testing/octave/src/.libs/liboctinterp-3.3.51+.dylib > Expected in: flat namespace > > unmangled: > std::basic_stringbuf<char, std::char_traits<char>, std::allocator<char> > >::seekoff(long, std::_Ios_Seekdir, std::_Ios_Openmode) > > /usr/lib/libstdc++.6.dylib has an _almost_ matching entry: > __ZNSt15basic_stringbufIcSt11char_traitsIcESaIcEE7seekoffExSt12_Ios_SeekdirSt13_Ios_Openmode > > unmangled: > std::basic_stringbuf<char, std::char_traits<char>, std::allocator<char> > >::seekoff(long long, std::_Ios_Seekdir, std::_Ios_Openmode) > > The difference is that the first parameter to seekoff() should be "long > long", but with gnulib it is "long", as it is of type std::streamoff, which > is defined to be int64_t. > > OSX /usr/include/stdint.h typedefs int64_t as "long long". As long as gnulib > stdint.h (re)defines this as "long int" there is going to be this > ABI/mangling/linking problem, even though both definitions result in the same > size of the std::streamoff. > > It seems the tests in stdint.in.h are insufficient. Testing for the size of > "long" is not enough, as the name mangling rules are different for "long" and > "long long", even if they are of the same size. stdint.in.h defines int64_t > as "long long int" when @HAVE_LONG_LONG_INT@, provided that "long" is NOT 64 > bit. I propose the following patch (see below) that allows defining int64_t > as "long long int" (same mangling as for "long long"), when defined, even if > "long" is 64 bit. With this patch the ABI compatibility is maintained, and > linking succeeds. > > However, it is possible that some other platforms need int64_t to be defined > as "long int", when long is 64 bit, causing this change to break the ABI > compatibility on those platforms. So, maybe int64_t should NOT be defined, if > already typedef'ed? But this may be hard to detect with the preprocessor > macros, so maybe a configure time check for int64_t is needed. > > Regards, > > Jarno > > > diff --git a/lib/stdint.in.h b/lib/stdint.in.h > index a861c07..25719ac 100644 > --- a/lib/stdint.in.h > +++ b/lib/stdint.in.h > @@ -135,7 +135,7 @@ typedef unsigned int gl_uint32_t; > > /* Do not undefine int64_t if gnulib is not being used with 64-bit > types, since otherwise it breaks platforms like Tandem/NSK. */ > -#if LONG_MAX >> 31 >> 31 == 1 > +#if LONG_MAX >> 31 >> 31 == 1 && !...@have_long_long_int@ > # undef int64_t > typedef long int gl_int64_t; > # define int64_t gl_int64_t > > > >>> I faced the following linking error trying to compile octave on OSX with >>> GCC 4.3 -m64: >>> >>> dyld: Symbol not found: >>> __ZNSt15basic_stringbufIcSt11char_traitsIcESaIcEE7seekoffElSt12_Ios_SeekdirSt13_Ios_Openmode >>> Referenced from: >>> /Users/rajahalm/testing/octave/src/.libs/liboctinterp-3.3.51+.dylib >>> Expected in: flat namespace >>> in /Users/rajahalm/testing/octave/src/.libs/liboctinterp-3.3.51+.dylib >>> >>> unmangled: >>> >>> std::basic_stringbuf<char, std::char_traits<char>, std::allocator<char> >>> >::seekoff(long, std::_Ios_Seekdir, std::_Ios_Openmode) >>> >>> /opt/local/lib/gcc43/libstdc++.6.dylib has an _almost_ matching entry: >>> >>> __ZNSt15basic_stringbufIcSt11char_traitsIcESaIcEE7seekoffExSt12_Ios_SeekdirSt13_Ios_Openmode >>> >>> unmangled: >>> >>> std::basic_stringbuf<char, std::char_traits<char>, std::allocator<char> >>> >::seekoff(long long, std::_Ios_Seekdir, std::_Ios_Openmode) >>> >>> The difference is that the first parameter to seekoff() should be "long >>> long", but it is "long", as it is of type std::streamoff, which is defined >>> to be int64_t, if _GLIBCXX_HAVE_INT64_T is defined. This definition is >>> handled differently in GCC 4.4, which does not exhibit this linking problem. >>> >>> GCC 4.0 and 4.2 seem to have the same definition of std::streamoff as GCC >>> 4.3, so this problem exists with those versions as well. >>> >>> OSX /usr/include/stdint.h defines int64_t as "long long". As long as gnulib >>> stdint.h redefines this as "long int" there is going to be this linking >>> problem with GCC 4.3, even though both definitions result in the same size >>> of the std::streamoff :-) >>> >>> I tested this with the following change: >>> >>> *** lib/stdint.in.h~ Fri Apr 2 17:38:10 2010 >>> --- lib/stdint.in.h Thu Apr 8 19:29:39 2010 >>> *************** >>> *** 135,141 **** >>> >>> /* Do not undefine int64_t if gnulib is not being used with 64-bit >>> types, since otherwise it breaks platforms like Tandem/NSK. */ >>> ! #if LONG_MAX >> 31 >> 31 == 1 >>> # undef int64_t >>> typedef long int gl_int64_t; >>> # define int64_t gl_int64_t >>> --- 135,141 ---- >>> >>> /* Do not undefine int64_t if gnulib is not being used with 64-bit >>> types, since otherwise it breaks platforms like Tandem/NSK. */ >>> ! #if LONG_MAX >> 31 >> 31 == 1 && !(defined (__APPLE__) && defined >>> (__MACH__)) >>> # undef int64_t >>> typedef long int gl_int64_t; >>> # define int64_t gl_int64_t >>> # define GL_INT64_T >>> #elif defined _MSC_VER >>> # undef int64_t >>> typedef __int64 gl_int64_t; >>> # define int64_t gl_int64_t >>> # define GL_INT64_T >>> #elif @HAVE_LONG_LONG_INT@ >>> # undef int64_t >>> typedef long long int gl_int64_t; >>> # define int64_t gl_int64_t >>> # define GL_INT64_T >>> #endif >>> >>> (added lines above for reference) >>> >>> This change causes int64_t to be defined as "long long int", which seems to >>> be equivalent to "long long" for name mangling pusposes. >>> >>> With this change this linking error disappears. However, more >>> fundamentally, it seems that definition of int64_t based on a matching >>> LONG_MAX is not enough in any 64 bit C++ system, due to the name mangling >>> difference between long and long long. The proper thing would be to not >>> redefine int64_t at all if it is already defined as any type that is 64 >>> bits long. >>> >>> Jarno >>> >>> >>> >>> >>> >> > > >