如何构建 Windows Itanium 应用程序。

简介

本文档包含描述如何创建 Windows Itanium 工具链的信息。

Windows Itanium 允许您在 MS VS CRT 之上部署 Itanium C++ ABI 应用程序。此环境可以直接使用 Windows SDK 标头,并且不需要额外的标头或其他运行时机制(例如 mingw 使用的机制)。

Windows Itanium 堆栈

  • 使用 Itanium C++ abi。

  • libc++。

  • libc++-abi。

  • libunwind。

  • MS VS CRT。

  • 与 MS Windows SDK 包含标头兼容。

  • COFF/PE 文件格式。

  • LLD

注意:不使用 compiler-rt。此功能由 MS VCRT 提供。

先决条件

  • MS SDK 作为 MS Visual Studio 的一部分安装。

  • Clang,支持 windows-itanium 三元组。

  • COFF LLD,支持 -autoimport 开关。

已知问题:

SJLJ 异常,“-fsjlj-exceptions”,是当前唯一支持的模型。

link.exe(MS 链接器)不适用,因为它不支持自动导入,而自动导入是当前正确链接所必需的。但是,如果消除了该限制,则使用 link.exe 没有其他已知问题。

目前,Windows Itanium 缺少可用的 Windows 编译器驱动程序。一个合理的解决方法是使用 windows-msvc 默认目标构建 clang,然后使用例如“-Xclang -triple -Xclang x86_64-unknown-windows-itanium”覆盖三元组。链接器可以使用“-fuse-ld=lld”指定。

在 Itanium C++ ABI 中,对象的第一个成员是指向其类的虚函数表的指针。虚函数表通常与关键函数一起发出到目标文件中,并且必须为标记为 dllimport 的类导入。指针必须是全局唯一的。不幸的是,COFF/PE 文件格式没有提供一种机制将来自另一个 DLL 的运行时地址存储到此指针中(尽管运行时地址已修补到 IAT 中)。因此,编译器必须发出一些代码,这些代码在 IAT 修补之后但在任何可能使用虚函数表指针的代码之前运行,并将虚函数表指针设置为来自 IAT 的地址。对于从 typeinfo 对象到 __cxxabiv1::__class_type_info 的虚函数表的引用的特殊情况,编译器没有可用的声明,因此无法完成此操作。为了允许程序链接,我们目前依赖 LLD 中的 -auto-import 开关来自动导入对 __cxxabiv1::__class_type_info 指针的引用(参见:https://reviews.llvm.org/D43184 以获取相关讨论)。这允许链接;但是,实际使用此类字段的代码将无法正常工作,因为它们不会在运行时修复。请参阅 _pei386_runtime_relocator,它处理用于 mingw 的自动导入方案的运行时组件,以及 https://reviews.llvm.org/D43184https://reviews.llvm.org/D89518 中的注释以了解更多信息。

组装工具链:

步骤如下

# 构建支持 Windows Itanium 的 LLVM 工具链。 # 使用步骤 1 中的工具链构建 libc++、libc++abi 和 libunwind。

也可以从 Linux 进行交叉编译。

要构建步骤 2 中的库,请参阅 libc++ 文档

下一节讨论构建和安装库所需的重要选项和修改。这假定我们将 libunwind 和 libc++ 构建为 DLL,并将 libc++abi 静态链接到 libc++ 中。其他构建配置也是可能的,但此处未讨论。

常见的 CMake 配置选项:

  • -D_LIBCPP_ABI_FORCE_ITANIUM'

告诉 libc++ 标头正在使用 Itanium C++ ABI。

  • -DCMAKE_C_FLAGS="-lmsvcrt -llegacy_stdio_definitions -D_NO_CRT_STDIO_INLINE"

提供 CRT 定义,包括已从 MS VS CRT 中删除的 stdio 定义。我们不希望 stdio 函数内联声明,因为当从 legacy_stdio_definitions.ib 中拉入相同的符号时,它们将导致多重定义错误。

  • -DCMAKE_INSTALL_PREFIX=<安装 路径>

库和标头的安装位置。

构建 libunwind:

  • -DLIBUNWIND_ENABLE_SHARED=ON

  • -DLIBUNWIND_ENABLE_STATIC=OFF

libunwind 可以构建为 DLL。它不依赖于其他项目。

  • -DLIBUNWIND_USE_COMPILER_RT=OFF

我们使用 MS 运行时。

需要编辑 CMake 文件以防止它们将 GNU 特定库添加到链接行。

构建 libc++abi:

  • -DLIBCXXABI_ENABLE_SHARED=OFF

  • -DLIBCXXABI_ENABLE_STATIC=ON

  • -DLIBCXX_ENABLE_SHARED=ON'

  • -DLIBCXX_ENABLE_STATIC_ABI_LIBRARY=ON

为了打破 libc++abi 和 libc++ 之间的符号依赖关系,我们将 libc++abi 构建为静态库,然后将其静态链接到 libc++ DLL 中。这需要设置 CMake 文件以确保展开可见性宏(它扩展为 dllexport/import),因为在稍后创建最终的 libc++ DLL 时将需要它们,请参阅:https://reviews.llvm.org/D90021

  • -DLIBCXXABI_LIBCXX_INCLUDES=<libcxx 路径>/include

libc++ 标头的查找位置

构建 libc++:

  • -DLIBCXX_ENABLE_SHARED=ON

  • -DLIBCXX_ENABLE_STATIC=OFF

我们将 libc++ 构建为 DLL,并将 libc++abi 静态链接到其中。

  • -DLIBCXX_INSTALL_HEADERS=ON

安装标头。

  • -DLIBCXX_USE_COMPILER_RT=OFF

我们使用 MS 运行时。

  • -DLIBCXX_HAS_WIN32_THREAD_API=ON

Windows Itanium 不提供 WIN32 之上的类似 POSIX 的层。

  • -DLIBCXX_ENABLE_STATIC_ABI_LIBRARY=ON

  • -DLIBCXX_CXX_ABI=libcxxabi

  • -DLIBCXX_CXX_ABI_INCLUDE_PATHS=<libcxxabi src 路径>/include

  • -DLIBCXX_CXX_ABI_LIBRARY_PATH=<libcxxabi build 路径>/lib

使用先前构建的静态 libc++abi 库。

  • -DLIBCXX_NO_VCRUNTIME=ON

删除对 VC 运行时的任何依赖项 - 我们需要 libc++abi 来提供 C++ 运行时。

  • -DCMAKE_C_FLAGS=<已安装的 unwind.lib 路径>

由于我们是静态链接到 libc++abi,因此我们需要链接到 unwind 导入库以解析来自 libc++abi 对象的 unwind 引用。

  • -DCMAKE_C_FLAGS+=' -UCLOCK_REALTIME'

防止包含 MS 不提供的 sys/time。

注释:

此处提供了一个示例构建配方:https://reviews.llvm.org/D88124