Electron 打印原理深度解析-Day07
1. 概述
Electron 的打印功能建立在 Chromium 浏览器引擎之上,通过多进程架构将网页内容转换为可打印格式,并最终通过操作系统的打印子系统输出到物理打印机或生成 PDF 文件。理解 Electron 的打印原理,需要穿透三个层次:Electron 自身的 API 封装层、Chromium 的打印中间件层、以及操作系统原生的打印子系统层。
本文将从 webContents.print() 和 webContents.printToPDF() 的调用出发,逐层剖析数据流在 Windows、macOS 和 Linux 三大平台下的完整路径,并重点分析默认打印机配置在 silent 模式下不生效这一常见问题的技术根源。

2. Electron 打印 API 总览
Electron 在 WebContents 接口上提供了两个核心打印方法:
2.1 webContents.print([options], [callback])
该方法调用操作系统的原生打印对话框(或通过 silent: true 直接打印),将当前网页内容发送到物理打印机。关键选项包括:
silent: 是否跳过系统打印对话框直接打印deviceName: 指定目标打印机名称pageSize: 自定义页面尺寸(微米单位)printBackground: 是否打印 CSS 背景margins: 页边距配置color: 是否彩色打印dpi: 分辨率设置
2.2 webContents.printToPDF(options)
该方法使用 Chromium 内置的打印预览机制将网页渲染为 PDF 数据流,不经过操作系统打印子系统。返回一个 Promise<Buffer>,包含生成的 PDF 二进制数据。默认配置为:
{
marginsType: 0, // 默认边距
printBackground: false, // 不打印背景
printSelectionOnly: false,
landscape: false, // 纵向
pageSize: 'A4', // 默认 A4
scaleFactor: 100
}
关键区别:
print()走的是系统打印路径(依赖 OS 打印子系统),而printToPDF()走的是Chromium 内部 PDF 生成路径(Blink → Skia/PDFium → Buffer)。
3. 从 Electron 调用到操作系统处理的完整链路
3.1 JavaScript API 层
当开发者在主进程中调用:
win.webContents.print({ silent: true, deviceName: 'My-Printer' })
该调用首先进入 Electron 的 TypeScript/JavaScript 封装层。WebContents 的实现在 lib/browser/api/web-contents.ts 中定义了 JavaScript 接口,随后通过 Node.js 的绑定机制将调用转发到 C++ 层。
3.2 Electron C++ 绑定层
打印功能的 C++ 实现位于 shell/browser/api/electron_api_web_contents.cc 中。该层负责:
- 解析 JavaScript 传递的 options 对象,转换为 Chromium 的
base::Value::Dict格式 - 构建打印设置字典(
printing::PrintSettings),包括纸张大小、方向、边距等 - 调用 Chromium 的打印基础设施(
printing::PrintViewManager或printing::PrintBackendService)
源码路径示意:
JS (lib/browser/api/web-contents.ts) ↓ Node.js binding C++ (shell/browser/api/electron_api_web_contents.cc) ↓ Chromium IPC Chromium Print Layer (components/printing/)
在 electron_api_web_contents.cc 中,关键代码逻辑大致如下:
// 伪代码,示意 Electron 如何处理打印选项
if (options.Get("mediaSize", &media_size)) {
settings.Set(printing::kSettingMediaSize, std::move(media_size));
} else {
// 注意:此处存在硬编码默认值的逻辑
settings.Set(printing::kSettingMediaSize,
base::Value::Dict()
.Set(printing::kSettingMediaSizeHeightMicrons, 297000)
.Set(printing::kSettingMediaSizeWidthMicrons, 210000));
}
3.3 Chromium 打印架构
Chromium 的打印系统采用多进程架构,核心组件分布在不同进程中:
进程分工
| 进程 | 职责 |
|---|---|
| Renderer Process | 执行 Blink 渲染引擎,生成页面的可视化表示,处理 @media print CSS 规则 |
| Browser Process | 管理打印对话框、与操作系统打印 API 交互、调度打印作业 |
| Utility Process | (可选)执行耗时的打印后端查询操作,避免阻塞主线程 |
打印流程
- 内容准备阶段:Renderer Process 中的 Blink 引擎根据
@media print规则重新计算样式和布局,生成打印专用的布局树 - 渲染阶段:Blink 的 Paint 阶段将布局树转换为绘制指令(Display List),然后通过 Skia 图形库栅格化为位图或矢量数据
- 序列化阶段:
- 对于
printToPDF():Chromium 使用内置的 PDF 生成器(基于 PDFium/Skia)直接输出 PDF 数据流 - 对于
print():Chromium 将渲染结果转换为操作系统可接受的中间格式(如 Windows 的 EMF/XPS、macOS/Linux 的 PDF),通过 IPC 发送到 Browser Process
- 对于
- 系统提交阶段:Browser Process 调用操作系统原生打印 API 提交打印作业
3.4 Blink 渲染与打印输出
Blink 处理打印任务时,会执行一个简化的渲染管线:
HTML + CSS → DOM Tree → Style Resolution → Render Tree → Layout (Print)
→ Paint → Skia Recording → Platform Print Output
| 英文原文 | 中文翻译 | 说明 |
|---|---|---|
| HTML + CSS | HTML + CSS | 输入的原始文档和样式 |
| DOM Tree | DOM 树 | 解析 HTML 后生成的文档对象模型 |
| Style Resolution | 样式解析 | 计算每个节点的最终 CSS 样式 |
| Render Tree | 渲染树 | 合并 DOM 和样式后生成的可视化树 |
| Layout (Print) | 布局(打印) | 针对打印介质计算元素的几何位置 |
| Paint | 绘制 | 将渲染树转换为绘制指令 |
| Skia Recording | Skia 录制 | 通过 Skia 图形库记录绘制操作 |
| Platform Print Output | 平台打印输出 | 最终生成平台相关的打印数据(如 PDF、PostScript) |
关键特性:
- Blink 在打印模式下会忽略
overflow: hidden等屏幕显示优化规则 @pageCSS 规则可以覆盖 JavaScript 中传递的landscape参数page-break-before: always;可用于强制分页
4. 各操作系统打印子系统详解
当 Chromium 的 Browser Process 将打印作业提交到操作系统后,三大平台的处理路径出现显著分化。
4.1 Windows 打印架构
Windows 的打印子系统是一个一级操作系统子系统,由打印后台处理程序(Print Spooler)和一组可替换的打印机驱动程序组成。
核心组件
| 组件 | 说明 |
|---|---|
spoolsv.exe |
打印后台处理服务,运行在所有打印路径的中心 |
localspl.dll |
本地打印提供程序,包含 EMF 打印处理器 |
Winspool.drv |
客户端打印 API DLL |
Spoolss.dll |
后台处理程序路由器 |
两条主要打印路径
Windows 自 Vista 起支持两条并行的打印路径:
GDI 和 XPS 都是 Windows 下的图形/打印技术,但属于不同时代的方案:
GDI(Graphics Device Interface):Windows 最传统的 2D 图形 API,从 Windows 1.0 时代就存在,主要用于画图、显示窗口、打印文档。
特点:
- 基于设备上下文(DC)和位图/矢量指令
- 打印时,应用程序通过 GDI 把内容画到打印机的设备上下文上
- 驱动程序再把 GDI 指令转成打印机能懂的PCL/PostScript/位图
缺点:依赖打印机驱动,不同驱动渲染效果可能不一致;高 DPI 下容易模糊
XPS(XML Paper Specification):微软推出的基于 XML 的固定文档格式,类似 PDF,主要用于:作为打印管道中的中间文档格式,实现"所见即所得"的精确打印
特点:
- 打印时,应用先把内容生成 XPS 文件(本质是打包的 XML + 资源)
- XPS 驱动直接把这份固定格式发给打印机,不经过驱动二次解释
- 和 PDF 类似,保证不同设备上显示/打印效果完全一致
优点:免驱动渲染、矢量保真、支持透明/渐变等高级效果
GDI XPS 本质 图形绘制 API 固定文档格式(类似 PDF) 年代 1985 年至今 2006 年推出(Vista 时代) 打印路径 App → GDI → 打印机驱动 → 打印机 App → XPS 文档 → XPS 驱动 → 打印机 是否依赖驱动渲染 ✅ 是,驱动解释 GDI 指令 ❌ 否,文档格式即最终呈现 跨设备一致性 差(不同驱动效果不同) 好(固定格式,所见即所得) 现代支持 仍广泛支持,但逐渐老化 Windows 仍支持,但推广不及 PDF GDI 是 Windows 老式的"画图+打印"接口;XPS 是微软试图用来替代 GDI 打印路径的、类似 PDF 的精确文档格式。
GDI 打印路径(经典路径):
Win32/GDI 应用
→ GDI (CreateDC → DrvEnableDriver → DrvEnablePDEV)
→ EMF 后台处理文件(Enhanced Metafile)
→ spoolsv.exe(后台处理程序)
→ EMF 打印处理器(localspl.dll)回放 EMF
→ GDI + 打印机图形 DLL 渲染
→ 设备数据流(EngWritePrinter / WritePrinter)
→ 端口监视器(TCPMON / WSDMON)
→ 端口驱动程序
→ 打印机设备
XPS 打印路径(现代路径):
WPF 应用 或 XPS Print API
→ XPS 后台处理文件(OPC/ZIP + XAML)
→ spoolsv.exe
→ XPSDrv 筛选器管道(XPSDrv Render Module / v4 Render)
→ 设备 PDL 或光栅
→ 端口
→ 打印机设备
跨路径转换
Windows 提供了两个转换模块,确保任意应用可以打印到任意驱动程序:
- MXDC(Microsoft XPS Document Converter):将 GDI 输出转换为 XPS,用于 GDI 应用 → XPS 打印机
- XGC(XPS-to-GDI Conversion):将 XPS 转换为 EMF,用于 XPS 应用 → GDI 打印机
GDI EMF 本质 Windows 的 2D 图形 API(函数调用) GDI 绘图指令的序列化文件格式 关系 调用 LineTo()、TextOut()等函数画图把这些函数调用逐条记录下来,存成 .emf文件类比 画家现场作画 把作画过程录成视频,以后可以回放
驱动模型演进
| 驱动模型 | 打印路径 | 核心格式 | 中间环节 |
|---|---|---|---|
| v3 (GDI-based) | App → GDI → 驱动图形DLL → 打印机 | GDI/EMF | 驱动负责全部渲染转换 |
| v4 | App → XPS → 驱动 → 打印机 | XPS | 系统提供通用渲染,驱动只做轻量转换 |
| IPP 收件箱 + PSA | App → XPS/IPP → 网络协议 → 打印机 | XPS / PDF / PWG Raster | 经常无需本地驱动 |
驱动模型越新,打印路径越"短":v3 是应用画给驱动看、驱动再翻译;v4 是应用生成标准文档给驱动封包;IPP 是应用直接通过网络把标准文档发给打印机自己处理。
IPP 全称 Internet Printing Protocol(互联网打印协议),是一种基于 HTTP 的网络打印标准。
Electron 在 Windows 上的打印路径
当 Electron 在 Windows 上调用 webContents.print() 时:
- Chromium 的 Browser Process 通过
Winspool.drv调用 Windows 打印 API - 如果目标打印机使用 GDI 驱动,Chromium 通常生成 EMF 格式的后台处理数据
- 后台处理程序将 EMF 数据路由到对应打印队列
- EMF 打印处理器回放绘图指令,调用打印机驱动程序的图形 DLL 进行渲染
- 渲染后的设备特定数据通过端口监视器发送到打印机
4.2 macOS 打印架构
macOS 的打印架构采用分层设计,上层为应用框架,底层为 CUPS。
CUPS 全称 Common UNIX Printing System(通用 Unix 打印系统),是 Linux/macOS 上负责管理打印的后台服务。
命令 作用 lpstat -a查看所有打印机是否接受任务 lpstat -p查看打印机状态(空闲/禁用/拒绝) lpstat -d查看系统默认打印机 lpstat -o查看当前打印队列中的任务 lpstat -s汇总显示所有打印机及默认目标 lpstat -l显示详细信息 lpinfo -v查看系统可用的打印机连接方式(USB/网络等) lpinfo -m查看可用的驱动/PPD 列表
分层结构
应用层(AppKit / NSView / NSDocument)
→ Core Printing(C API,如 PMCreateSession, PMSessionBeginDocument)
→ CUPS(cupsd 守护进程)
→ 筛选器链
→ 后端(usb, ipp, socket)
→ 打印机设备
关键技术特性
- Quartz 2D / Core Graphics:macOS 的绘图基础使用基于 PDF 的成像模型。当应用打印时,内容首先被描述为 PDF 数据,这与 CUPS 的原生格式高度兼容
- CUPS 集成:自 OS X 10.2 起,macOS 使用 CUPS 作为打印后端,
cupsd守护进程监听 IPP 端口 631 - 筛选器链:CUPS 根据
mime.convs和 PPD 文件计算从作业 MIME 类型到打印机格式的最低成本转换链。典型路径为:PDF → pdftopdf → pdftoraster → CUPS Raster → 设备筛选器 → 打印机 - AirPrint:macOS 原生支持 AirPrint(基于 IPP Everywhere),可实现无驱动打印
Electron 在 macOS 上的打印路径
- Chromium 的 Browser Process 调用 macOS 的 Core Printing API
- 系统通过 Quartz 将渲染内容转换为 PDF 表示
- CUPS 接收 PDF 作业,排队存储在
/var/spool/cups/ - CUPS 调度器根据打印机配置选择合适的筛选器链
- 筛选器将 PDF 转换为打印机原生语言(PostScript、PCL、ZPL 等)
- CUPS 后端通过 USB/网络将数据发送到打印机
4.3 Linux 打印架构
Linux 的打印子系统以 CUPS 为核心,架构与 macOS 底层类似,但更加开放和可定制。
核心组件
| 组件 | 说明 |
|---|---|
cupsd |
CUPS 调度守护进程,监听 IPP 端口 631 |
/etc/cups/printers.conf |
打印机配置文件 |
/var/spool/cups/ |
后台处理文件存储位置 |
cups-filters |
OpenPrinting 提供的筛选器和后端集合 |
Ghostscript / Poppler / MuPDF |
PDF/PostScript 渲染引擎 |
打印数据流
应用(Electron/Chromium)
→ CUPS 客户端库(libcups)
→ cupsd(通过 IPP 协议提交作业)
→ 作业入队(控制 c-file + 数据 d-file)
→ 筛选器链(根据 MIME 类型转换)
例如:application/pdf → pdftopdf → pdftoraster → CUPS Raster → 设备筛选器
→ 可选端口监视器
→ 后端(usb, ipp, socket, lpd)
→ 打印机设备(固件 RIP 处理 PDL)
CUPS 2.x vs 3.x 架构变迁
| 特性 | CUPS 2.x | CUPS 3.x(新架构) |
|---|---|---|
| 驱动模型 | 支持 PPD 文件和经典驱动 | 移除 PPD,仅支持驱动程序应用(Printer Applications) |
| 标准格式 | PDF 作为标准作业格式 | 全 IPP,仅支持无驱动打印 |
| 筛选器 | cups-filters 2.x | 内置 IPP 处理 |
| 兼容性 | 支持传统打印机 | 仅支持 IPP Everywhere / AirPrint / Mopria 认证打印机 |
Electron 在 Linux 上的打印路径
- Chromium 的 Browser Process 通过 CUPS 客户端库提交打印作业
- 作业以 PDF 格式进入 CUPS 队列
- CUPS 根据打印机配置(PPD 或 printer application)确定筛选器链
- 筛选器将 PDF 转换为打印机支持的格式(如 PCL、PostScript、ESC/POS 等)
- 后端模块通过 USB 或网络将数据发送到打印机
5. 跨平台差异对比
| 维度 | Windows | macOS | Linux |
|---|---|---|---|
| 打印后台处理 | Print Spooler (spoolsv.exe) |
CUPS (cupsd) |
CUPS (cupsd) |
| 后台处理文件位置 | %SystemRoot%\System32\spool\PRINTERS |
/var/spool/cups/ |
/var/spool/cups/ |
| 核心图形 API | GDI / XPS / Direct2D | Quartz 2D (Core Graphics) | Cairo / Skia(Chromium 内部) |
| 标准作业格式 | EMF(GDI 路径)/ XPS(XPS 路径) | PDF(Quartz 原生) | PDF(CUPS 标准) |
| 驱动模型 | v3 (GDI) / v4 / IPP Class Driver | CUPS 筛选器 + PPD / AirPrint | CUPS 筛选器 + PPD / Printer Applications |
| 无驱动打印 | IPP Everywhere / Mopria(Win 10/11) | AirPrint / IPP Everywhere(原生) | IPP Everywhere / Mopria |
| 颜色管理 | Windows Color System + ICC | ColorSync + ICC | CUPS color management + ICC |
| 打印对话框 | 系统原生对话框 | 系统原生对话框 | GTK/Qt 对话框或 CUPS 对话框 |
| Chromium 交互层 | Winspool.drv API | Core Printing API | CUPS API (libcups) |
| 热敏/票据打印机支持 | 依赖驱动配置 | 依赖 CUPS 配置 | 依赖 CUPS 配置(最常见场景) |
关键差异分析
-
后台处理格式差异:
- Windows GDI 路径使用 EMF(增强型图元文件),这是一种记录 GDI 绘图指令的封闭格式,需要回放和二次渲染
- macOS 和 Linux 使用 PDF 作为中间格式,与 Chromium 的输出格式天然兼容,减少了格式转换损耗
-
渲染位置差异:
- Windows GDI 路径中,渲染可能发生在主机端(通过打印机图形 DLL)或设备端(固件 RIP)
- macOS/Linux 的 CUPS 路径中,渲染通常通过 Ghostscript/Poppler 在主机端完成,生成 CUPS Raster 后发送到设备
-
驱动配置方式差异:
- Windows 打印机配置存储在注册表和驱动特定的 DEVMODE 结构中
- macOS/Linux 的 CUPS 配置存储在
/etc/cups/printers.conf和 PPD 文件中
6. 默认打印机配置与 silent 模式行为分析
6.1 问题现象
在使用 webContents.print({ silent: true }) 时,开发者经常遇到以下问题:
现象 1:纸张大小不匹配
- 在 Windows 上将默认打印机设置为 Letter 尺寸,但 silent 打印输出 A4
- 在 Linux 上配置 CUPS 使用 80mm 热敏纸,但 silent 打印输出 A4 裁剪版
现象 2:方向设置被忽略
- 在打印机首选项中设置为横向(Landscape),但 silent 打印输出纵向(Portrait)
现象 3:自定义页边距/分辨率失效
- 打印机驱动中配置的自定义页边距或 DPI 在 silent 模式下不生效
6.2 根本原因
原因一:Electron 硬编码默认纸张大小
Electron 的 webContents.print() 在 silent: true 且未显式指定 pageSize 时,会硬编码 A4(210mm × 297mm)作为默认纸张大小,而不是查询打印机驱动程序的配置:
// electron_api_web_contents.cc 中的逻辑(简化)
if (options.Get("mediaSize", &media_size)) {
settings.Set(printing::kSettingMediaSize, std::move(media_size));
} else {
// 硬编码 A4 - 与 Chromium 原生行为不一致
settings.Set(printing::kSettingMediaSize,
base::Value::Dict()
.Set(printing::kSettingMediaSizeHeightMicrons, 297000)
.Set(printing::kSettingMediaSizeWidthMicrons, 210000)
...);
}
这与 Chromium 的 window.print() 行为形成对比——后者会查询打印机驱动程序获取原生默认纸张大小。
原因二:silent 模式跳过系统打印对话框
当 silent: true 时,Electron 直接构建打印设置字典并提交作业,跳过了操作系统打印对话框。而系统打印对话框通常会:
- 读取打印机驱动的默认 DEVMODE(Windows)或 PPD 配置(CUPS)
- 将驱动配置与应用程序请求合并
- 提供用户确认的机会
跳过对话框意味着 Electron 必须自行承担"读取驱动默认配置"的责任,但当前实现中这部分逻辑缺失。
原因三:跨平台配置存储差异
- Windows:打印机默认配置存储在注册表和驱动的 DEVMODE 结构中,Electron 未实现跨驱动的 DEVMODE 查询
- macOS/Linux:CUPS 配置存储在
printers.conf和 PPD 中,但 Electron 的 silent 路径未通过 CUPS API 读取这些配置
原因四:Chromium 打印设置与系统设置的隔离
Chromium 的打印系统设计上将"内容渲染设置"(纸张大小、边距、方向)与"设备配置"(驱动设置)分离。在标准 Chrome 中,用户通过打印预览 UI 手动调整设置,这些调整会覆盖驱动默认值。Electron 的 silent 模式移除了用户调整环节,但未能自动填充驱动默认值。
6.3 解决方案与最佳实践
方案一:显式指定所有打印参数
最可靠的方案是在调用 print() 时显式传递所有关键参数,不依赖系统默认值:
const options = {
silent: true,
deviceName: 'My-Thermal-Printer',
pageSize: {
width: 80000, // 80mm in microns
height: 297000 // 或根据内容动态计算
},
margins: {
marginType: 'none' // 或自定义边距
},
landscape: false,
dpi: { horizontal: 203, vertical: 203 },
printBackground: true
};
win.webContents.print(options, (success, failureReason) => {
if (!success) console.log(failureReason);
});
方案二:使用 printToPDF + 系统打印命令
对于需要精确控制输出格式的场景,可以先生成 PDF,再通过系统命令打印:
// 1. 生成 PDF
const pdfData = await win.webContents.printToPDF({
pageSize: 'A4',
printBackground: true
});
fs.writeFileSync('/tmp/output.pdf', pdfData);
// 2. 使用系统命令打印(Linux/macOS)
const { exec } = require('child_process');
exec('lp -d My-Printer -o media=Custom.80x200mm /tmp/output.pdf');
// Windows 可使用 SumatraPDF 等命令行工具
// exec('SumatraPDF.exe -print-to "My-Printer" -silent output.pdf');
方案三:使用 silent: false 让用户确认
如果业务场景允许,使用非静默模式可以让用户通过系统打印对话框确认设置:
win.webContents.print({ silent: false }, (success, failureReason) => {
// 用户可以在系统对话框中调整设置
});
方案四:查询系统默认配置后传入
在 Electron 28+ 版本中,可以使用 webContents.getPrintersAsync() 获取打印机列表及其默认配置,然后手动构建打印参数:
const printers = await win.webContents.getPrintersAsync();
const defaultPrinter = printers.find(p => p.isDefault);
// 根据打印机名称推断纸张大小,或维护一个配置映射表
const printerConfig = loadPrinterConfig(defaultPrinter.name);
win.webContents.print({
silent: true,
deviceName: defaultPrinter.name,
pageSize: printerConfig.pageSize,
landscape: printerConfig.landscape
});
方案五:使用 usePrinterDefaultPageSize(Electron 28+)
Electron 28 及以上版本引入了 usePrinterDefaultPageSize 选项。当设置为 true 时,Electron 会尝试使用打印机驱动的默认页面尺寸:
win.webContents.print({
silent: true,
usePrinterDefaultPageSize: true, // 尝试使用驱动默认纸张
deviceName: 'My-Printer'
});
注意:该选项的行为依赖于 Chromium 底层实现,在某些驱动程序上可能仍不生效。
7. 总结
Electron 的打印功能是一个跨平台封装层,其本质是将 Chromium 的网页渲染能力与操作系统的打印子系统桥接起来。理解其原理的关键在于把握三个层次:
- Electron API 层:提供 JavaScript 接口,负责参数解析和格式转换,但存在硬编码默认值的问题
- Chromium 中间件层:处理多进程渲染、打印预览、PDF 生成,将网页内容转换为平台无关的打印描述
- 操作系统子系统层:
- Windows:GDI/XPS 双路径 + Print Spooler + 驱动模型(v3/v4/IPP)
- macOS:AppKit → Core Printing → CUPS,基于 PDF 的成像模型
- Linux:CUPS 为核心,筛选器链处理格式转换,后端负责设备通信
关于默认打印机配置是否一定会按配置执行:
答案是否定的。在 silent: true 模式下,Electron 的 webContents.print() 不会自动读取打印机驱动的默认配置,而是使用内部硬编码的默认值(主要是 A4 纸张大小)。这会导致:
- 热敏/票据打印机输出格式错误
- 区域设置(Letter vs A4)被忽略
- 驱动中的方向、边距、分辨率设置失效
根本原因在于:Electron 在简化打印流程时,移除了 Chromium 原生的"查询驱动默认设置"逻辑,同时跳过了系统打印对话框(该对话框通常负责合并应用请求与驱动默认配置)。
最佳实践是:在调用 print() 时显式传递所有关键参数(pageSize、landscape、margins、dpi 等),或采用 printToPDF() + 系统命令的间接打印方案,以确保输出结果的可预测性。
参考资源
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐


所有评论(0)