编译原理 H 实验环境配置
本课程推荐的实验环境有三种:
Windows 10 Anniversary Edition (Build 1607) or higher
如果使用 Windows,你需要安装 Windows Subsystem for Linux (WSL)。图形化相关的工作会在 Native Windows 下完成,但代码生成推荐在 WSL 中进行,这是为了便于依赖安装。
Linux
Mac with Homebrew installed
Linux 和 Mac 都是不错的 POSIX 环境,也都各自有好用的包管理器、便利的图形化环境。
如果你原本安装 Windows 7/8 并且不想升级 Windows 10,那么在虚拟机(如 VirtualBox)中安装一个 Linux 发行版(如 Ubuntu)将会是一个不错的选择。
1. 基本的编译执行环境
为了编译实验代码,你需要安装以下软件:
- CMake 3.5 或更高版本
- 任何支持 C++ 14 的编译器,如 g++,clang
- 任意 Java VM,推荐使用 OpenJDK 8 或 Oracle JRE 1.8/8
- pkg-config
- uuid-dev
1.1. 依赖软件的安装
在 Linux 的发行版上安装这些软件会十分简单,例如, 在 Ubuntu 下,运行如下命令即可:
sudo apt install cmake g++ openjdk-8-jre pkg-config uuid-dev
而在 Windows 下,推荐通过 WSL 配置实验的编译执行环境。安装的方式和 Ubuntu 类似,但考虑到 WSL 并不需要图形部分的安装,建议将上述命令中的openjdk-8-jre更换为openjdk-8-jre-headless。
在 Mac 下,你需要使用 clang 作为编译器(随 XCode 安装),单独安装 JVM,然后从 Homebrew 安装其余包:
brew install cmake pkg-config ossp-uuid
对于 Mac,部分同学可能遇到安装报错的问题。这一问题暂时没有找到出现原因(助教不是 Mac 用户),如果实在解决不了的话推荐虚拟机 Linux 解决问题。
1.2. CMake 的使用
CMake 根据内置的规则和语法来自动生成相关的makefile 文件进行编译,同时还支持静态库和动态库的构建等。
通过 CMake 管理的项目主目录下会有一个 CMakeLists.txt ,其中会包括工程包含哪些子目录等内容;而在每个子目录下,也会包含一个 CMakeLists.txt,用来管理该子目录中相关内容的构建。
编译
编译的时候,可以建立单独的文件夹(如build),让编译产生的文件和源代码区分出来,以下是一种常用的编译方式, 当前目录为项目源代码目录:
$ mkdir build
$ cd build
$ cmake ..
$ make
编写CMakeLists.txt
在 CMakeLists.txt 中,可以包含如下一些内容:
cmake_minimum_required(VERSION 3.1) # CMake 版本要求
PROJECT(hello) # 项目名称
set(CMAKE_CXX_STANDARD 14) # 设置编译器遵循的C++标准
set(CMAKE_CXX_FLAGS “-O2 -g”) # 自定义编译选项
假设 args 代表通过空格或换行分隔的多个参数,你可以
- 通过
include_directories(args)来添加外部库的头文件所在的一组目录args作为头文件查找目录; - 通过
link_directories(args)来添加外部链接库的查找目录; - 通过
link_libraries(args)来添加链接的外部库; - 通过
target_link_libraries(hello args)来设置生成的可执行目标及其要链接的库 - 通过
add_library(mylib STATIC ${SRC})来创建静态库libmylib.a; 如果STATIC换成SHARED,则为创建动态库libmylib.so; - 通过
add_executable(hello ${SRC})来创建可执行文件hello
你可以使用内置宏 CMAKE_CURRENT_SOURCE_DIR 来获取当前CMakeLists.txt 所在目录,例如 ${CMAKE_CURRENT_SOURCE_DIR}/..表示
CMakeLists.txt 所在目录的上一级目录。
2. ANTLR
ANTLR (ANother Tool for Language Recognition)是一个强大的解析器的生成器。在课程实验中,你将利用 ANTLR 工具读入描述要解析的语言词法和语法的文法文件(扩展名是 .g4), 生成解析器的源码。
ANTLR v4 使用 Java 实现,但是生成的解析器源码可以是 Java、C++、C#、Go、JavaScript、Swift等。
2.1. 依赖环境准备
ANTLR 工具需要 JVM 才能执行;另一方面,为了方便使用 grun,你需要一个能够编译 java 源文件的环境。因此,你需要一个完整的 Java Development Kit。
如果你使用 Windows:
由于
grun工具需要图形化显示,因此在 Windows 下不推荐在 WSL 中执行,WSL 中配置桌面环境会有些 tricky。你需要在 Windows 中安装 Java Development Kit(推荐使用 Oracle Java SE 8),并确认你的 PowerShell 的可用性(Anniversary Edition 以上的版本应当已经自带,右键开始菜单就可以看到)。
安装后,你需要设置好环境变量,将
{Your JDK installation}\bin加入环境变量PATH中。如果你使用 Linux:
推荐通过包管理器安装 OpenJDK 8。在你的包管理器中通过搜索确定包名,如 Ubuntu 下包名为
openjdk-8-jdk, 安装之即可。如果你使用 Mac:
类似 Windows,你需要手动安装一个 JDK,并配置好环境变量。
2.2. 获取 antlr
你需要从 ANTLR Download 下载 antlr-4.7-complete.jar。
然后,你需要将该jar包的路径加入到环境变量 CLASSPATH 中,即 Bash 中执行
export CLASSPATH=".:/path/to/your/antlr-4.7-complete.jar:$CLASSPATH"
或 PowerShell 中的
$env:CLASSPATH=".;/path/to/your/antlr-4.7-complete.jar;$CLASSPATH"
你可以考虑将这一命令加入.bashrc(对于Bash)或profile.ps1(对于PowerShell),以省去你每次配置的麻烦。
2.3. antlr4 和 grun 工具
可以定义别名 antlr4 表示 ANTLR 工具,即
alias antlr4='java org.antlr.v4.Tool'
这样,你可以直接使用 antlr4 your.g4 来为your.g4 生成解析器源码。
ANTLR 的运行时库中还提供了一个灵活的测试工具 TestRig,它可以显示解析器如何匹配输入的许多相关信息。TestRig使用Java的反射机制来调用编译过的解析器。为了方便用户使用,ANTLR 提供了一个 grun 工具来使用 TestRig。
grun 本质上是一个别名,可以定义如下:
alias grun='java org.antlr.v4.runtime.misc.TestRig'
或
alias grun='java org.antlr.v4.gui.TestRig'
如果你工作在 PowerShell 下,你应该使用Set-Alias命令。
同样的,这些别名命令也可以加入.bashrc或profile.ps1中来为你节省时间。
3. LLVM 配置
由于 Ubuntu 源中 LLVM 的打包错误、以及此后对 Clang 和 LLVM 的实验需要,这里推荐同学们自行编译 LLVM。
3.1. 获取 LLVM
这里将在当前目录下建立一个名为llvm的目录,其中包含了 LLVM 和 Clang。
wget http://releases.llvm.org/4.0.1/llvm-4.0.1.src.tar.xz
wget http://releases.llvm.org/4.0.1/cfe-4.0.1.src.tar.xz
tar xvf llvm-4.0.1.src.tar.xz
mv llvm-4.0.1-src llvm
tar xvf cfe-4.0.1.src.tar.xz
mv cfe-4.0.1.src llvm/tools/clang
3.2. 编译并安装
这里将在当前目录下建立一个名为llvm-build的目录(和llvm同级),用于构建 LLVM 和 Clang,并将安装目录配置为和这两个目录同级的llvm-install目录。
mkdir llvm-build && cd llvm-build
cmake ../llvm -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=`cd .. && pwd`/llvm-install
make -j install
在 WSL 下使用make -j,会有小概率在长时间执行后导致系统卡死,推荐考虑使用make -jn,其中将n替换为你的 CPU 逻辑处理器数目减一。例如,在 Core i7 6700HQ 上,使用make -j7。
编译时间较长,基本占满你的 CPU,这段时间里你可能需要玩一会儿手机或者去冲一杯咖啡,当然去吃个饭也不错。
请注意,为了避免你的内存爆炸,这里使用了 Release 配置。这一配置下,链接时无需处理调试符号,内存占用大幅度降低。考虑到同学们不会有 Debug 进入 LLVM 中的需求,Release 配置已经足够使用。