从macOS(arm64)交叉编译到Windows(x86_x64)时Conan/CMake无法识别LLVM链接器
Mac下用Conan+CMake交叉编译Windows程序失败的解决方法
问题背景
在Mac设备上,使用Conan 2.1、CMake 3.28.3、LLVM Clang 17.0.6(均通过Homebrew安装)交叉编译Windows平台的"hello world"程序时失败,但手动编译可正常运行。
手动编译成功步骤
# 切换到Homebrew安装的LLVM,替代AppleClang export LLVM_DIR=/opt/homebrew/opt/llvm export PATH="$LLVM_DIR/bin:$PATH" export LDFLAGS="-L$LLVM_DIR/lib" export CPPFLAGS="-I$LLVM_DIR/include" export CC=$LLVM_DIR/bin/clang export CXX=$LLVM_DIR/bin/clang++ # 配置Windows交叉编译所需SDK路径 export SDK_DIR=/Users/pawel/SDKs export MSVC_DIR=$SDK_DIR/MSVC/14.39.33519 export WIN_INC_DIR=$SDK_DIR/Win/10/Include/10.0.22621.0 export WIN_LIB_DIR=$SDK_DIR/Win/10/Lib/10.0.22621.0 # 执行交叉编译 clang++ \ -I$MSVC_DIR/include \ -L$MSVC_DIR/lib/x64 \ -I$WIN_INC_DIR/ucrt \ -L$WIN_LIB_DIR/ucrt/x64 \ -L$WIN_LIB_DIR/um/x64 \ -fuse-ld=lld-link \ -lmsvcrt \ -lucrt \ -lvcruntime \ -o hello.exe \ -target x86_64-pc-windows-msvc \ -g \ -O0 \ hello.cpp
Conan/CMake编译失败流程
使用以下命令触发编译:
# Conan安装依赖并生成配置 conan install . \ --output-folder=cmake-build-win-debug \ --profile:host=host-windows-llvm-x64-debug \ --profile:build=build-mac-llvm-x64-debug # 使用Conan生成的预设执行CMake cmake --preset windows-debug
相关文件内容
conanfile.py
from conan import ConanFile from conan.tools.cmake import CMakeToolchain, CMakeDeps class PackageConan(ConanFile): settings = 'os', 'build_type', 'compiler', 'arch' options = {'target_os': ['Windows', 'Macos']} def generate(self): tc = CMakeToolchain(self) tc.presets_prefix = f'{self.options.target_os}'.lower() tc.generate() cmake_deps = CMakeDeps(self) cmake_deps.generate()
CMakeLists.txt
cmake_minimum_required(VERSION 3.28) project(hello CXX) # 指定C++标准 set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) add_executable(hello hello.cpp)
Conan配置文件
default-llvm
[settings] arch=armv8 build_type=Release compiler=clang compiler.cppstd=20 compiler.libcxx=libc++ compiler.version=17 os=Macos [buildenv] CC=/opt/homebrew/opt/llvm/bin/clang CXX=/opt/homebrew/opt/llvm/bin/clang++
build-mac-llvm-x64-debug
include(default-llvm) [settings] arch=x86_64 build_type=Debug [buildenv] CXXFLAGS=-g -O0
host-windows-llvm-x64-debug
include(default-llvm) [settings] os=Windows arch=x86_64 build_type=Debug [options] target_os=Windows [conf] tools.cmake.cmaketoolchain:generator=Ninja [buildenv] CXXFLAGS=-g -O0 LDFLAGS=-fuse-ld=lld-link -L/Users/pawel/SDKs/MSVC/14.39.33519/lib/x64 -L/Users/pawel/SDKs/Win/10/Lib/10.0.22621.0/ucrt/x64 -L/Users/pawel/SDKs/Win/10/Lib/10.0.22621.0/um/x64 PATH=/opt/homebrew/opt/llvm/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
错误信息
clang++: 错误:参数 '-fuse-ld=lld-link' 中的链接器名称无效
解决方法
核心问题
手动编译时指定了-target x86_64-pc-windows-msvc告诉Clang要编译Windows程序,但Conan/CMake流程中未配置该目标参数,导致Clang默认编译Mac平台程序,无法识别Windows专用的lld-link链接器。
修改步骤
- 更新conanfile.py,在CMakeToolchain中添加交叉编译目标、链接器设置以及Windows SDK的头文件/库路径:
from conan import ConanFile from conan.tools.cmake import CMakeToolchain, CMakeDeps class PackageConan(ConanFile): settings = 'os', 'build_type', 'compiler', 'arch' options = {'target_os': ['Windows', 'Macos']} def generate(self): tc = CMakeToolchain(self) tc.presets_prefix = f'{self.options.target_os}'.lower() # 设置Windows交叉编译目标 tc.variables["CMAKE_CXX_COMPILER_TARGET"] = "x86_64-pc-windows-msvc" # 指定使用lld-link链接器 tc.link_flags.append("-fuse-ld=lld-link") # 添加MSVC和Windows SDK的头文件路径 sdk_dir = "/Users/pawel/SDKs" tc.add_include_paths([ f"{sdk_dir}/MSVC/14.39.33519/include", f"{sdk_dir}/Win/10/Include/10.0.22621.0/ucrt" ]) # 添加MSVC和Windows SDK的库路径 tc.add_link_paths([ f"{sdk_dir}/MSVC/14.39.33519/lib/x64", f"{sdk_dir}/Win/10/Lib/10.0.22621.0/ucrt/x64", f"{sdk_dir}/Win/10/Lib/10.0.22621.0/um/x64" ]) # 添加需要链接的Windows运行时库 tc.link_flags.extend(["-lmsvcrt", "-lucrt", "-lvcruntime"]) tc.generate() cmake_deps = CMakeDeps(self) cmake_deps.generate()
- 修改host-windows-llvm-x64-debug配置文件,移除
LDFLAGS中的-fuse-ld=lld-link(已在toolchain中设置):
include(default-llvm) [settings] os=Windows arch=x86_64 build_type=Debug [options] target_os=Windows [conf] tools.cmake.cmaketoolchain:generator=Ninja [buildenv] CXXFLAGS=-g -O0 LDFLAGS=-L/Users/pawel/SDKs/MSVC/14.39.33519/lib/x64 -L/Users/pawel/SDKs/Win/10/Lib/10.0.22621.0/ucrt/x64 -L/Users/pawel/SDKs/Win/10/Lib/10.0.22621.0/um/x64 PATH=/opt/homebrew/opt/llvm/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
- 重新执行编译命令:
# 清理旧的构建目录(可选) rm -rf cmake-build-win-debug # 重新运行Conan和CMake conan install . \ --output-folder=cmake-build-win-debug \ --profile:host=host-windows-llvm-x64-debug \ --profile:build=build-mac-llvm-x64-debug cmake --preset windows-debug cmake --build cmake-build-win-debug
说明
通过在CMakeToolchain中明确设置CMAKE_CXX_COMPILER_TARGET,Clang会知晓目标平台是Windows,此时-fuse-ld=lld-link参数才会被正确识别。同时将头文件、库路径和链接库统一配置在toolchain中,避免了环境变量传递的不确定性,让Conan和CMake的流程与手动编译逻辑保持一致。
内容的提问来源于stack exchange,提问作者Pawel Pajor
相关产品推荐
相关产品推荐

