Skip to content

undefined symbol: std::__1::basic_streambuf<char, std::__1::char_traits<char>>::seekoff(long, std::__1::ios_base::seekdir, unsigned int) when using libcxx with newlib #152763

@inglorion

Description

@inglorion

On #131921, it was noted that the change caused an undefined symbol in some situations. What happens is that libcxx_static.a ends up containing a definition of std::__1::basic_streambuf<char, std::__1::char_traits<char>>::seekoff(long long, std::__1::ios_base::seekdir, unsigned int) and a reference to std::__1::basic_streambuf<char, std::__1::char_traits<char>>::seekoff(long, std::__1::ios_base::seekdir, unsigned int). The difference is the type of the first parameter: long long vs. long.

At link time, this will result in an error such as

error: undefined symbol: std::__1::basic_streambuf<char, std::__1::char_traits<char>>::seekoff(long, std::__1::ios_base::seekdir, unsigned int)

with references from vtable for std::__1::__stdinbuf<char> and similar.

The difference is caused by these lines in libcxx/include/__fwd/ios.h:

#if defined(_NEWLIB_VERSION)
// On newlib, off_t is 'long int'
using streamoff = long int; // for char_traits in <string>
#else
using streamoff = long long; // for char_traits in <string>
#endif

On systems with newlib, it is possible to get to this code with or without _NEWLIB_VERSION being defined. The inclusion of newlib header files causes _NEWLIB_VERSION to be defined, so including libc headers before libcxx headers will cause _NEWLIB_VERSION to be defined, resulting in streamoff being long int. However, if libcxx headers are included without first including newlib headers, _NEWLIB_VERSION will be undefined and streamoff will be long long. The inconsistency results in the link error.

An attempt was made in #131921 to fix this issue by adding the following lines to libcxx/include/__configuration/platform.h:

// This is required in order for _NEWLIB_VERSION to be defined in places where we use it.                                                                                                                                                                                       
// TODO: We shouldn't be including arbitrarily-named headers from libc++ since this can break valid                                                                                                                                                                             
//       user code. Move code paths that need _NEWLIB_VERSION to another customization mechanism.                                                                                                                                                                               
#if __has_include(<picolibc.h>)
#  include <picolibc.h>
#endif

This presumably works on systems with picolibc, but systems that use newlib but not picolibc, the error still happens.

Metadata

Metadata

Assignees

No one assigned

    Labels

    libc++libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions