news 2026/9/18 19:30:41

Julia 在 RISC-V (Linux) 上的编译与交叉编译指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Julia 在 RISC-V (Linux) 上的编译与交叉编译指南

Julia 在 RISC-V (Linux) 上的编译与交叉编译指南

【免费下载链接】juliaThe Julia Programming Language项目地址: https://gitcode.com/gh_mirrors/ju/julia

本指南以 Julia 官方开发文档 doc/src/devdocs/build/riscv.md 为主体,系统讲解如何在 64 位 RISC-V(RV64)Linux 设备上原生编译 Julia,以及如何在 x86 等更快的主机上通过交叉编译产出 RISC-V 版本。读完本文,你将掌握MARCH/MCPU/JULIA_CPU_TARGET等核心构建变量的正确设置方式,并能独立搭建 riscv-gnu-toolchain + QEMU 的交叉编译环境,完成 Julia 在如 StarFive VisionFive2 等开发板上的完整构建。

RISC-V 支持现状与前提

Julia 目前对运行 Linux 的 64 位 RISC-V(RV64)处理器提供**实验性(experimental)**支持。这意味着:

  • 构建与运行链路已经打通,但某些功能仍可能存在缺陷或性能问题;
  • 社区维护着一份针对 RISC-V 的已知问题列表(对应 Julia 官方问题追踪器中的system:riscv标签),在动手之前可以先查阅;
  • 官方建议:如果遇到困难,在提交 issue 时务必附上cat /proc/cpuinfo的输出,以便维护者确认你的 CPU 型号与 ISA 扩展情况。

与 ARM 等架构不同,RISC-V 是开放指令集架构(ISA),同一款芯片厂商可以自由裁剪指令扩展。因此"面向 RISC-V 编译"并不像 x86 那样有一个相对统一的指令基线,构建前必须明确告诉编译器目标 ISA 字符串(rv64gc等)与可选的 CPU 型号(sifive-u74等),这是整个 RISC-V 构建流程的第一原则。

原生编译:通过Make.user指定架构与 CPU

Julia 的构建系统通过根目录下的 Make.inc 定义了大量可配置变量,并约定用户可以将自定义项写入Make.user(该文件不会被 git 跟踪)。在 RISC-V 上编译 Julia,核心是设置以下两个变量:

变量作用是否必填取值来源
MARCH指定 RISC-V ISA 字符串(即指令集架构),决定允许编译器使用哪些指令扩展必填设备文档或/proc/cpuinfo;可用gcc -march=help查看编译器支持的 flags
MCPU针对具体 CPU 型号进一步优化生成代码可选gcc --target-help可查看支持的值列表;不确定时建议留空

为什么MARCH在 RISC-V 上是硬性要求

从 Make.inc 的源码可以看到构建系统的默认策略:在未显式设置任何相关变量时,x86 等架构默认使用MARCH=nativeMTUNE=native,而 AArch64 默认使用MCPU=native。但对于 RISC-V 则直接触发构建错误:

else ifneq (,$(findstring riscv64,$(ARCH))) # RISC-V doesn't have a native option $(error Building for RISC-V requires a specific MARCH to be set))

也就是说:RISC-V 没有native这一选项(因为编译器无法从运行中的处理器可靠探测出完整的 ISA 扩展集合),ARCH检测到riscv64时若未提供MARCHmake会直接报错终止。这正是文档要求"必须手动指定架构"的底层原因。

MARCH/MCPU如何传导到编译过程

Make.inc 中展示了这两个变量对编译器的传导方式:

# Set MARCH-specific flags ifneq ($(MARCH),) CC += -march=$(MARCH) CXX += -march=$(MARCH) FC += -march=$(MARCH) # On RISC-V, don't forward the MARCH ISA string to JULIA_CPU_TARGET, # as it's always incompatible with LLVM's CPU target name parser. ifeq (,$(findstring riscv64,$(ARCH))) JULIA_CPU_TARGET ?= $(MARCH) endif endif # Set MCPU-specific flags ifneq ($(MCPU),) CC += -mcpu=$(MCPU) CXX += -mcpu=$(MCPU) FC += -mcpu=$(MCPU) JULIA_CPU_TARGET ?= $(MCPU) endif

可以看到MARCHMCPU会被拼接到 C、C++ 与 Fortran 编译器(CC/CXX/FC)的调用参数上,从而影响所有 C/Fortran 依赖(如 OpenBLAS、libuv 等)以及 Julia 运行时本身的编译。同时,构建系统默认会把它们同步到 JIT 侧的系统镜像目标JULIA_CPU_TARGET——唯一的例外是 RISC-V 上的MARCH:由于 RISC-V 的 ISA 字符串(如rv64gc)与 LLVM 的 CPU target 名称解析器不兼容,代码中特意跳过了这一步(见 Make.inc)。这正是文档中"可移植构建"示例需要手动补充JULIA_CPU_TARGET的原因。

具体设备示例:StarFive VisionFive2

文档给出的示例是 StarFive VisionFive2 开发板:它搭载的 JH7110 处理器基于 SiFive U74 核心设计。对这类已知 CPU,可以同时设置 ISA 字符串与 CPU 型号以获得针对性优化:

# Make.user MARCH := rv64gc_zba_zbb MCPU := sifive-u74

其中:

  • rv64gc_zba_zbbrv64gc是 RV64 的通用组合(i整数、m乘除、a原子、f单精度浮点、d双精度浮点、c压缩指令,外加zicsr/zifencei),_zba_zbb追加了位操作(bit-manipulation)扩展,U74 核心支持这些扩展;
  • sifive-u74:告诉编译器按 SiFive U74 的微架构做指令调度与优化。

如何确认你的设备应当使用哪些扩展?两种途径:

  1. 查阅芯片/开发板官方文档中的 ISA 描述;
  2. 直接查看运行中系统的/proc/cpuinfo,其中会列出内核识别的 ISA 扩展。

可移植构建:不锁定特定 CPU

如果你希望产出的 Julia 二进制能够在更广泛的 RISC-V 设备上运行(而不是只为某一款 CPU 特化),可以采用可移植配置:

# Make.user MARCH := rv64gc # also set JULIA_CPU_TARGET to the expanded form of rv64gc # (it normally copies the value of MCPU, which we don't set) JULIA_CPU_TARGET := generic-rv64,i,m,a,f,d,zicsr,zifencei,c

这里的关键点是:

  • MARCH := rv64gc将 ISA 基线收敛到最通用的组合,任何支持 RV64GC 的芯片都能运行;
  • 由于 RISC-V 上MARCH不会自动转发为JULIA_CPU_TARGET,且这里也没有设置MCPU(按文档建议留空),因此必须手动把rv64gc展开形式写入JULIA_CPU_TARGET,告诉 LLVM JIT 生成什么样的指令。generic-rv64,i,m,a,f,d,zicsr,zifencei,crv64gc逐项展开后的 LLVM 特性列表,其中generic-rv64是 LLVM 侧的通用 64 位 RISC-V 目标,逗号后依次列出各指令扩展。

补充说明:JULIA_CPU_TARGET的默认值在 Make.inc 中定义为native,因此在 RISC-V 交叉/特化构建场景下,显式设置它是保证系统镜像(sysimage)与运行时 JIT 目标一致的必要手段。关于该变量的更通用讨论,可参见构建分发文档 doc/src/devdocs/build/distributing.md 与 Linux 构建文档 doc/src/devdocs/build/linux.md 中的 "Architecture Customization" 一节(ARM 平台的类似做法可参考 doc/src/devdocs/build/arm.md)。

交叉编译:在高速主机上为 RISC-V 构建

RISC-V 开发板(尤其是初代单板计算机)的计算能力通常有限,在板子上原生编译 Julia 可能耗时极长。官方支持在一台更快的机器上进行交叉编译,整体分三步走。

第一步:准备 RISC-V 交叉编译工具链

需要一套同时支持C、C++ 和 Fortran的 RISC-V 交叉工具链(Julia 的构建依赖大量 C/Fortran 数值库)。官方推荐的方式是获取 riscv-gnu-toolchain 源码仓库并自行构建:

sudo mkdir /opt/riscv && sudo chown $USER /opt/riscv ./configure --prefix=/opt/riscv --with-languages=c,c++,fortran make linux -j$(nproc)

要点:

  • 安装到/opt/riscv,后续所有路径均以此为基准;
  • --with-languages=c,c++,fortran必不可少,缺少 Fortran 会导致 OpenBLAS 等依赖无法交叉编译;
  • make linux目标构建的是 Linux 用户态工具链(而非裸机newlib版本),这是运行 Linux 的 RISC-V 开发板所需要的。

第二步:配置 QEMU 用户态模拟与 binfmt

交叉编译出的 RISC-V 二进制无法直接在主机上运行,而 Julia 的构建过程需要在主机上执行部分"目标架构"的程序(例如构建系统会用目标二进制做探测、生成代码等)。解决方案是安装 QEMU 用户态模拟器并启用binfmt支持,使主机内核能够自动把 RISC-V 可执行文件交给 QEMU 执行:

  • 具体安装步骤随发行版而异。以 Arch Linux 为例,需要安装qemu-user-staticqemu-user-static-binfmt两个软件包;
  • binfmt注册表会让内核按 ELF 头自动识别 RISC-V 二进制并调用对应的模拟器;
  • QEMU 执行 RISC-V 程序时,需要能够找到 RISC-V 的系统根目录(sysroot),这是通过QEMU_LD_PREFIX环境变量指定的,指向工具链安装路径下的根文件系统(/opt/riscv/sysroot)。

第三步:配置 Julia 的交叉构建变量

在 Make.inc 中,交叉编译通过XC_HOST变量启用:设置后构建系统会自动给所有工具链命令加上$(XC_HOST)-前缀(即CROSS_COMPILE机制),并用它推导目标三元组(triplet)。在之前的Make.user基础上追加:

# Make.user(追加内容) XC_HOST=riscv64-unknown-linux-gnu OS=Linux export QEMU_LD_PREFIX=/opt/riscv/sysroot
  • XC_HOST=riscv64-unknown-linux-gnu:指定交叉工具链前缀,make会调用riscv64-unknown-linux-gnu-gccriscv64-unknown-linux-gnu-g++riscv64-unknown-linux-gnu-gfortran等;
  • OS=Linux:由于是从非 Linux 或未自动识别环境交叉编译,需要显式声明目标操作系统为 Linux(XC_HOST非空时 Makefile 要求显式设置OS,参见 Make.inc 的相关错误处理逻辑);
  • export QEMU_LD_PREFIX:让 QEMU 找到 RISC-V 系统库。

启动构建时,需要确保PATH中包含交叉工具链,例如:

PATH=/opt/riscv/bin:$PATH make -j$(nproc)

补充系统库:以 zlib 为例

官方文档特别提醒:我们使用的 RISC-V sysroot 往往非常精简(barren),Julia 构建系统期望的一些系统级库在 sysroot 中可能不存在。文档给出的例子是libz——当前构建依赖于系统提供的 zlib,因此需要把 Julia 构建出的 zlib 拷贝进 sysroot:

make -C deps install-zlib cp -v usr/lib/libz.* /opt/riscv/sysroot/usr/lib cp -v usr/include/z*.h /opt/riscv/sysroot/usr/include

这里make -C deps install-zlib调用的是 Julia 依赖子系统的 zlib 构建目标(定义于 deps/zlib.mk,其中install-zlibstaged-install宏生成,另有get-zlibextract-zlibconfigure-zlibcompile-zlibclean-zlib等配套目标)。在交叉编译阶段,Julia 自身会先把 zlib 交叉编译出来并安装到本地的usr/目录,随后再将其产物复制到/opt/riscv/sysroot下,供后续链接阶段使用。

如果你的交叉构建还遇到其他"找不到系统库"的问题,可以沿用同一思路:先用make -C deps install-<库名>构建对应依赖,再把库与头文件补齐到 sysroot 中。这是 RISC-V 精简 sysroot 环境下常见的解决路径。

构建流程原理小结

把整条链路串起来看,Julia 在 RISC-V 上的构建涉及三层目标决策:

  1. ISA 与微架构层MARCH(ISA 字符串)与MCPU(CPU 型号)决定 C/C++/Fortran 侧所有代码的生成质量与兼容性,其中MARCH在 RISC-V 上是强制的;
  2. JIT 与系统镜像层JULIA_CPU_TARGET决定 LLVM JIT 为 Julia 代码生成什么指令,RISC-V 上需要手动给出rv64gc的展开形式;
  3. 交叉执行层XC_HOST驱动工具链前缀切换,QEMU_LD_PREFIX+binfmt解决目标二进制在主机上的运行问题,OS=Linux保证目标平台判定正确。

此外,构建系统对 riscv64 还有一些自动化的默认处理,例如自动设置OPENBLAS_DYNAMIC_ARCH=1BINARY=64(见 Make.inc),并在生成二进制发行包名时使用riscv64作为架构标识(Make.inc),这些无需用户干预。

常见问题与排障建议

  1. make报错 "Building for RISC-V requires a specific MARCH to be set":说明MARCH未设置。在Make.user中补上MARCH := rv64gc(或更具体的 ISA 字符串)后重试。
  2. 不知道自己的 CPU 支持哪些扩展:执行cat /proc/cpuinfo查看内核识别的 ISA;用gcc -march=help查看编译器支持的 RISC-V flag 列表;用gcc --target-help查看可用的-mcpu取值。
  3. 交叉编译时目标二进制无法执行:确认已安装 QEMU 用户态模拟与binfmt支持,并已export QEMU_LD_PREFIX=/opt/riscv/sysroot
  4. 链接时找不到系统库:按上文 zlib 的示例,通过make -C deps install-<库名>构建依赖后补齐 sysroot。
  5. 提交问题报告:遇到编译或运行问题时,在官方问题追踪器的system:riscv标签下查找是否已有相同问题,新建 issue 时请附上cat /proc/cpuinfo输出以及你使用的Make.user内容。

【免费下载链接】juliaThe Julia Programming Language项目地址: https://gitcode.com/gh_mirrors/ju/julia

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/18 19:29:34

从需求规格说明书到OA系统实现:模块拆解、工作流与权限设计

简介&#xff1a;这是一份面向OA系统设计与开发人员的需求规格说明书&#xff0c;完整覆盖办公自动化系统的总体需求、功能需求、性能要求、接口要求、测试与验收标准&#xff0c;重点细化个人办公子系统中的电子邮件、待办事宜、日程安排、个人空间、委托授权、在线帮助等模块…

作者头像 李华
网站建设 2026/9/18 19:29:28

现在实用的AI论文写作软件有哪些品牌?深度用户实话实说

每到期末、毕业答辩、课题申报阶段&#xff0c;很多学生都会面临论文写作的多重压力&#xff1a;选题毫无头绪、大纲搭建逻辑混乱、正文撰写耗时长、参考文献格式出错、查重重复率偏高、AIGC检测告警、本校论文排版标准复杂。纯人工从零开始撰写、反复修改格式和降重&#xff0…

作者头像 李华
网站建设 2026/9/18 19:28:23

先进封装2.5D与3D堆叠:TSV、混合键合与良率选型

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/18 19:27:31

uC/OS-II 事件控制块与信号量/互斥量源码精读

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/18 19:27:12

FPGA工程师学Linux:Zynq平台7寸触摸屏驱动全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华