编译原理 H 实验环境配置
本课程推荐的实验环境有两种:
- Linux
- Mac with Homebrew installed
Linux 和 Mac 都是不错的 POSIX 环境,也都各自有好用的包管理器、便利的图形化环境。
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-jdk pkg-config uuid-dev
在 Mac 下,你需要使用 clang 作为编译器(随 XCode 安装),单独安装 JVM,然后从 Homebrew 安装其余包:
brew install cmake pkg-config ossp-uuid antlr4-cpp-runtime
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。
如果你使用 Linux:
推荐通过包管理器安装 OpenJDK 8。在你的包管理器中通过搜索确定包名,如 Ubuntu 下包名为
openjdk-8-jdk
, 安装之即可。如果你使用 Mac:
你需要手动安装一个 JDK。
2.2. 获取 ANTLR
你需要从 ANTLR Download 下载 antlr-4.7.1-complete.jar
。
然后,你需要将该jar包的路径加入到环境变量 CLASSPATH
中,即 Bash 中执行
export CLASSPATH=".:/path/to/your/antlr-4.7.1-complete.jar:$CLASSPATH"
你可以考虑将这一命令加入.bashrc
(对于Bash),以省去你每次配置的麻烦。
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'
同样的,你可以将这些别名命令加入到.bashrc
,以节省你配置和使用的时间。
3. LLVM 配置
由于 Ubuntu 源中 LLVM 的打包错误、以及此后对 Clang 和 LLVM 的实验需要,这里推荐同学们自行编译 LLVM。
3.1. 获取 LLVM
这里将在当前目录下建立一个名为llvm
的目录,其中包含了 LLVM 和 Clang。
wget http://releases.llvm.org/6.0.1/llvm-6.0.1.src.tar.xz
wget http://releases.llvm.org/6.0.1/cfe-6.0.1.src.tar.xz
tar xvf llvm-6.0.1.src.tar.xz
mv llvm-6.0.1-src llvm
tar xvf cfe-6.0.1.src.tar.xz
mv cfe-6.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
推荐考虑使用make -jn
,其中将n
替换为你的 CPU 逻辑处理器数目减一。例如,在 i5-7287U 上,使用make -j3
,编译时间可能不到一个小时。而如果使用单线程,那么编译时间可能超过两个小时。这段时间里你可能需要玩一会儿手机或者去冲一杯咖啡,当然复习一下编译的知识、看一下 LALR 是个不错的选择。
请注意,为了避免你的内存爆炸,这里使用了 Release 配置。这一配置下,链接时无需处理调试符号,内存占用大幅度降低。考虑到同学们不会有 Debug 进入 LLVM 中的需求,Release 配置已经足够使用。
但是,我们强烈建议你使用 Debug 配置进行编译。一方面是让你体验一下比较大的工程的编译过程,另一方面在这个过程里面会有一点点奇怪又好玩的问题出现,强烈安利!前两年课程的llvm编译,用的不是新版的llvm 6,所以编译的时候大家都遇到了一些很多好玩的问题,得到了刺激的体验!内存占用峰值也超过了12GB。所以真的强烈安利!内存不大的同学也可以尝试一下,看看会有什么有趣的问题,理解一下编译过程、链接过程的各种优化的必要性!