鸿蒙造物者之路 03 · 铸剑
续写章节|沿用「造物者」系列的武侠讲解体,面向电子信息 / 嵌入式方向的新手
=================前情提要===============
老陈给我划了三条底线:4 核 CPU、8 G 内存、100 G 磁盘,外加一句"南向编译必须 Linux"。
他还说今晚是动手之夜——装系统、拉源码、编第一个固件,目标是让那颗蓝灯按我的意志闪烁。
后来我才知道,那一晚我根本没摸到灯。我摸到的是一整晚的报错。
========================================
这一章你会得到什么
🎯 学完这一章,你应该能:
- ☐ 搭好 Ubuntu 编译环境(虚拟机方案,最安全)
- ☐ 拿到 OpenHarmony 源码,编出第一个固件
- ☐ 把固件烧进开发板,并能通过串口看到日志
- ☐ 记住七个高频坑的解法(这一章的「翻车急救手册」最值钱)
**🧰 需要准备:**100 GB 硬盘(建议 150)、4 核 CPU、8 GB 内存、Hi3861 开发板、能传数据的 USB 线。
**⏱ 预计用时:**4–8 小时。这一章耗时最长,别急。
📊 难度:★★★★★ 劝退墙,几乎每个人都会卡
一、先把话说清楚:两套工具,别搞混
"动手之前,先认清楚你要装的是哪一套东西。"老陈在白板上画了个分叉:
┌──────────────────────────────┐
│ 鸿蒙开发 │
└───────────────┬───────────────┘
┌────────────┴────────────┐
▼ ▼
┌───────────────────┐ ┌───────────────────┐
│ 南向 · 设备开发 │ │ 北向 · 应用开发 │
├───────────────────┤ ├───────────────────┤
│ 系统:Ubuntu │ │ 系统:Win / Mac │
│ IDE:DevEco Device │ │ IDE:DevEco Studio │
│ Tool(VSCode)│ │ │
│ 语言:C / C++ │ │ 语言:ArkTS │
│ 产出:固件 .bin │ │ 产出:应用 .hap │
└───────────────────┘ └───────────────────┘
"名字只差一个词,干的完全不是一件事。"老陈特意把两个名字圈出来:
- DevEco Device Tool —— 南向用的,是 VS Code 的一个插件,跑在 Ubuntu / Windows 上,用来编译烧录调试固件
- DevEco Studio —— 北向用的,是 IntelliJ IDEA 改的独立 IDE,用来写 ArkTS 应用
"我见过太多新手装错了。"老陈说,“想点灯结果装了 Studio,装完一脸懵:我的 GPIO 在哪儿?”
“那我两个都要装?”
"都要,但不用同一天装。"老陈说,“今晚先把南向这条线打通。北向的 DevEco Studio 等你第 06 章再说。”
二、Ubuntu:第一道坎
2.1 怎么装
“三种方案,你自己选。”
| 方案 | 优点 | 缺点 | 适合谁 |
|---|---|---|---|
| 物理机双系统 | 性能满血,编译最快 | 装崩了影响 Windows,切换要重启 | 有闲置电脑 / 胆子大的 |
| 虚拟机(VirtualBox / VMware) | 安全,崩了删了重来 | 编译慢,IO 是瓶颈 | 新手首选 |
| WSL2 | 跟 Windows 无缝,方便 | 串口 / USB 支持麻烦,烧录要折腾 | 有经验的人 |
“我选虚拟机。”
"明智。"老陈点头,“第一次搞,别拿双系统赌。等哪天你确定要长期做南向了,再考虑上物理机。”
他给了我几条硬性要求:
虚拟机配置(底线,不是推荐值)
─────────────────────────────
CPU : 4 核(给满,别省)
内存 : 8 GB 起(编译峰值会吃满)
磁盘 : 100 GB 起(建议 150 GB,动态分配也行)
网络 : 必须能访问外网
系统 : Ubuntu 20.04 或 22.04 LTS
“为什么非要 LTS?”
"因为 OpenHarmony 的编译脚本对系统版本敏感。"老陈说,“非 LTS 版本的 glibc、Python 版本可能太新,编译脚本没适配,报错报到你怀疑人生。20.04 和 22.04 是社区验证过最多的两个。”
2.2 装完之后第一件事:换源
“系统装好,第一件事不是装鸿蒙,是换软件源。”
# 备份原来的源
sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak
# 换成国内镜像(以清华源为例,也可以换阿里/中科大)
sudo sed -i 's|http://.*archive.ubuntu.com|https://mirrors.tuna.tsinghua.edu.cn|g' /etc/apt/sources.list
sudo sed -i 's|http://.*security.ubuntu.com|https://mirrors.tuna.tsinghua.edu.cn|g' /etc/apt/sources.list
# 更新
sudo apt update && sudo apt upgrade -y
“不换会怎样?”
"不换的话,下载速度几十 KB,你能等到天亮。"老陈说,“这是最容易被忽略、但最浪费时间的一步。”
2.3 装依赖
"然后装这一堆。"老陈甩给我一条命令:
sudo apt install -y \
git git-lfs curl wget vim \
build-essential gcc g++ make cmake \
ninja-build gn python3 python3-pip python3-venv \
libssl-dev zlib1g-dev libffi-dev \
unzip zip dosfstools mtools \
default-jre device-tree-compiler \
libncurses5-dev
"python3 版本必须是 3.8 以上。"他强调,“检查一下:”
python3 --version
# 输出应该是 Python 3.8.x / 3.9.x / 3.10.x
“如果系统默认是 python3 但 python 命令不存在呢?”
"加个软链接,或者永远用 python3。"老陈说,“OpenHarmony 的脚本大多写的是 python3,所以问题不大。但有些老脚本会调 python,保险起见:”
sudo ln -sf /usr/bin/python3 /usr/bin/python
⚠️ 注意:Ubuntu 20.04 之后官方不建议把
python指向python3(可能干扰系统包管理)。如果你只在虚拟机里玩,无所谓;如果是双系统,建议用python3显式调用。
2.4 pip 也换源
pip3 config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
三、拿源码:三种姿势
"源码怎么拿?"我问。
“三种,推荐第二种。”
姿势一:repo 拉全量(最正规,最慢)
# 1. 装 repo 工具
mkdir -p ~/bin
curl https://gitee.com/oschina/repo/raw/fork_flow/repo-py3 -o ~/bin/repo
chmod +x ~/bin/repo
echo 'export PATH=~/bin:$PATH' >> ~/.bashrc
source ~/.bashrc
# 2. 初始化(以 master 分支为例,实际请选 LTS 版本分支)
mkdir -p ~/openharmony && cd ~/openharmony
repo init -u https://gitee.com/openharmony/manifest.git -b master --no-repo-verify
# 3. 同步(这一步很慢,几小时起步)
repo sync -c
repo forall -c 'git lfs pull'
# 4. 下载预编译工具链
bash build/prebuilts_download.sh
"repo sync 这一步,国内网络可能要四五个小时。"老陈说,“而且中途断一次就得重来。你要是网络不好,直接用第二种。”
姿势二:下发行版压缩包(新手推荐)
“去 OpenHarmony 官网的发布版本页,直接下对应版本的源码压缩包(一般在几 GB 到十几 GB)。下完解压即可,比 repo 快得多,也稳得多。”
# 假设下载的是 code-vX.x.x.tar.gz
tar -zxvf code-vX.x.x.tar.gz -C ~/openharmony
cd ~/openharmony
bash build/prebuilts_download.sh # 还是要下载预编译工具链
“下载页面在哪儿?”
"gitee 的 openharmony 仓库 Release 页,或者 OpenHarmony 官网下载中心。"老陈说,“记得选 LTS 版本,别追 master。”
“为什么别追 master?”
"因为 master 是开发分支,天天在变,今天能编过明天可能就挂了。"老陈说,“LTS 是长期支持版,社区验证充分,配套的文档、教程、开发板支持都齐全。新手追新版本 = 给自己找罪受。”
姿势三:只拉某个芯片的样例(最快尝鲜)
“如果你只是想先看看长什么样,可以去 Gitee 找设备厂商提供的快速上手仓库,比如润和、小熊派这些厂商会打包好一套能直接编译的最小环境。这个最快,但学到的东西最少。”
四、编译:hb 是个什么玩意儿
"源码到手,开始编译。"老陈敲了敲键盘。
4.1 认识构建系统
“OpenHarmony 用的构建系统,是 GN + Ninja。”
┌──────────────────────────────────────────┐
│ hb(OpenHarmony 的构建命令行工具) │ ← 你敲的是它
├──────────────────────────────────────────┤
│ GN(Generate Ninja) │ ← 生成构建描述文件
├──────────────────────────────────────────┤
│ Ninja │ ← 真正执行编译
├──────────────────────────────────────────┤
│ LLVM / GCC 工具链 │ ← 编译器
└──────────────────────────────────────────┘
“GN 是干嘛的?”
"GN 是一种’构建描述语言’。"老陈说,“你在每个目录里写的 BUILD.gn 文件,就是用 GN 语法描述:这个目录下有哪些源文件、要编成什么(可执行程序 / 静态库 / 动态库)、依赖谁。GN 读完全部 BUILD.gn,生成 build.ninja,然后 Ninja 按它执行编译。”
“听起来像 makefile?”
"就是 makefile 的现代替代品。"老陈说,“比 make 快得多,尤其是增量编译。”
他给我看了一个最简的 BUILD.gn:
# applications/sample/wifi-iot/app/my_led/BUILD.gn
static_library("my_led") { # 目标:一个静态库,名叫 my_led
sources = [ # 源文件列表
"my_led.c",
]
include_dirs = [ # 头文件搜索路径
"//utils/native/lite/include",
"//base/iot_hardware/peripheral/interfaces/kits",
]
deps = [ # 依赖别的模块
"//base/iot_hardware/peripheral:hal_iothardware",
]
}
“看懂了吗?”
“……大概。就是告诉编译器:编这个 .c,头文件去哪儿找,依赖谁。”
"够了。"老陈说,“GN 你不用精通,会照猫画虎改 BUILD.gn 就行。”
4.2 装 hb
# 在源码根目录执行
pip3 install --user build/lite # 老版本路径
# 或者
pip3 install --user ohos-build # 新版本可直接从 PyPI 装
# 加进 PATH(pip 装完会提示你加到 ~/.bashrc)
echo 'export PATH=~/.local/bin:$PATH' >> ~/.bashrc
source ~/.bashrc
# 验证
hb --version
⚠️ 常见坑 1:装完
hb提示command not found。
原因:~/.local/bin没进 PATH。
解法:手动加export PATH=~/.local/bin:$PATH,然后source ~/.bashrc。
4.3 三步编译
"编译就三步。"老陈伸出三根手指。
# 第一步:设置产品(选择要编译哪一款设备)
hb set
# 会弹出一个列表,用方向键选,比如 Hi3861 对应的产品
# 选完会在根目录生成 ohos_config.json
(示意:hb set 的输出)
Ohos Product List:
1. hispark_pegasus@wifiiot_hispark_pegasus ← Hi3861 选这个
2. hispark_taurus@ipcamera_hispark_taurus ← Hi3516
3. rk3568@hihope_rk3568 ← RK3568
Which would you like? [1]:
# 第二步:编译(-f 表示强制全量编译,第一次必须加)
hb build -f
# 第三步(可选):后续增量编译,去掉 -f
hb build
“-f 是什么?”
"force,全量重编。"老陈说,“第一次编译必须加,因为它要生成所有中间产物。后面你改了代码,直接 hb build 就行,它只会重编变动的部分——这就是 Ninja 的价值,全量要半小时,增量可能只要几秒。”
4.4 编译成功的样子
“成功的标志是最后几行长这样:”
[OHOS INFO] ...
[OHOS INFO] c targets overlap rate statistics
[OHOS INFO] ...
[OHOS INFO] wifiiot_hispark_pegasus build success
[OHOS INFO] cost time: 0:12:34
“看见 build success 就是成了。”
“产物在哪儿?”
ls out/hispark_pegasus/wifiiot_hispark_pegasus/
"找这个文件——"老陈指了指:
Hi3861_wifiiot_app_allinone.bin
“**这就是要烧进板子的固件。**名字里的 allinone 意思是’全部打包在一起’——内核、系统服务、你的应用,全在这一个 bin 里。”
“多大?”
"几百 KB 到一两 MB。"老陈说,“你对比一下安卓的系统镜像——几百 MB。这就是轻量系统的分量。”
五、烧录:把固件灌进板子
5.1 连线和串口
“烧录之前,先搞清楚两件事:串口和烧录模式。”
Hi3861 开发板
┌──────────────────────┐
│ [MicroUSB] ← 供电 + 串口 + 烧录 三合一
│ [RST] 按键
│ [KEY] 按键(烧录时要用)
│ [蓝色 LED]
└──────────────────────┘
“一根 USB 线搞定供电、串口通信和烧录。”
“虚拟机怎么用 USB?”
"这是虚拟机的经典坑。"老陈说,“你插上 USB 线,虚拟机默认是看不见的,得手动把设备’透传’进去。”
VMware: 虚拟机 → 可移动设备 → 找到你的 USB-Serial 设备 → 连接
VirtualBox: 设备 → USB → 勾选对应的 USB 设备
⚠️ 常见坑 2:虚拟机里
ls /dev/ttyUSB*什么都没有。
解法 1:确认 USB 设备已透传给虚拟机。
解法 2:Windows 主机上先确认能识别(设备管理器看端口),如果 Windows 占用了,虚拟机就拿不到。
解法 3:最省事的办法——烧录这一步直接在 Windows 上做,用 HiBurn 工具,串口调试再回 Ubuntu。
(我最后就是这么干的,省了两小时的折腾。)
5.2 用 HiBurn 烧录(Windows)
“HiBurn 是海思的串口烧录工具,Windows 下的,图形界面,傻瓜式。”
步骤:
1. 打开 HiBurn,选择串口号(COMx)
2. 波特率选 921600(默认最高档,烧得快)
3. 点 "Select file",选中 Hi3861_wifiiot_app_allinone.bin
4. 勾选 "Auto burn"
5. 点 "Connect"
6. 【关键】按下板子上的 RST 按键,让板子重启进入烧录模式
7. 进度条开始走,等它跑完
8. 显示 "Execution Successful" 即成功
“第六步是关键。“老陈强调,”**烧录不是插上线就能烧,你得让芯片进入 bootloader 的下载模式。**不同板子进入方式不同,Hi3861 是按 RST 重启后,bootloader 会短暂等待下载命令。”
“如果一直连不上呢?”
"按这个顺序排查——"老陈掏出一张纸:
| 症状 | 可能原因 | 解法 |
|---|---|---|
| 串口号都选不到 | 驱动没装 | 装 CH340 / CP210x USB 转串口驱动 |
| 连上了但一直等待 | 没进烧录模式 | 按 RST 键;或先按住 KEY 再按 RST |
| 波特率太高,传一半失败 | 线材差 / 干扰 | 降到 115200 再试(慢但稳) |
| 烧完了但板子没反应 | 没勾选 Auto burn / 文件选错 | 检查 bin 文件路径和选项 |
| 提示文件大于 Flash | 编错产品了 | 确认 hb set 选的是 Hi3861 对应产品 |
5.3 串口看日志
“烧完,板子会自动重启。这时候打开串口工具,能看到启动日志——这是你以后调试的唯一眼睛。”
Ubuntu 下:
# 装 minicom
sudo apt install -y minicom
# 查看串口设备
ls /dev/ttyUSB*
# 打开(波特率 115200)
sudo minicom -D /dev/ttyUSB0 -b 115200
# 退出:Ctrl+A 然后按 X,选 Yes
⚠️ 常见坑 3:
minicom打不开,提示Permission denied。
原因:当前用户不在dialout组。
解法:sudo usermod -aG dialout $USER # 然后注销重新登录(或者重启)
“启动日志长什么样?”
“你会看到一堆初始化信息刷屏,最后是类似这样的:”
...
[OHOS] LiteOS kernel init done
[OHOS] System service init ...
[OHOS] Wifi init success
[OHOS] app init ...
Hello, OpenHarmony! ← 你的应用打印的
“看到你自己的日志,就说明系统跑起来了。”
六、翻车急救手册(这一节最值钱)
那一晚上我踩了七个坑。老陈说这些坑他见过几百个新手踩,让我原样记下来。
坑 1:磁盘爆满,编译到一半挂掉
症状:编译到 80% 报错,提示 "No space left on device"
原因:out 目录 + 源码 + prebuilts,100 G 只够勉强
解法:
· 清理:hb clean 或删掉 out 目录重来
· 扩容:虚拟机磁盘扩容(先关虚拟机,在设置里扩,再进系统用 gparted 扩分区)
· 预防:一开始就给 150 G,别卡着底线给
坑 2:hb 报 Python 版本错
症状:SyntaxError / 各种 import 报错
原因:Python 版本过低(3.7 以下)或过高(3.12+ 部分脚本未适配)
解法:用 3.8 ~ 3.10,最稳
坑 3:prebuilts_download 卡住或失败
症状:下载工具链时超时 / 校验失败
原因:网络问题
解法:
· 重试(这个脚本支持断点)
· 手动下载对应工具链放到 prebuilts 目录
· 换个时间段(晚上速度通常好一点)
坑 4:找不到头文件 / 链接失败
症状:fatal error: xxx.h: No such file or directory
原因:BUILD.gn 里的 include_dirs 或 deps 写漏了
解法:
· 确认头文件实际路径(用 find 命令找)
· 路径要用 "//" 开头表示源码根目录
· 依赖的模块名去它自己的 BUILD.gn 里核对
坑 5:改了代码但编出来的固件没变化
症状:改了 .c 文件,重新烧录,行为没变
原因:忘了重新编译 / 编译的是别的产品 / 烧了旧的 bin
解法:
· hb build(不带 -f 也应该能检测变化)
· 实在不行:hb build -f 全量重编
· 确认 ohos_config.json 里的产品是你要的那个
· 确认烧录的 bin 路径是最新的(看文件时间)
坑 6:串口输出乱码
症状:minicom 里一堆乱码
原因:波特率不对
解法:确认是 115200(Hi3861 默认),8N1(8 数据位,无校验,1 停止位)
坑 7:虚拟机里编译极慢
症状:编译几小时不动
原因:CPU 核数给少了 / 磁盘 IO 差 / 内存不够导致 swap
解法:
· CPU 给到 4 核以上
· 内存 8G 起,别让系统用 swap
· 虚拟机磁盘放在 SSD 上,别放机械盘
· 用 hb build 的 -j 参数限制并发(内存不够时反而更快)
"最后一个建议——"老陈放下笔,“每一次成功,都把环境备份一份。”
“怎么备份?”
"虚拟机快照。"他说,“在你第一次 build success 的时候,立刻拍个快照。以后不管你怎么作死,一键回滚。这是你整个学习过程里,性价比最高的五分钟。”
七、北向预告:DevEco Studio
"南向的编译烧录你今晚过了一遍。"老陈看了眼时间,“最后十分钟,我给你看看另一半长什么样。”
他打开 Windows 上另一台机器,双击了一个图标。
“**DevEco Studio,北向应用开发的 IDE。**基于 IntelliJ IDEA 改的,你要是用过 Android Studio,界面会非常眼熟。”
他新建了一个项目,我看到了这样的目录结构:
MyApplication/
├── AppScope/ ← 应用全局配置
│ ├── app.json5 ← 应用级别配置(包名、版本、图标)
│ └── resources/
├── entry/ ← 默认模块(一个应用可以有多个模块)
│ ├── src/main/
│ │ ├── ets/ ← 【ArkTS 代码都在这儿】
│ │ │ ├── entryability/
│ │ │ │ └── EntryAbility.ets ← 应用入口
│ │ │ └── pages/
│ │ │ └── Index.ets ← 页面
│ │ ├── resources/ ← 资源(字符串、图片、布局)
│ │ └── module.json5 ← 模块配置(Ability 声明、权限)
│ ├── build-profile.json5
│ └── oh-package.json5 ← 依赖管理(类似 package.json)
└── build-profile.json5
“几个关键文件记住:”
| 文件 | 作用 | 类比安卓 |
|---|---|---|
app.json5 |
应用级配置(Bundle 名、版本、图标) | AndroidManifest.xml 的应用部分 |
module.json5 |
模块级配置(Ability、权限、设备类型) | AndroidManifest.xml 的 Activity 部分 |
oh-package.json5 |
三方依赖管理 | build.gradle 的依赖 |
EntryAbility.ets |
应用入口 Ability | MainActivity |
pages/Index.ets |
页面 UI | activity_main.xml + Activity |
"注意 json5 不是 json。"老陈提醒,“json5 允许注释、允许尾逗号,写起来舒服点。”
他点了一个按钮,右侧弹出了一个实时预览窗口,屏幕上显示着一个"Hello World"。
"这个叫预览器(Previewer),你写代码的时候它实时刷新,不用编译不用部署。"老陈说,“对新手极其友好——这一点比 Android Studio 做得好。”
“能直接在电脑上看效果?”
“能。还能开模拟器,跑一个完整的鸿蒙系统。”
我看着那个小小的预览窗口,忽然有点期待。
"好了,今天就到这儿。"老陈关掉 IDE,“今晚回去把环境装好,把源码拉下来,编一次,烧一次。哪怕只跑起来一个 Hello World,你也已经超过 80% 只看不练的人了。”
“那灯呢?”
老陈笑了。
“灯是下一章的事。”
=================小剧场模式=================
我:老师,我统计了一下,今晚我一共踩了七个坑。
老陈:七个算少的。 我第一次搭这套环境,踩了十几个,折腾了三天。
我:你是老手啊,也会踩?
老陈:环境搭建这件事,跟水平关系不大,跟运气关系大。 每个人机器不一样、网络不一样、系统版本不一样,踩的坑都不一样。
我:那新手遇到坑怎么办?
老陈:三步。第一,完整读一遍报错信息——90% 的报错里已经写了原因,只是你没看。
我:第二呢?
老陈:把报错原文复制去搜。 别自己造句子描述问题,就复制原文。你踩的坑,全网踩过的人成千上万。
我:第三?
老陈:看不懂就先跳过,别死磕。 有些坑是因为后面的步骤没做才出现的,继续往下走反而自己就消失了。
我:(记笔记)
老陈:还有最重要的一条——
我:什么?
老陈:第一次 build success 之后,立刻拍虚拟机快照。
========================================
八、本章速查卡
老陈临走前,在白板上留了这张表,让我贴在显示器边上:
| 我要干什么 | 命令 / 工具 |
|---|---|
| 选产品 | hb set |
| 全量编译 | hb build -f |
| 增量编译 | hb build |
| 清理产物 | hb clean |
| 下载工具链 | bash build/prebuilts_download.sh |
| 找固件 | out/<board>/<product>/Hi3861_wifiiot_app_allinone.bin |
| 烧录(Win) | HiBurn,波特率 921600,按 RST 进下载模式 |
| 看日志(Ubuntu) | sudo minicom -D /dev/ttyUSB0 -b 115200 |
| 串口没权限 | sudo usermod -aG dialout $USER 后重登录 |
| 北向 IDE | DevEco Studio(写 ArkTS) |
| 南向 IDE | DevEco Device Tool(VSCode 插件,编固件) |
| 构建系统 | GN(描述) + Ninja(执行),hb 是入口 |
"最后一句。"老陈在门口转身。
“今晚不管编出来什么,烧进去,看串口日志,确认它真的在跑。”
“为什么强调这个?”
“因为在嵌入式这行,'编译通过’和’真的能跑’之间,隔着一整个世界。”
本章自检
过一遍下面的问题。答不上来的,回去翻对应小节——那些就是你这个章的欠账。
- ☐
hb set和hb build分别做什么? - ☐ 编译产物在哪个目录?文件名是什么?
- ☐ 烧录时为什么要按 RST?连不上该查什么?
- ☐ 串口日志打不出来,按什么顺序排查?
- ☐ 最重要:第一次编译成功后,你拍虚拟机快照了吗?
**➡️ 下一站:**第 04 章 · 点灯 —— 终于可以让硬件动起来了。
=================剧情片段=================
导演:卡。这一章是不是有点"工具说明书"的味道?
助理:确实,命令多、故事少。
导演:这一章本来就该是工具书。 观众是照着它一步步操作的,这时候花活没意义,准确和齐全才重要。
助理:但会不会劝退?
导演:会。 这就是现实——环境搭建就是劝退率最高的地方。我们能做的,是把坑提前告诉他,让他少摔几次。
助理:下一章应该轻松多了吧?
导演:下一章才是真正的开始。
助理:《点灯》。
导演:对。GPIO、HDF 驱动框架、hcs 配置、驱动模型——从"让一个引脚变高"到"让一个操作系统去管理一个引脚"。
助理:听起来还是点灯啊。
导演:是点灯。但这次点灯,他要写的是一个驱动。 前者是操作寄存器,后者是给系统写一个"能被人调用的能力"。
助理:懂了。同一个动作,两种境界。
导演:这就是南向开发的入门礼。
========================================
未完待续。。。


