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

使用Clang交叉编译RISC-V版NumPy/SciPy遇编译错误求助

问题:Clang交叉编译RISC-V架构SciPy时函数指针类型不兼容错误

问题背景

  • 在WSL Ubuntu 20.04环境下,尝试用Clang/Clang++交叉编译面向RISC-V的NumPy和SciPy wheel包
  • 已完成操作:
    • 从源码编译LLVM、rvv-next分支的RISC-V GCC工具链,并用其编译最新版OpenBLAS
    • 借助crossenv搭建交叉编译虚拟环境,安装必要Python包后成功生成NumPy的wheel包
  • 失败情况:SciPy编译时触发函数指针类型不兼容错误

错误详情

scipy/spatial/qhull.c:10158:72: error: incompatible function pointer types passing 'void (*)(qhT *, void *, vertexT *, vertexT *, setT *, unsigned int)' (aka 'void (*)(struct qhT *, void *, struct vertexT *, struct vertexT *, struct setT *, unsigned int)') to parameter of type 'printvridgeT' (aka 'void (*)(struct qhT *, struct _IO_FILE *, struct vertexT *, struct vertexT *, struct setT *, unsigned int)') [-Wincompatible-function-pointer-types]
    (void)(qh_eachvoronoi_all(__pyx_v_self->_qh, ((void *)__pyx_v_self), (&__pyx_f_5scipy_7spatial_5qhull__visit_voronoi), (__pyx_v_self->_qh[0]).UPPERdelaunay, qh_RIDGEall, 1));

注:qhull.c文件由Cython在构建过程中自动生成

完整构建流程

cd ~
mkdir wheels-clang
cd wheels-clang
mkdir other-blas scripts
./scripts/build_gcc_and_clang.sh "$HOME/wheels-clang"
./scripts/download_build_and_install_openblas_using_llvm_toolchain.sh "$HOME/wheels-clang/other-blas" "$HOME/wheels-clang/other-blas/OpenBLAS/usr"

export SYSROOT=/opt/riscv/sysroot
export RISCV_GCC=$HOME/wheels-clang/scripts/llvm-clang-wrapper.sh
export RISCV_GPP=$HOME/wheels-clang/scripts/llvm-clang++-wrapper.sh
export RISCV_GFORTRAN=/opt/riscv/bin/riscv64-unknown-linux-gnu-gfortran
export RISCV_LD=/opt/riscv/bin/riscv64-unknown-linux-gnu-ld
export RISCV_AR=/opt/riscv/bin/riscv64-unknown-linux-gnu-ar

path-to-ubuntu-wsl-python3.9.14/bin/python3 -m pip install crossenv

path-to-ubuntu-wsl-python3.9.14/bin/python3 -m crossenv --cc $RISCV_GCC --cxx $RISCV_GPP --ar $RISCV_AR path-to-riscv-python3.9.14/bin/python riscv_cross_venv_stock
source riscv_cross_venv_stock/bin/activate
build-pip install wheel cython pybind11 pythran ply beniget gast pythran numpy==1.19.3
pip install wheel cython pybind11 pythran ply beniget gast pythran numpy==1.19.3

git clone --recurse-submodules -b v1.7.3 --depth 1 https://github.com/scipy/scipy.git
cd scipy/
echo '[openblas]' > site.cfg
echo 'libraries = openblas' >> site.cfg
echo "library_dirs = $HOME/wheels-clang/other-blas/OpenBLAS/usr/lib" >> site.cfg
echo "include_dirs = $HOME/wheels-clang/other-blas/OpenBLAS/usr/include" >> site.cfg
echo "runtime_library_dirs = $HOME/wheels-clang/other-blas/OpenBLAS/usr/lib" >> site.cfg

export BLAS_DIR=$HOME/wheels-clang/other-blas/OpenBLAS/usr/
export OPEN_BLAS_DIR=$HOME/wheels-clang/other-blas/OpenBLAS/usr/
export F90=$RISCV_GFORTRAN
export F77=$RISCV_GFORTRAN
export LD=$RISCV_LD
export CC=$HOME/wheels-clang/scripts/llvm-clang-wrapper.sh
export CXX=$HOME/wheels-clang/scripts/llvm-clang++-wrapper.sh
export LD_LIBRARY_PATH=$HOME/wheels-clang/other-blas/OpenBLAS/usr/lib:$LD_LIBRARY_PATH

export LDFLAGS="$LDFLAGS -L$HOME/wheels-clang/other-blas/OpenBLAS/usr/lib"
export CPPFLAGS="$CPPFLAGS -I$HOME/wheels-clang/other-blas/OpenBLAS/usr/include"
export PKG_CONFIG_PATH="$HOME/wheels-clang/other-blas/OpenBLAS/usr/lib/pkgconfig"
export BLAS=$HOME/wheels-clang/other-blas/OpenBLAS/usr/lib/libopenblas.so

pip wheel . -v -w ../wheels_stock
cd ..
cp riscv_cross_venv_stock/cross/lib/python3.9/site-packages/numpy/core/lib/libnpymath.a riscv_cross_venv_stock/build/lib/python3.9/site-packages/numpy/core/lib/libnpymath.a
cp riscv_cross_venv_stock/cross/lib/python3.9/site-packages/numpy/random/lib/libnpyrandom.a riscv_cross_venv_stock/build/lib/python3.9/site-packages/numpy/random/lib/libnpyrandom.a
cd scipy/
pip wheel . -v -w ../wheels_stock

配套脚本文件

1. build_gcc_and_clang.sh

#!/bin/bash
function install_prerequisites()
{
    sudo apt -y install autoconf automake autotools-dev
    sudo apt -y install libmpc-dev libmpfr-dev libgmp-dev
    sudo apt -y install build-essential
    sudo apt -y install bison flex
    sudo apt -y install curl python3
    sudo apt -y install texinfo gperf libtool patchutils bc
    sudo apt -y install zlib1g-dev libexpat-dev
    sudo apt -y install make cmake git-all
}

function create_installation_dirs()
{
    sudo mkdir /opt/riscv
    sudo chown -R $USER /opt/riscv
}

function download_and_build_gcc()
{
    git clone https://github.com/riscv/riscv-gnu-toolchain --branch rvv-next
    cd riscv-gnu-toolchain/
    ./configure --with-arch=rv64gcv --prefix=/opt/riscv --enable-linux
    make linux
}

function download_and_build_llvm()
{
    git clone https://github.com/llvm/llvm-project
    cd llvm-project
    mkdir build
    cd build
    cmake -G 'Unix Makefiles' -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/opt/riscv -DLLVM_TARGETS_TO_BUILD="RISCV" -DLLVM_DEFAULT_TARGET_TRIPLE="riscv64-unknown-linux-gnu" -DLLVM_ENABLE_PROJECTS="clang;llvm;lld;flang" ../llvm
    make -j4
    make install
}

DIR_FOR_SOURCES="$1"
if [ -z "$DIR_FOR_SOURCES" ]
then
    DIR_FOR_SOURCES="$HOME"
fi

echo "The parent directory for GCC and LLVM sources: $DIR_FOR_SOURCES"
install_prerequisites
create_installation_dirs
cd "$DIR_FOR_SOURCES"
download_and_build_gcc
cd ..
download_and_build_llvm
cd ..

2. download_build_and_install_openblas_using_llvm_toolchain.sh

#!/bin/bash
function clone_openblas()
{
    git clone https://github.com/xianyi/OpenBLAS.git
    cd OpenBLAS
    sed -i 's/ifeq/#ifeq/g' Makefile.riscv64
    sed -i 's/endif/#endif/g' Makefile.riscv64
    sed -i 's/CCOMMON_OPT += -march=rv64imafdcv0p7_zfh_xtheadc -mabi=lp64d -mtune=c920/CCOMMON_OPT += --target=riscv64-unknown-linux-gnu -march=rv64gcv_zfh -mabi=lp64d --sysroot=$(SYSROOT)/g'  Makefile.riscv64
    sed -i 's/FCOMMON_OPT += -march=rv64imafdcv0p7_zfh_xtheadc -mabi=lp64d -mtune=c920 -static/FCOMMON_OPT += -march=rv64gcv_zfh -mabi=lp64d -static --sysroot=$(SYSROOT)/g' Makefile.riscv64
    sed -i 's/TARGET_FLAGS = -march=rv64gcv0p7_zfh_xtheadc -mabi=lp64d/TARGET_FLAGS = --target=riscv64-unknown-linux-gnu -march=rv64gcv_zfh -mabi=lp64d/g' Makefile.prebuild
}

function setup_environment_vars()
{
    HOSTCC=clang
    CROSS_SUFFIX=llvm-
    ROOT=/opt/riscv
    CC=$ROOT/bin/clang
    FC=/opt/riscv/bin/riscv64-unknown-linux-gnu-gfortran
    AR=$ROOT/bin/${CROSS_SUFFIX}ar
    RANLIB=$ROOT/bin/${CROSS_SUFFIX}ranlib
    SYSROOT=/opt/riscv/sysroot
    GCC_TOOLCHAIN=/opt/riscv
    CFLAGS=" -fuse-ld=lld --gcc-toolchain=$GCC_TOOLCHAIN"
}

function build_openblas()
{
    make -j4 TARGET=C910V CC=$CC FC=$FC AR=$AR RANLIB=$RANLIB HOSTCC=$HOSTCC SYSROOT=$SYSROOT CROSS_SUFFIX=$CROSS_SUFFIX CFLAGS="$CFLAGS" V=1
    if ! [ -d "$1" ]
    then
        echo "The defined installation directory $1 does not exist and will be created."
        mkdir -p "$1"
    fi
    make install PREFIX="$1"
    cd ..
}

DIR_FOR_SOURCES="$1"
INSTALLATION_DIR="$2"

if [ -z "$DIR_FOR_SOURCES" ]
then
    echo "A directory for OpenBLAS sources was not defined. The directory $HOME will be used by default."
    DIR_FOR_SOURCES="$HOME"
fi

if [ -z "$INSTALLATION_DIR" ]
then
    echo "Creating the default directory to install."
    sudo mkdir /opt/OpenBLAS
    sudo chown -R $USER /opt/OpenBLAS
    INSTALLATION_DIR="/opt/OpenBLAS"
    echo "A directory to install OpenBLAS was not defined. The directory $INSTALLATION_DIR will be used by default."
fi

echo "Directory for BLAS sources: $HOME"
echo "Installation directory: $INSTALLATION_DIR"
cd "$DIR_FOR_SOURCES"
clone_openblas
setup_environment_vars
build_openblas "$INSTALLATION_DIR"

echo "OpenBLAS was installed into $INSTALLATION_DIR"

3. llvm-clang-wrapper.sh

#!/bin/bash
GCC_TOOLCHAIN=/opt/riscv
/opt/riscv/bin/clang --target=riscv64-unknown-linux-gnu -march=rv64gcv_zfh -mabi=lp64d -v --sysroot=$SYSROOT -fuse-ld=lld --gcc-toolchain=$GCC_TOOLCHAIN "$@"

4. llvm-clang++-wrapper.sh

#!/bin/bash
GCC_TOOLCHAIN=/opt/riscv
/opt/riscv/bin/clang++ --target=riscv64-unknown-linux-gnu -march=rv64gcv_zfh -mabi=lp64d -v --sysroot=$SYSROOT -fuse-ld=lld --gcc-toolchain=$GCC_TOOLCHAIN "$@"

已知可行对比情况

  • 使用Ubuntu官方提供的RISC-V交叉编译GCC工具链时,可成功生成NumPy和SciPy的正确wheel包
  • 使用Ubuntu 20.04仓库的Clang/Clang+++GFortran时出现链接错误

解决方案

1. 临时禁用函数指针类型不兼容警告

Clang的类型检查比GCC更严格,该错误属于警告升级为错误。在SciPy编译前添加编译选项忽略该警告:

# 在SciPy目录下执行
export CFLAGS="$CFLAGS -Wno-incompatible-function-pointer-types"
# 重新编译
pip wheel . -v -w ../wheels_stock

2. 匹配Cython与SciPy版本兼容性

当前使用的Cython版本可能与Clang交叉编译存在适配问题,SciPy 1.7.3推荐使用Cython 0.29.30版本:

# 在crossenv激活状态下执行
build-pip uninstall -y cython
build-pip install cython==0.29.30
pip uninstall -y cython
pip install cython==0.29.30
# 进入SciPy目录,清理之前生成的文件后重新编译
cd scipy/
rm -rf build/ scipy/spatial/qhull.c
pip wheel . -v -w ../wheels_stock

3. 调整Clang编译选项匹配GCC宽松度

添加选项降低Clang的类型检查严格程度:

export CFLAGS="$CFLAGS -fno-strict-aliasing -Wno-pointer-sign"

4. 验证交叉环境头文件引用

确保编译时使用的是RISC-V交叉环境中的qhull头文件,而非主机系统的。检查CPPFLAGS是否包含交叉环境的头文件路径,若缺失则添加:

export CPPFLAGS="$CPPFLAGS -I/opt/riscv/sysroot/usr/include"

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 01:25:40