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

  • Clang 支援 windows-itanium triple。

  • 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」覆蓋 triple。連結器可以使用「-fuse-ld=lld」指定。

在 Itanium C++ ABI 中,物件的第一個成員是指向其類別的 vtable 的指標。vtable 通常與金鑰函數一起發射到物件檔案中,並且對於標記為 dllimport 的類別必須匯入。指標必須是全域唯一的。不幸的是,COFF/PE 檔案格式沒有提供將來自另一個 DLL 的執行階段位址儲存到此指標中的機制(儘管執行階段位址已修補到 IAT 中)。因此,編譯器必須發射一些程式碼,這些程式碼在 IAT 修補之後但在任何可能使用 vtable 指標的程式碼之前執行,並將 vtable 指標設定為來自 IAT 的位址。對於從 typeinfo 物件到 __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 中的程式庫,請參閱 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=<install path>

程式庫和標頭的安裝位置。

建置 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=<path to 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 path>/include

  • -DLIBCXX_CXX_ABI_LIBRARY_PATH=<libcxxabi build path>/lib

使用先前建置的靜態 libc++abi 程式庫。

  • -DLIBCXX_NO_VCRUNTIME=ON

移除對 VC 執行階段的任何依賴 - 我們需要 libc++abi 來提供 C++ 執行階段。

  • -DCMAKE_C_FLAGS=<path to installed unwind.lib>

由於我們是靜態連結到 libc++abi,因此我們需要連結到 unwind 匯入程式庫,以解析來自 libc++abi 物件的 unwind 參考。

  • -DCMAKE_C_FLAGS+=' -UCLOCK_REALTIME'

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

注意事項:

此處提供了一個範例建置配方:https://reviews.llvm.org/D88124