AutoTools:使用 LLVM/Clang Windows 编译器

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

  • 使用 MSVC 运行时的 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 的项目和使用 AutotoolsToolchain 的 Conan 包 Recipe。

Autotools: 使用 GNU 风格前端 clang 的 LLVM/Clang

为了构建此配置,我们将使用以下 Profile

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

Profile 快速说明

  • 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: 使用 MSVC 风格前端 clang-cl 的 LLVM/Clang

为了构建此配置,我们将使用以下 Profile

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

该 Profile 与上面的几乎相同,主要区别在于 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 的项目。但需要提供该 Clang 组件在 Visual Studio 安装文件夹中的完整路径,以便通过 [buildenv] 和 或 tools.build:compiler_executables 找到它,因为它本质上是由 Visual Studio 安装程序打包和分发的 LLVM/Clang 编译器。