AutoTools:使用 LLVM/Clang Windows 编译器

Windows 中的 Clang 编译器可以来自 2 种不同的安装或发行版

  • 使用 MSVC 运行时(runtime)的 LLVM/Clang 编译器

  • 使用 Msys2 运行时(libstdc++6.dll)的 Msys2 Clang 编译器

本示例解释了使用 MSVC 运行时的 LLVM/Clang。此 Clang 发行版又可以通过两种不同的方式使用

  • 使用下载的 LLVM/Clang 编译器(仍使用 MSVC 运行时),通过类 GNU 的前端 `clang`

  • 使用下载的 LLVM/Clang 编译器(仍使用 MSVC 运行时),通过类 MSVC 的前端 `clang-cl`

让我们从一个简单的 `autotools_exe` 模板开始

$ conan new autotools_exe -d name=mypkg -d version=0.1

这将创建一个简单的基于 Autotools 的项目和 Conan 包配方,它使用 `AutotoolsToolchain`。

AutoTools:使用 `clang` 类 GNU 前端的 LLVM/Clang

我们将使用以下配置文件来构建此配置

llvm_clang
[settings]
os=Windows
arch=x86_64
build_type=Release
compiler=clang
compiler.version=18
compiler.cppstd=14
compiler.runtime=dynamic
compiler.runtime_type=Release
compiler.runtime_version=v144

[buildenv]
PATH=+(path)C:\ws\LLVM\18.1\bin

[conf]
tools.compilation:verbosity=verbose
tools.build:compiler_executables = {"c": "clang", "cpp": "clang++"}
tools.microsoft.bash:subsystem=msys2
tools.microsoft.bash:path=C:\ws\msys64\usr\bin\bash.exe

配置文件快速说明

  • `compiler.runtime` 定义是区分 Msys2-Clang 和使用 MSVC 运行时的 LLVM/Clang 的重要区别。LLVM/Clang 定义了这个 `compiler.runtime`,而 Msys2-Clang 则没有。

  • MSVC 运行时可以是动态的或静态的。定义此运行时的运行时版本(工具集版本 `v144`)也很重要,因为可以使用不同的版本。

  • `[buildenv]` 允许指向 LLVM/Clang 编译器,以防它尚未在路径中。**注意** `PATH=+(path)` 语法,用于**前置**该路径,使其具有更高的优先级

  • 在定义 `tools.microsoft.bash:path` 时,使用了 `msys2` `bash.exe` 的完整路径。否则,它可能会在 Windows 系统中找到另一个无效的 `bash.exe`。

让我们来构建它

$ conan build . -pr=llvm_clang
...
conanfile.py (mypkg/0.1): Calling build()
conanfile.py (mypkg/0.1): RUN: autoreconf --force --install
conanfile.py (mypkg/0.1): RUN: "/c/projectpath/clang/configure" --prefix=/ --bindir=${prefix}/bin --sbindir=${prefix}/bin --libdir=${prefix}/lib --includedir=${prefix}/include --oldincludedir=${prefix}/include
conanfile.py (mypkg/0.1): RUN: make -j8
...
clang++ -DPACKAGE_NAME=\"mypkg\" -DPACKAGE_TARNAME=\"mypkg\" -DPACKAGE_VERSION=\"0.1\" -DPACKAGE_STRING=\"mypkg\ 0.1\" -DPACKAGE_BUGREPORT=\"\" -DPACKAGE_URL=\"\" -DPACKAGE=\"mypkg\" -DVERSION=\"0.1\" -I. -I/c/projectpath/clang/src   -DNDEBUG  -std=c++14 -D_DLL -D_MT -Xclang --dependent-lib=msvcrt -O3 -c -o main.o /c/projectpath/clang/src/main.cpp
source='/c/projectpath/clang/src/mypkg.cpp' object='mypkg.o' libtool=no \
DEPDIR=.deps depmode=none /bin/sh /c/projectpath/clang/depcomp \
clang++ -DPACKAGE_NAME=\"mypkg\" -DPACKAGE_TARNAME=\"mypkg\" -DPACKAGE_VERSION=\"0.1\" -DPACKAGE_STRING=\"mypkg\ 0.1\" -DPACKAGE_BUGREPORT=\"\" -DPACKAGE_URL=\"\" -DPACKAGE=\"mypkg\" -DVERSION=\"0.1\" -I. -I/c/projectpath/clang/src   -DNDEBUG  -std=c++14 -D_DLL -D_MT -Xclang --dependent-lib=msvcrt -O3 -c -o mypkg.o /c/projectpath/clang/src/mypkg.cpp
clang++  -std=c++14 -D_DLL -D_MT -Xclang --dependent-lib=msvcrt -O3  -fuse-ld=lld-link -o mypkg.exe main.o mypkg.o

请注意如何使用 `clang++` 编译器,运行时是通过 `-D_DLL -D_MT -Xclang --dependent-lib=msvcrt` 选择的。

我们可以运行我们的可执行文件,并查看 Clang 编译器版本和 MSVC 运行时如何与定义的匹配

$ build-release\src\mypkg.exe
mypkg/0.1: Hello World Release!
    mypkg/0.1: _M_X64 defined
    mypkg/0.1: __x86_64__ defined
    mypkg/0.1: MSVC runtime: MultiThreadedDLL
    mypkg/0.1: _MSC_VER1943
    mypkg/0.1: _MSVC_LANG201402
    mypkg/0.1: __cplusplus201402
    mypkg/0.1: __clang_major__18
    mypkg/0.1: __clang_minor__1

AutoTools:使用 `clang-cl` 类 MSVC 前端的 LLVM/Clang

我们将使用以下配置文件来构建此配置

llvm_clang_cl
[settings]
os=Windows
arch=x86_64
build_type=Release
compiler=clang
compiler.version=18
compiler.cppstd=14
compiler.runtime=dynamic
compiler.runtime_type=Release
compiler.runtime_version=v144

[buildenv]
PATH=+(path)C:/ws/LLVM/18.1/bin

[conf]
tools.compilation:verbosity=verbose
tools.microsoft.bash:subsystem=msys2
tools.build:compiler_executables = {"c": "clang-cl", "cpp": "clang-cl"}
tools.microsoft.bash:path=C:\ws\msys64\usr\bin\bash.exe

配置文件与上面的几乎相同,主要区别在于 `tools.build:compiler_executables` 的定义,它定义了 `clang-cl` 编译器。

注意

使用 `clang-cl` 编译器的 `tools.build:compiler_executables` 定义是 Conan 用来区分前端的,同样也用于其他构建系统。这个前端不是一个 `setting`,因为编译器仍然是相同的,并且生成的二进制文件应该是二进制兼容的。

让我们来构建它

$ conan build . -pr=llvm_clang_cl
...
clang-cl -DPACKAGE_NAME=\"mypkg\" -DPACKAGE_TARNAME=\"mypkg\" -DPACKAGE_VERSION=\"0.1\" -DPACKAGE_STRING=\"mypkg\ 0.1\" -DPACKAGE_BUGREPORT=\"\" -DPACKAGE_URL=\"\" -DPACKAGE=\"mypkg\" -DVERSION=\"0.1\" -I. -I/c/projectpath/clang/src   -DNDEBUG  -std:c++14 -MD -O2 -c -o main.obj `cygpath -w '/c/projectpath/clang/src/main.cpp'`
source='/c/projectpath/clang/src/mypkg.cpp' object='mypkg.obj' libtool=no \
DEPDIR=.deps depmode=msvc7msys /bin/sh /c/projectpath/clang/depcomp \
clang-cl -DPACKAGE_NAME=\"mypkg\" -DPACKAGE_TARNAME=\"mypkg\" -DPACKAGE_VERSION=\"0.1\" -DPACKAGE_STRING=\"mypkg\ 0.1\" -DPACKAGE_BUGREPORT=\"\" -DPACKAGE_URL=\"\" -DPACKAGE=\"mypkg\" -DVERSION=\"0.1\" -I. -I/c/projectpath/clang/src   -DNDEBUG  -std:c++14 -MD -O2 -c -o mypkg.obj `cygpath -w '/c/projectpath/clang/src/mypkg.cpp'`
clang-cl  -std:c++14 -MD -O2   -o mypkg.exe main.obj mypkg.obj
...

请注意如何使用所需的 `clang-cl`,以及如何使用 `MSVC-like` 命令行语法,例如 `-std:c++14`。这种类 MSVC 的语法使用 `-MD/-MT` 标志来区分动态/静态 MSVC 运行时。

我们可以运行我们的可执行文件,并查看 Clang 编译器版本和 MSVC 运行时如何与定义的匹配

$ build\Release\mypkg.exe
mypkg/0.1: Hello World Release!
    mypkg/0.1: _M_X64 defined
    mypkg/0.1: __x86_64__ defined
    mypkg/0.1: MSVC runtime: MultiThreadedDLL
    mypkg/0.1: _MSC_VER1943
    mypkg/0.1: _MSVC_LANG201402
    mypkg/0.1: __cplusplus201402
    mypkg/0.1: __clang_major__18
    mypkg/0.1: __clang_minor__1

正如预期的那样,输出与之前的完全相同,因为除了编译器前端之外,没有任何改变。

注意

有可能使用 Visual Studio 组件提供的 `clang-cl` 来构建 autotools-like 项目。但有必要通过 `[buildenv]` 和/或 `tools.build:compiler_executables` 提供该 Visual Studio 已安装文件夹中 Clang 组件的完整路径,以便找到它,因为它基本上是一个 LLVM/Clang 编译器,由 Visual Studio 安装程序打包和分发。