如何建置 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 include 標頭相容。

  • 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>

  • <建置程式,例如 ninja>

  • <建置程式> 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