使用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
相关产品推荐
相关产品推荐

