如何构建 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 的一部分安装。

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

  • 支持 -autoimport 开关的 COFF LLD。

已知问题:

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 中,对象的第一个成员是指向其类 vtable 的指针。vtable 通常与关键函数一起输出到目标文件中,并且必须为标记为 dllimport 的类导入。指针必须全局唯一。不幸的是,COFF/PE 文件格式没有提供将来自另一个 DLL 的运行时地址存储到此指针中的机制(尽管运行时地址已修补到 IAT 中)。因此,编译器必须发出一些代码,这些代码在 IAT 修补后但在任何可能使用 vtable 指针之前运行,并将 vtable 指针设置为来自 IAT 的地址。对于从 typeinto 对象到 __cxxabiv1::__class_type_info 的 vtable 的引用的特殊情况,编译器没有可用的声明,因此无法做到这一点。为了允许程序链接,我们目前依赖于 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 中的库的一种方法是“独立”构建它们。独立构建不涉及 LLVM 树的其余部分。步骤如下

  • cd build-dir

  • cmake -DLLVM_PATH=<llvm 检出路径,例如 /llvm-project/> -DCMAKE_INSTALL_PREFIX=<安装路径> <其他选项> <项目路径,例如 /llvm-project/libcxxabi>

  • <make 程序,例如 ninja>

  • <make 程序> install

有关独立构建的更多信息,请参阅各个库的构建文档。下一节讨论使用独立构建构建和安装库所需的相关选项和修改。这假设我们正在将 libunwind 和 ibc++ 构建为 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源代码路径>/include

  • -DLIBCXX_CXX_ABI_LIBRARY_PATH=<libcxxabi构建路径>/lib

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

  • -DLIBCXX_NO_VCRUNTIME=ON

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

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

由于我们正在静态链接 libcxxabi,因此我们需要链接 unwind 导入库以解析来自 libcxxabi 对象的 unwind 引用。

  • -DCMAKE_C_FLAGS+=' -UCLOCK_REALTIME'

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

注释:

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