You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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中只会在编译阶段生效,所以会出现参数未使用的警告。

正确配置步骤

  1. 提前准备x86_64 Linux的sysroot:可以从目标Linux发行版下载glibc、libc++/libstdc++的开发包解压得到,也可以通过crosstool-ng生成成套交叉编译环境,或者从Linux x86_64容器中拷贝/lib、/usr/lib、/usr/include相关目录作为sysroot。
  2. 删除工具链中所有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)
  1. 配置完成后删除之前的build目录重新生成缓存,即可正常交叉编译。

内容的提问来源于stack exchange,提问作者Denis Steinman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 00:18:22