Error message:
Undefined symbols for architecture arm64:
"std::__1::basic_string<unsigned short, base::string16_internals::string16_char_traits, std::__1::allocator<unsigned short> >::shrink_to_fit()", referenced from:
base::UTF8ToUTF16(char const*, unsigned long, std::__1::basic_string<unsigned short, base::string16_internals::string16_char_traits, std::__1::allocator<unsigned short> >*) in libbase.a(utf_string_conversions.o)
base::WideToUTF16(wchar_t const*, unsigned long, std::__1::basic_string<unsigned short, base::string16_internals::string16_char_traits, std::__1::allocator<unsigned short> >*) in libbase.a(utf_string_conversions.o)
ld: symbol(s) not found for architecture arm64
subprocess.CalledProcessError: Command '['clang++', '-B', '/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/', '-shared', '-Xlinker', '-install_name', '-Xlinker', '@rpath/Cronet.framework/Cronet', '-Xlinker', '-objc_abi_version', '-Xlinker', '2', '-arch', 'arm64', '-Werror', '-isysroot', '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS15.0.sdk', '-stdlib=libc++', '-miphoneos-version-min=8.0', '-fembed-bitcode', '-Wl,-ObjC', '-o', 'obj/components/cronet/ios/arm64/Cronet', '-Wl,-filelist,obj/components/cronet/ios/arm64/Cronet.rsp', '-framework', 'UIKit', '-framework', 'CoreFoundation', '-framework', 'CoreGraphics', '-framework', 'CoreText', '-framework', 'Foundation', '-framework', 'JavaScriptCore', '-framework', 'CFNetwork', '-framework', 'MobileCoreServices', '-framework', 'Security', '-framework', 'SystemConfiguration', '-lresolv']' returned non-zero exit status 1
3
Answers
Here is my feedback to Apple and their reply:
Basic information
Please provide a descriptive title for your feedback:
Which area are you seeing an issue with?
What type of feedback are you reporting?
Details
What version of Xcode are you using?
Description
Please describe the issue:
Please list the steps you took to reproduce the issue
What did you expect to happen?
What actually happened?
Apple's reply:
It looks like you are using std::basic_string<char16, base::string16_char_traits>, which comes from Chromium. Since there is an explicit instantiation declaration for that type 2, the instantiation of std::basic_string<char16, base::string16_char_traits> appears to be provided in a library that probably ships with Chromium. You need to make sure you link against it, otherwise such link errors are to be expected.
We think this link may also be relevant: https://stackoverflow.com/a/17484003/627587. It doesn't pertain to libc++, however the issue is most likely the same.
Also, in case you are wondering why this started happening with Xcode 13.1, we suspect this is simply because std::basic_string<char16, base::string16_char_traits>::shrink_to_fit was previously being inlined in your code, which means that the fact that you're not linking to the required Chromium library was not triggering any error. We made some changes to shrink_to_fit and the compiler is probably deciding not to inline it anymore because it is more efficient to use the instantiation announced by the string16.h header, which uncovers the fact that you haven't been linking against that library.
I don’t know why the output object file for base/strings/string16.cc doesn’t contain
base::string16::shrink_to_fit()
(my current guess is that it has something to do with the include/c++/v1/string header file from libc++ in the macOS 12 and iOS 15 SDKs), but it does appear to containbase::string16::reserve(unsigned long)
. Forstd::basic_string
in C++17 and earlier (not C++20 or later),shrink_to_fit()
is equivalent toreserve(0)
. Since the affected version of string16.cc is presumably being compiled with-std=c++14
, a workaround is to replace (inUTFConversion()
in base/strings/utf_string_conversions.cc):with:
This was pretty tricky to track down, but I think I found the issue. First of all,
string16.ii
can be simplified to:utf_string_conversions.ii
can be simplified to:Since
shrink_to_fit
has internal linkage, the compiler doesn’t even bother emitting it insidestring16.o
, because it is not used in that TU. If it did emit it instring16.o
, it would be dead code since no other TU can refer to it anyway.Then, from
utf_string_conversions.o
, we see an extern template instantiation declaration, which basically promises that we will be able to findshrink_to_fit()
in some other TU (presumablystring16.o
). Of course, that can’t be the case, since another TU can’t "export"shrink_to_fit
, which has internal linkage as explained above.As a result, we end up in a situation where
utf_string_conversions.o
expects to seeshrink_to_fit()
in some other TU, but the other TU that should provide it doesn’t. Furthermore, if we compile the above, we can actually see that the compiler is warning us from exactly that:This warning does not show up in the original code because warnings inside system headers are suppressed. This really tripped me up initially, and I think it would make sense for the compiler to warn if the explicit template instantiation declaration appears outside of a system header, regardless of whether the class itself is declared inside a system header. I actually removed the system header directives from the original reproducer and I was able to get the same warning, see this.
Now, you might be wondering why that doesn’t happen with other methods of
basic_string
? Well, apparently, most if not all other methods ofbasic_string
are eitherinline
), orinline
explicitly, or__attribute__((internal_linkage))
I believe that’s the reason why this issue is only showing up with
shrink_to_fit()
: it is a non-inline function because it is defined outside its class definition, despite the class being a template.Concretely:
shrink_to_fit()
so it isinline
. (edit: here)Thanks for reporting this tricky issue.