记一次 Windows 上使用 MSVC 构建并使用 Clang

因为想尝试一下最新的 Clang,于是去 https://llvm.org/,从 git 获取到最新的源码。进入发布页 https://releases.llvm.org/ 就可以看到从 Git 获取代码的方法:https://llvm.org/docs/GettingStarted.html

准备工作

安装 MSVC, Git 和 Python

笔者使用 MSVC 进行的构建,这需要事先安装 MSVC,去官网下载即可,安装 C++ 桌面开发的 Workload。如果需要使用 lldb,似乎还需要安装 Python。

打开 Developer Shell for VS

接下来的构建过程在命令行中进行. VS 的环境默认不对外, 需要打开 VS 的开发者命令行, 以便使用其中的工具.

首先在开始菜单的 Visual Studio 2022 目录中找到并打开 Developer PowerShell for VS,建议选择以管理员模式启动,不过这个打开之后环境默认是 x86 的,我们也可以选择打开 x64 Native Tools Command Prompt for VS。由于目前还没有 “x64 Native Developer PowerShell”,所以可以输入 powershell 命令启动 PowerShell,这样就能使用 PowerShell 了,并且继承之前的环境变量。

默认使用的终端是 Win32 控制台,该终端有很多 BUG,比如执行的时候无意间的鼠标滚轮可能会导致命令暂停,这样在执行耗时比较长并且没有即时提醒的任务时,可能会不知道任务是否还在继续,需要经常在终端中按键 (比如 Enter 键) 进行确认。

因此建议使用 Windows Terminal,它可以在 Windows 商店中安装,Windows 11 也预装了这个终端。如果没有选择将这个 Windows Terminal 设置成默认终端,可以在刚刚的 Win32 控制台中再输入 wt 命令,即可调出 Windows Terminal,并且继承之前的环境变量。

获取源码

之后,便是获得源码。切换到一个工作目录,比如 D:\dev,并且将该目录添加到 Windows Defender 或者其他反病毒软件的白名单

cd D:\dev

由于 LLVM 的一些 Test 对 EOL 敏感,因此在 Windows 签出需要禁用自动 CRLF 转换。此外,如果磁盘空间吃紧,并且不计划参与 LLVM 开发,可以使用浅克隆,即添加参数 --depth=1

如果网络条件不佳,注意使用代理服务器。

git clone --depth=1 --config core.autocrlf=false https://github.com/llvm/llvm-project.git

CMake Configure 阶段

进入目录 llvm-project,新建目录预备进行构建。

cd llvm-project
mkdir build

先要使用 CMake 进行 Configure, 生成构建信息.

有几个选项需要注意:

LLVM_ENABLE_PROJECTS 选项是选择需要的构建目标。这里笔者选择了 clang、lld、lldb。如果需要 Clang-tidy 等工具,可以添加 clang-tools-extra。

libcxx、libcxxabi 需要放在 LLVM_ENABLE_RUNTIMS 里面。

这里需要选择 lld 以构建 LLVM 的 Linker,不然,因为 Clang 是用 MSVC 构建的,所以默认是用的 MSVC 的链接器,但是在日常使用时,默认 MSVC 的环境变量不暴露在外,所以 CMake 配置的时候就会找不到 Linker 导致链接失败。所以我们需要一个除了 MSVC Linker 之外的 Linker。

建议选择 Release 的构建类型,这样结合 --depth=1 的 Git 选项,构建后总文件大小约为 5GB,而如果选择 Debug 类型,则可能消耗数十 GB 的磁盘空间。

笔者选择使用 Ninja 作为构建工具 (笔者也尝试使用 MSVC 的构建工具 MSBuild,但是似乎无视了 Release 的 CMAKE_BUILD_TYPE 设定。不确定 VS 中是否包含 Ninja,可自行安装)。需要注意,Ninja 不支持选择主机平台 triplet,而我们打开的 Developer PowerShell 默认是 32 位的,因此这样构建出的 Clang 是 32 位的,且默认目标平台是 i386-windows-pc。

不过,可以添加选项,修改默认目标平台 Target Triple:-DLLVM_DEFAULT_TARGET_TRIPLE=x86_64-pc-windows-msvc

如果之前打开的是 x64 Native 的 Developer Shell,默认主机就是 x64 了,构建出来的是 64 位的,默认目标平台也是 x86_64。

此外,可以选择 Clang + LLVM 构建好后的安装目录。即设定 CMAKE_INSTALL_PREFIX 变量,Windows 下默认为 X:/Program Files (x86)/,这样的话最后执行 ninja install 时,需要管理员权限。不过笔者构建时没有更改这个选项。

综上,笔者的 CMake 命令如下 (PowerShell):

cmake -G "Ninja" -S llvm -B build `
    -DCMAKE_BUILD_TYPE=Release `
    -DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra;lld;lldb;mlir" `
    -DLLVM_ENABLE_RUNTIMES="libcxx" `

开始构建

等待 CMake Configure 完成后,就可以开始构建了:

cmake --build build

然后就是漫长的构建过程。笔者的 i7-1065U + 16GB RAM 大约花了 2 小时。过程中没有 error,只有一些 warning,因此可以或许在睡觉休憩的时候执行构建过程。

安装

构建完成后,安装即可:

ninja install

如果没有更改 CMAKE_INSTALL_PREFIX, 又没有管理员权限, 会安装失败.

安装完成后,我们就可以把 Clang 的路径添加进 PATH 环境变量。之后,就可以在默认的命令行使用 Clang 了。

笔者测试使用的是 Visual Studio Code 上的 CMake 插件 (需要将 Generator 选择为 Ninja, 前文中已安装, 之后在 VSCode 设置中的 CMake: Configure Args 添加一项 -G Ninja).

使用 Visual Studio Code 中的 CMake 插件配置项目没有遇到问题

补充说明

如果时候发现想要的工具功能忘记构建,可以删除 CMakeCache.txt 并重新执行 CMake configure 和 build 过程。

此外,第一次构建有了 lld 过后 (或者 VS 安装了 “适用于 Windows 的 C++ Clang 工具”),可以使用 lld 作为链接器。

cmake -G "Ninja" -S llvm -B build `
    -DCMAKE_BUILD_TYPE=Release `
    -DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra;lld;lldb;mlir" `
    -DLLVM_ENABLE_RUNTIMES="libcxx" `
    -DLLVM_USE_LINKER=lld `
    -DLLVM_PARALLEL_LINK_JOBS=8 `

关于 Target 的问题

以下部分可能多有疏漏,仅供参考。

这里的 Target 不是指构建的“目标”,而是指“目标平台”。

LLVM 和 GCC 有个很大的不同点是, GCC 需要为每个特定的体系架构,譬如 arm/x86 独立生成一套交叉工具链套件,而 LLVM 是在一个工具链套件中就可以支持多个体系架构。

CMake 在 Configure LLVM Project 时,通过 LLVM_TARGETS_TO_BUILD 来指定生成的 LLVM 可以支持的体系架构(这里称为 target)。默认时全部都选的,详见 LLVM 文档。

LLVM_DEFAULT_TARGET_TRIPLE: 可以通过该选项修改默认的 target 的 triple 组合。

来源:https://zhuanlan.zhihu.com/p/263550372

笔者编译时使用的 x86 工具并且没有指定上面的选项,得到的结果如下:

$ clang -v
clang version 14.0.0 (https://github.com/llvm/llvm-project.git a2a826d8b66cfc85499a92949767d153563078a0)
Target: i686-pc-windows-msvc
Thread model: posix
InstalledDir: C:\Program Files (x86)\LLVM\bin

关于 Triple 的介绍在这里:https://clang.llvm.org/docs/CrossCompilation.html#target-triple

在 LLVM 的 GettingStarted 页的例子 处了解到,可以像 gcc 那样直接使用 clang,编译得到目标平台可执行程序:

clang hello.c -o hello.exe

这样子实际上是直接将生成的中间产物丢给 llvm,最终得到了目标平台的可执行程序。可以使用 emit-llvm 参数略过这个过程。

所以,当笔者使用上述命令时,实际上是针对 i686-pc-windows-msvc 编译的。可以向 clang 传递 --verbose 参数查看这些细节。

如果要生成针对 x86_64 平台的可执行程序,应当使用 -target 选项:

clang hello.c -o hello.exe -target x86_64-pc-windows-msvc

根据 LLVM 的 Getting Started 页,LLVM 很依赖宿主机的 C++ 编译器。或者换句话说,就算 Clang 默认支持跨平台编译,也需要有对应平台的 Headers 和 Libraries 才能生成可执行程序(正确进行系统调用等)。

在我们 x86_64-pc-windows-msvc 或者 i386-pc-windows-msvc 的最末一条为 MSVC,即需要 Windows 的 SDK 才能进行开发。

在安装 MSVC 时,自然也是安装了 Windows 的 SDK。如果没有安装 Windows 的 SDK,或者,想针对 MinGW-w64 的平台,则需将 msvc 修改为 gnu,Clang 便会在 PATH 中寻找对应的 include path 和 Libraries 等。

参见:https://stackoverflow.com/questions/39871656/how-to-use-clang-with-mingw-w64-headers-on-windows/47148323#47148323

另请参见:

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值