macOS用Homebrew自定义LLVM交叉编译Linux共享库配置问题排查
macOS下Clang交叉编译Linux共享库的CMake配置问题
初始配置
我的CMakeLists.txt配置如下:
cmake_minimum_required(VERSION 3.9) project(Arkan) # Specify the C++ standard set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED True) # Build the native Arkan library add_library(arkan SHARED lib/cpp/greeting.cpp ) set_target_properties(arkan PROPERTIES VERSION ${PROJECT_VERSION}) set_target_properties(arkan PROPERTIES SOVERSION 0) set_target_properties(arkan PROPERTIES PUBLIC_HEADER lib/cpp/include/arkan.hpp)
这是一个结构简单的共享库项目,需要在macOS平台上编译生成适用于Linux平台的共享库,最初编写的工具链文件如下:
set(triple x86_64-linux-gnu) set(llvm /opt/homebrew/Cellar/llvm/13.0.1_1) set(CMAKE_SYSTEM_NAME Linux) set(CMAKE_SYSTEM_PROCESSOR x86_64) set(CMAKE_IGNORE_PATH /Applications/Xcode.app) set(CMAKE_PREFIX_PATH ${llvm}) set(CMAKE_C_COMPILER ${llvm}/bin/clang) set(CMAKE_C_COMPILER_TARGET ${triple}) set(CMAKE_C_STANDARD_LIBRARIES ${llvm}/lib) set(CMAKE_C_STANDARD_INCLUDE_DIRECTORIES ${llvm}/include/c++/v1) set(CMAKE_C_LINK_EXECUTABLE ${llvm}/bin/llvm-link) set(CMAKE_CXX_COMPILER ${llvm}/bin/clang++) set(CMAKE_CXX_COMPILER_TARGET ${triple}) set(CMAKE_CXX_STANDARD_LIBRARIES ${llvm}/lib) set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES ${llvm}/include/clang) set(CMAKE_CXX_LINK_EXECUTABLE ${llvm}/bin/llvm-link) SET(CMAKE_AR ${llvm}/bin/llvm-ar) SET(CMAKE_LINKER ${llvm}/bin/llvm-link) SET(CMAKE_NM ${llvm}/bin/llvm-nm) SET(CMAKE_OBJDUMP ${llvm}/bin/llvm-objdump) SET(CMAKE_RANLIB ${llvm}/bin/llvm-ranlib)
项目配置阶段出现如下报错:
[100%] Built target arkan -- The C compiler identification is Clang 13.0.1 -- The CXX compiler identification is Clang 13.0.1 -- Detecting C compiler ABI info -- Detecting C compiler ABI info - failed -- Check for working C compiler: /opt/homebrew/Cellar/llvm/13.0.1_1/bin/clang -- Check for working C compiler: /opt/homebrew/Cellar/llvm/13.0.1_1/bin/clang - broken CMake Error at /opt/homebrew/Cellar/cmake/3.23.2/share/cmake/Modules/CMakeTestCCompiler.cmake:69 (message): The C compiler "/opt/homebrew/Cellar/llvm/13.0.1_1/bin/clang" is not able to compile a simple test program. It fails with the following output: Change Dir: /Users/user/Projects/arkan/build/linux/x86_64/CMakeFiles/CMakeTmp Run Build Command(s):/usr/bin/make -f Makefile cmTC_bf6b9/fast && /Applications/Xcode.app/Contents/Developer/usr/bin/make -f CMakeFiles/cmTC_bf6b9.dir/build.make CMakeFiles/cmTC_bf6b9.dir/build Building C object CMakeFiles/cmTC_bf6b9.dir/testCCompiler.c.o /opt/homebrew/Cellar/llvm/13.0.1_1/bin/clang --target=x86_64-linux-gnu -isystem /opt/homebrew/Cellar/llvm/13.0.1_1/include/c++/v1 -MD -MT CMakeFiles/cmTC_bf6b9.dir/testCCompiler.c.o -MF CMakeFiles/cmTC_bf6b9.dir/testCCompiler.c.o.d -o CMakeFiles/cmTC_bf6b9.dir/testCCompiler.c.o -c /Users/user/Projects/arkan/build/linux/x86_64/CMakeFiles/CMakeTmp/testCCompiler.c Linking C executable cmTC_bf6b9 /opt/homebrew/Cellar/cmake/3.23.2/bin/cmake -E cmake_link_script CMakeFiles/cmTC_bf6b9.dir/link.txt --verbose=1 /opt/homebrew/Cellar/llvm/13.0.1_1/bin/llvm-link llvm-link: Not enough positional command line arguments specified! Must specify at least 1 positional argument: See: /opt/homebrew/Cellar/llvm/13.0.1_1/bin/llvm-link --help make[1]: *** [cmTC_bf6b9] Error 1 make: *** [cmTC_bf6b9/fast] Error 2 CMake will not be able to correctly generate this project. Call Stack (most recent call first): CMakeLists.txt:3 (project)
配置迭代过程
第一次更新:构建脚本
build.sh构建脚本内容如下:
#!/bin/bash # Variables A_BUILDDIR=./build A_OUTDIR=$A_BUILDDIR/out A_THREADS=4 # Check for .env configuration if [ -f .env ]; then source .env fi # Create build and output directories if they do not exist mkdir -p $A_BUILDDIR mkdir -p $A_OUTDIR ################# # Linux platform ################# for ABI in "x86_64"; do LINUX_BUILDDIR=$A_BUILDDIR/linux/$ABI LINUX_OUTDIR=$A_OUTDIR/linux/$ABI mkdir -p $LINUX_BUILDDIR mkdir -p $LINUX_OUTDIR cmake -S . -B $LINUX_BUILDDIR \ -DCMAKE_TOOLCHAIN_FILE=toolchains/${ABI}_linux_gnu.toolchain.cmake cmake --build $LINUX_BUILDDIR -j $A_THREADS cp $LINUX_BUILDDIR/*.so $LINUX_OUTDIR done
第二次更新:补全链接参数后的报错
补全CMAKE_C_LINK_EXECUTABLE和CMAKE_CXX_LINK_EXECUTABLE的参数占位符后,工具链配置如下:
set(triple x86_64-linux-gnu) set(llvm /opt/homebrew/Cellar/llvm/13.0.1_1) set(CMAKE_SYSTEM_NAME Linux) set(CMAKE_SYSTEM_PROCESSOR x86_64) set(CMAKE_IGNORE_PATH /Applications/Xcode.app) set(CMAKE_PREFIX_PATH ${llvm}) set(CMAKE_C_COMPILER ${llvm}/bin/clang) set(CMAKE_C_COMPILER_TARGET ${triple}) set(CMAKE_C_STANDARD_LIBRARIES ${llvm}/lib) set(CMAKE_C_STANDARD_INCLUDE_DIRECTORIES ${llvm}/include/c++/v1) set(CMAKE_C_LINK_EXECUTABLE "${llvm}/bin/llvm-link <FLAGS> <CMAKE_C_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>") set(CMAKE_CXX_COMPILER ${llvm}/bin/clang++) set(CMAKE_CXX_COMPILER_TARGET ${triple}) set(CMAKE_CXX_STANDARD_LIBRARIES ${llvm}/lib) set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES ${llvm}/include/clang) set(CMAKE_CXX_LINK_EXECUTABLE "${llvm}/bin/llvm-link <FLAGS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>") SET(CMAKE_AR ${llvm}/bin/llvm-ar) SET(CMAKE_LINKER ${llvm}/bin/llvm-link) SET(CMAKE_NM ${llvm}/bin/llvm-nm) SET(CMAKE_OBJDUMP ${llvm}/bin/llvm-objdump) SET(CMAKE_RANLIB ${llvm}/bin/llvm-ranlib)
修改后出现新的报错:
Run Build Command(s):/usr/bin/make -f Makefile cmTC_1d33d/fast && /Applications/Xcode.app/Contents/Developer/usr/bin/make -f CMakeFiles/cmTC_1d33d.dir/build.make CMakeFiles/cmTC_1d33d.dir/build Building C object CMakeFiles/cmTC_1d33d.dir/testCCompiler.c.o /opt/homebrew/Cellar/llvm/13.0.1_1/bin/clang --target=x86_64-linux-gnu -isystem /opt/homebrew/Cellar/llvm/13.0.1_1/include/c++/v1 -MD -MT CMakeFiles/cmTC_1d33d.dir/testCCompiler.c.o -MF CMakeFiles/cmTC_1d33d.dir/testCCompiler.c.o.d -o CMakeFiles/cmTC_1d33d.dir/testCCompiler.c.o -c /Users/user/Projects/arkan/build/linux/x86_64/CMakeFiles/CMakeTmp/testCCompiler.c Linking C executable cmTC_1d33d /opt/homebrew/Cellar/cmake/3.23.2/bin/cmake -E cmake_link_script CMakeFiles/cmTC_1d33d.dir/link.txt --verbose=1 /opt/homebrew/Cellar/llvm/13.0.1_1/bin/llvm-link CMakeFiles/cmTC_1d33d.dir/testCCompiler.c.o -o cmTC_1d33d /opt/homebrew/Cellar/llvm/13.0.1_1/lib /opt/homebrew/Cellar/llvm/13.0.1_1/bin/llvm-link: CMakeFiles/cmTC_1d33d.dir/testCCompiler.c.o:1:1: error: expected top-level entity ELF > � @ @ UH���E� �}�H�u��E���]� Homebrew clang version 13.0.1 zR x A�C /opt/homebrew/Cellar/llvm/13.0.1_1/bin/llvm-link: error: loading file 'CMakeFiles/cmTC_1d33d.dir/testCCompiler.c.o' make[1]: *** [cmTC_1d33d] Error 1 make: *** [cmTC_1d33d/fast] Error 2
第三次更新:简化工具链后的报错
移除错误的llvm-link配置,改用-fuse-ld=lld指定链接器,简化后的工具链配置如下:
set(triple x86_64-linux-gnu) set(llvm /opt/homebrew/Cellar/llvm/13.0.1_1) set(CMAKE_SYSTEM_NAME Linux) set(CMAKE_SYSTEM_PROCESSOR x86_64) set(CMAKE_IGNORE_PATH /Applications/Xcode.app) set(CMAKE_PREFIX_PATH ${llvm}) set(CMAKE_C_COMPILER ${llvm}/bin/clang) set(CMAKE_C_COMPILER_TARGET ${triple}) set(CMAKE_C_FLAGS "-fuse-ld=lld") set(CMAKE_CXX_COMPILER ${llvm}/bin/clang++) set(CMAKE_CXX_COMPILER_TARGET ${triple}) set(CMAKE_CXX_FLAGS "-fuse-ld=lld")
此时出现新的报错:
clang-13: warning: argument unused during compilation: '-fuse-ld=lld' [-Wunused-command-line-argument] Linking C executable cmTC_3631b /opt/homebrew/Cellar/cmake/3.23.2/bin/cmake -E cmake_link_script CMakeFiles/cmTC_3631b.dir/link.txt --verbose=1 /opt/homebrew/Cellar/llvm/13.0.1_1/bin/clang --target=x86_64-linux-gnu -fuse-ld=lld CMakeFiles/cmTC_3631b.dir/testCCompiler.c.o -o cmTC_3631b ld.lld: error: /Library/Developer/CommandLineTools/SDKs/MacOSX12.sdk/usr/lib/crt1.o: unknown file type ld.lld: error: cannot open crti.o: No such file or directory ld.lld: error: cannot open crtbegin.o: No such file or directory ld.lld: error: unable to find library -lgcc ld.lld: error: unable to find library -lgcc_s ld.lld: error: unable to find library -lc ld.lld: error: unable to find library -lgcc ld.lld: error: unable to find library -lgcc_s ld.lld: error: cannot open crtend.o: No such file or directory ld.lld: error: cannot open crtn.o: No such file or directory
问题原因与修复方案
核心配置错误
- 误用
llvm-link作为原生程序链接器:llvm-link是LLVM位码(bitcode)专用链接工具,不支持链接原生ELF/Mach-O格式的目标文件。第一次报错是因为直接调用llvm-link未传任何参数,第二次报错是因为传入编译生成的ELF格式.o文件,llvm-link无法识别文件格式。 - 未配置Linux系统根目录(sysroot):交叉编译时编译器不会自动获取目标平台的系统库、头文件、启动文件(
crt*.o)路径,当前配置没有指定Linux sysroot,Clang会默认搜索本地macOS的SDK路径,就会出现加载MacOSX.sdk下的crt1.o格式不兼容、找不到libc等Linux系统库的错误。 - 错误指定本地LLVM路径为标准库/头文件路径:Homebrew安装的LLVM自带的include、lib目录是macOS平台原生资源,不包含Linux平台的运行时文件,手动指定这些路径反而会干扰交叉编译的搜索逻辑。
- 链接参数传递错误:
-fuse-ld=lld是链接阶段参数,只加到CMAKE_C_FLAGS/CMAKE_CXX_FLAGS中只会在编译阶段生效,所以会出现参数未使用的警告。
正确配置步骤
- 提前准备x86_64 Linux的sysroot:可以从目标Linux发行版下载glibc、libc++/libstdc++的开发包解压得到,也可以通过crosstool-ng生成成套交叉编译环境,或者从Linux x86_64容器中拷贝
/lib、/usr/lib、/usr/include相关目录作为sysroot。 - 删除工具链中所有
llvm-link相关的错误配置,不要手动覆盖CMAKE_AR、CMAKE_LINKER等二进制工具变量,Clang配合lld会自动调用对应工具,参考修正后的工具链配置:
set(triple x86_64-linux-gnu) set(llvm /opt/homebrew/Cellar/llvm/13.0.1_1) # 替换为你实际存放Linux x86_64 sysroot的绝对路径 set(sysroot /path/to/your/x86_64-linux-gnu-sysroot) set(CMAKE_SYSTEM_NAME Linux) set(CMAKE_SYSTEM_PROCESSOR x86_64) set(CMAKE_IGNORE_PATH /Applications/Xcode.app) set(CMAKE_C_COMPILER ${llvm}/bin/clang) set(CMAKE_C_COMPILER_TARGET ${triple}) set(CMAKE_C_FLAGS "--sysroot=${sysroot}") # 链接阶段参数单独通过对应LINKER_FLAGS传递 set(CMAKE_EXE_LINKER_FLAGS "-fuse-ld=lld --sysroot=${sysroot}") set(CMAKE_SHARED_LINKER_FLAGS "-fuse-ld=lld --sysroot=${sysroot}") set(CMAKE_CXX_COMPILER ${llvm}/bin/clang++) set(CMAKE_CXX_COMPILER_TARGET ${triple}) set(CMAKE_CXX_FLAGS "--sysroot=${sysroot} -stdlib=libc++") # 配置搜索规则:程序搜索用本地环境,库、头文件、包只搜索sysroot路径 set(CMAKE_FIND_ROOT_PATH ${sysroot}) set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
- 配置完成后删除之前的build目录重新生成缓存,即可正常交叉编译。
内容的提问来源于stack exchange,提问作者Denis Steinman
相关产品推荐
相关产品推荐

