【问题标题】:"Undefined symbols" of shrink_to_fit() when compiling Cronet on iOS 15 with Xcode 13在使用 Xcode 13 在 iOS 15 上编译 Cronet 时,shrink_to_fit() 的“未定义符号”
【发布时间】:2021-11-29 21:00:36
【问题描述】:

错误信息:

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

【问题讨论】:

  • 我知道在运行 macOS 12.0 Monterey 的 Apple Silicon Mac 上从 QtWebEngine 5.15.7 构建 Chromium 时几乎相同的错误(这两个函数使用的未定义符号)的报告。
  • 有解决办法吗?
  • 我不知道。考虑订阅trac.macports.org/ticket/63725 以获取更新。
  • 您是否 0) 更新了 libbase,1) 在 libbase 之前包含 &lt;string&gt;This comment 似乎表明这些功能仅在 Windows 上需要
  • 您能否提供一个导致此问题的最小工作示例?

标签: c++ ios xcode


【解决方案1】:

这很难追踪,但我想我找到了问题所在。首先string16.ii可以简化为:

template <class T>
struct basic_string {
    __attribute__((internal_linkage))
    void shrink_to_fit();
};

template <class T>
void basic_string<T>::shrink_to_fit() { }

template class basic_string<char>;

utf_string_conversions.ii 可以简化为:

template <class T>
struct basic_string {
    __attribute__((internal_linkage))
    void shrink_to_fit();
};

template <class T>
void basic_string<T>::shrink_to_fit() { }

extern template class basic_string<char>;

int main() {
    basic_string<char> s;
    s.shrink_to_fit();
}

由于shrink_to_fit 具有内部链接,编译器甚至不会费心在string16.o 内发出它,因为它没有在那个TU 中使用。如果它确实在string16.o 中发出了它,那将是死代码,因为无论如何其他 TU 都无法引用它。

然后,从utf_string_conversions.o,我们看到一个extern 模板实例化声明,它基本上承诺我们将能够在其他一些TU 中找到shrink_to_fit()(大概是string16.o)。当然,情况并非如此,因为另一个 TU 无法“导出”shrink_to_fit,它具有如上所述的内部链接。

因此,我们最终会遇到utf_string_conversions.o 期望在其他某个 TU 中看到 shrink_to_fit(),但应该提供它的其他 TU 没有看到的情况。此外,如果we compile the above,我们实际上可以看到编译器正在警告我们:

<stdin>:4:10: warning: function 'basic_string<char>::shrink_to_fit' has internal linkage but is not defined [-Wundefined-internal]
    void shrink_to_fit();
         ^
<stdin>:14:7: note: used here
    s.shrink_to_fit();
      ^
1 warning generated.
Undefined symbols for architecture x86_64:
  "basic_string<char>::shrink_to_fit()", referenced from:
      _main in main.o
ld: symbol(s) not found for architecture x86_64

此警告未显示在原始代码中,因为系统标头内的警告被禁止。最初这确实让我感到困惑,我认为编译器警告显式模板实例化声明是否出现在系统头文件之外是有意义的,无论类本身是否在系统头文件中声明。我实际上从原始复制器中删除了系统头指令,并且能够得到相同的警告,请参阅this

现在,您可能想知道为什么 basic_string 的其他方法不会发生这种情况?好吧,显然,basic_string 的大多数(如果不是全部)其他方法都是

  1. 在类内部定义(因此隐含为inline),或
  2. 在类外部定义但显式标记为inline,或
  3. 未标记__attribute__((internal_linkage))

我相信这就是为什么这个问题只出现在shrink_to_fit() 中的原因:它是一个非内联函数,因为它是在其类定义之外定义的,尽管该类是一个模板

具体来说:

  1. Chromium 应该考虑删除它们的显式实例化——这些实例很脆弱,正如 here 所解释的那样。
  2. 我将修复 libc++ 的 shrink_to_fit(),使其变为 inline。 (编辑:here
  3. 我将提交一个 Clang 错误来讨论当显式模板实例化声明出现在系统标头之外时发出该警告的可能性。 (编辑:here

感谢您报告这个棘手的问题。

【讨论】:

    【解决方案2】:

    我不知道为什么 base/strings/string16.cc 的输出目标文件不包含base::string16::shrink_to_fit()(我目前的猜测是它与 include/c++/v1/string 头文件有关来自 macOS 12 和 iOS 15 SDK 中的 libc++),但它似乎确实包含 base::string16::reserve(unsigned long)For std::basic_string in C++17 and earlier (not C++20 or later), shrink_to_fit() is equivalent to reserve(0). 由于 string16.cc 的受影响版本大概是用 -std=c++14 编译的,解决方法是替换(在 base/strings/utf_string_conversions.cc 中的 UTFConversion() 中):

      bool res = DoUTFConversion(src_str.data(), src_len32, dest, &dest_len32);
    
      dest_str->resize(dest_len32);
      dest_str->shrink_to_fit();
    
      return res;
    }
    

    与:

      bool res = DoUTFConversion(src_str.data(), src_len32, dest, &dest_len32);
    
      dest_str->resize(dest_len32);
      dest_str->reserve(0);
    
      return res;
    }
    

    【讨论】:

    • 这个建议不是很好,相反我们应该弄清楚为什么string16.cc 不包含shrink_to_fit。您能否分享一个用于创建该目标文件的独立复制器?
    • 1.checkout chromium 源代码 2.setup Cronet iOS 构建环境 3.编译 Xcode 13.1 和 iOS 15.0, MacOS 12.0.1
    • 为了获得一个目标文件,我需要做很多工作。如果您在本地有该设置,您可以与文件的预处理内容和用于编译它的命令行调用共享一个要点吗?应该够了。
    • @LouisDionne 这是预处理后的 string16.cc(来自 qtwebengine-chromium 和 macOS 12 SDK,而不是 cronet 和 iOS 15 SDK,但表现出同样的问题):gist.github.com/chrstphrchvz/f9d486d060bf4d1726dfc82d4f47bb17
    • 谢谢@chrstphrchvz。你能告诉我一个最小的翻译单元(预处理),当链接到目标文件时,由于缺少符号错误而失败?还有你正在使用的编译器调用。
    【解决方案3】:

    这是我对 Apple 的反馈和他们的回复:

    基本信息

    请为您的反馈提供描述性标题:

    在带有 Xcode 13 的 iOS 15 上编译 Cronet 时,shrink_to_fit() 的未定义符号

    您认为哪个区域存在问题?

    Xcode

    您要报告什么类型的反馈?

    不正确/意外的行为

    详情

    你使用的是什么版本的 Xcode?​​p>

    13.1

    说明

    请描述问题:

    在 iOS 平台上使用 Xcode 13.1 和 iOS 15.0 编译 Cronet 时,出现错误:

    架构 arm64 的未定义符号:

    “std::__1::basic_string::shrink_to_fit()”,引用自:base::UTF8ToUTF16(char const*, unsigned long, std::__1::basic_string) 在 libbase.a(utf_string_conversions.o) base::WideToUTF16(wchar_t const, unsigned long , std::__1::basic_string*) in libbase.a(utf_string_conversions.o)

    ld: 未找到架构 arm64 的符号

    subprocess.CalledProcessError: 命令'['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']' 返回非零退出状态 1

    请列出您为重现该问题所采取的步骤

    1. 签出 Chromium 源代码
    2. 设置 Cronet 构建环境
    3. 使用 Xcode 13.1 和 iOS 15.0 编译,macOS v12.0.1 (Sierra)

    你预计会发生什么?

    像 Xcode 12 一样成功编译

    究竟发生了什么?

    架构 arm64 的未定义符号:“std::__1::basic_string::shrink_to_fit()”,引用自:base:: UTF8ToUTF16(char const*, unsigned long, std::__1::basic_string) 在 libbase.a(utf_string_conversions.o) base::WideToUTF16 (wchar_t const, unsigned long, std::__1::basic_string*) 在 libbase.a(utf_string_conversions.o)

    苹果的回复:

    看起来您正在使用来自 Chromium 的 std::basic_string。由于该类型 2 有一个显式的实例化声明,因此 std::basic_string 的实例化似乎在可能随 Chromium 附带的库中提供。您需要确保链接到它,否则会出现此类链接错误。

    我们认为此链接也可能是相关的:https://stackoverflow.com/a/17484003/627587。它与 libc++ 无关,但问题很可能是相同的。

    另外,如果您想知道为什么 Xcode 13.1 开始出现这种情况,我们怀疑这仅仅是因为 std::basic_string::shrink_to_fit 之前已内联在您的代码中,这意味着您没有链接到所需的 Chromium 库这一事实并没有触发任何错误。我们对 shrink_to_fit 进行了一些更改,编译器可能决定不再内联它,因为使用 string16.h 标头宣布的实例化更有效,这揭示了您没有链接到该库的事实。

    【讨论】:

    • 我不同意原因是“未链接所需的 Chromium 库”。但据推测,苹果提供的信息太少,无法提出更有可能的替代方案……
    • ...string16.cc 和 utf_string_conversions.cc 的对象同时链接到 libbase.a 中(此时出现链接错误)。我可以用reserve(0) 替换shrink_to_fit() 用法,而reserve(unsigned long) 不会出现类似的未定义符号错误,我认为这表明string16 所需的“库” is 被链接。而且,以前的 macOS 版本的 SDK 没有类似的链接错误(假设 chromium 构建工具链在每个 macOS 版本上表现不同不是一个因素)。
    • 第一部分(没有字面问题(但部分或全部可以转换为小节标题) ) 属于问题。 Stack Overflow is not a forum。您可以同时编辑(更改)change your answerchange your question。或者换句话说,这应该变成问答的形式。提前致谢。
    • 这个答案正在meta讨论。
    • 我写了那个苹果回复。我确实在猜测可能会发生什么,并且从查看 Chromium 资源中最有可能的是您没有链接到所需的.a。我来看看上面的预处理输出。
    猜你喜欢
    • 2022-07-08
    • 1970-01-01
    • 1970-01-01
    • 2022-01-01
    • 2012-07-06
    • 1970-01-01
    • 2013-03-07
    • 2021-12-02
    • 1970-01-01
    相关资源
    最近更新 更多