运行代码
本节阅读量:这一节只解决一个很实际的问题:
|
|
下面的示例默认你已经打开 Linux、macOS 或 WSL 的终端,并且当前目录是本课程仓库的根目录,也就是能看到 code/ 和 doc/ 的位置。
进入代码目录
每章代码都放在:
|
|
例如第一章代码是:
|
|
所以先进入第一章代码目录:
|
|
这里的 cd 是 change directory,意思是切换当前目录。后面的命令都会在这个目录里执行。
如果终端提示找不到这个目录,先检查自己是不是站在仓库根目录。命令里的相对路径,都是从“当前目录”开始寻找的。
构建 mini
进入章节代码目录后,运行:
|
|
它会读取当前目录下的 Makefile,把这一章的 C++ 代码编译成一个小程序:
|
|
mini 就是这一章的命令行工具。每章都有自己的 mini,所以读哪一章,就先进入哪一章的代码目录再运行 make。
如果想清理生成出来的文件,可以运行:
|
|
然后再重新构建:
|
|
平时修改代码后直接再运行 make 就可以,不需要每次先 make clean。本章最后一节会单独解释 make 怎样判断是否需要重新构建。
运行 mini
构建成功后,当前目录会出现:
|
|
运行解释器:
|
|
这里的意思是:
|
|
开头的 ./ 表示“当前目录里的”。Unix 风格 shell 通常不会自动到当前目录寻找程序,所以这里不能只写 mini。
查看 AST:
|
|
查看 IR:
|
|
生成汇编:
|
|
这里的 -o out.s 表示:
|
|
汇编怎么执行
out.s 还不是可以直接运行的程序。它只是汇编文本。
在 Linux、WSL 或常见 x86-64 环境里,完整流程是:
|
|
其中:
|
|
如果 examples/add.lang 的内容是:
|
|
最后应该看到:
|
|
注意,运行 ./out 时不会显示任何内容。这里的 42 是随后执行的 echo $? 打印出来的退出码,不是 ./out 主动打印的结果。
退出码通常只能可靠地观察 0 到 255 之间的小整数。例如语言里的结果是 300 或 -1 时,echo $? 看到的数字会不同。第一章会专门留一道练习观察这个现象。
先分清四个程序
这一串命令里出现了几个容易混在一起的名字:
| 名字 | 谁提供 | 在这里做什么 |
|---|---|---|
make |
开发工具 | 根据 Makefile 构建课程代码 |
mini |
本课程 | 解释小语言,或把它编译成汇编 |
cc |
系统工具链 | 把汇编组装、链接成可执行文件 |
out |
cc 的输出 |
真正运行编译后的小语言程序 |
因此,完整关系是:
|
|
这条最短流程适用于目前正在使用的第一章快照。第九章加入垃圾回收以后,collector 会成为单独的 C++ runtime object;届时每章的 make 还会生成 gc_runtime.o,链接命令变成:
|
|
out.s 负责生成程序和 root 协议,gc_runtime.o 提供分配器与 collector。教程到第九章时会完整解释这条新边界;现在只需知道,mini compile 在任何章节都不替你链接。
macOS 上的差异
macOS 上,程序入口名字通常是 _main,Linux 上通常是 main。mini compile 会按当前系统自动选择。也可以手动指定目标:
|
|
如果你在 Apple Silicon Mac 上,cc 默认可能按 arm64 汇编。但本课程生成的是 x86-64 汇编,所以链接时可以写:
|
|
如果系统没有 x86-64 工具链或 Rosetta,这一步可能会失败。可以先换到 x86-64 Linux、Intel Mac,或者装好对应工具后再继续。
常见问题
如果看到:
|
|
说明当前命令行环境里没有 make。
如果看到:
|
|
说明当前环境里没有 C++ 编译器,或者编译器不在 PATH 里。
如果构建成功,但运行 cc out.s -o out 时看到:
|
|
说明当前环境缺少负责组装和链接汇编的 C 编译器驱动。
这些问题都不是课程代码本身的错误,而是命令行环境还没有准备好。继续之前,请确认当前环境能找到 make、c++ 和 cc;Linux、macOS 或装好开发工具的 WSL 都可以完成后面的步骤。
到这里,只要能在 code/01_numbers 中完成 make、mini run、mini compile 和 cc 这四步,运行环境就准备好了。暂时看不懂 AST、IR 和汇编输出没有关系,后面的正文会逐层把它们拆开。