为了第一个测试项目,创建一个简单的Clang工具,该工具运行编译器,并检查提供的源文件的语法。先创建一个所谓的树外LLVM项目,即一个将使用LLVM但位于主LLVM源树外的项目。 创建项目需要执行以下几项操作: 必须构建和安装所需的LLVM库和头文件 需要为测试项目创建一个构建配置文件 使用LLVM的源代码必须创建 从第一步开始,安装Clang支持库和头文件。使用以下CMake配置命令: cmake -G Ninja -DCMAKEBUILDTYPE=Debug -DCMAKEINSTALLPREFIX=..
为了第一个测试项目,创建一个简单的Clang工具,该工具运行编译器,并检查提供的源文件的语法。先创建一个所谓的树外LLVM项目,即一个将使用LLVM但位于主LLVM源树外的项目。
创建项目需要执行以下几项操作:
必须构建和安装所需的LLVM库和头文件
需要为测试项目创建一个构建配置文件
使用LLVM的源代码必须创建
从第一步开始,安装Clang支持库和头文件。使用以下CMake配置命令:
cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug
-DCMAKE_INSTALL_PREFIX=../install -DLLVM_TARGETS_TO_BUILD="X86"
-DLLVM_ENABLE_PROJECTS="clang" -DLLVM_USE_LINKER=gold
-DLLVM_USE_SPLIT_DWARF=ON -DBUILD_SHARED_LIBS=ON ../llvm
图 1.12: LLVM CMake配置,用于简单的语法检查Clang工具
这里只启用了一个项目:clang。所有其他选项都是我们调试构建的标准配置。该命令必须从LLVM源树中创建的构建文件夹中运行。
重要提示 图1.12中指定的配置将在整本书中作为默认构建配置使用。
使用动态库的配置,除了减少大小外,还有简化依赖项指定的优点。只需要指定项目直接依赖的动态库,动态链接器将处理其余部分。
所需的库和头文件可以通过以下命令安装:
库和头文件将安装到通过CMAKE_INSTALL_PREFIX选项指定的文件夹中。
再为项目创建两个文件:
CMakeLists.txt: 项目配置文件
TestProject.cpp: 项目源代码
项目配置文件,CMakeLists.txt,将通过LLVM_HOME环境变量接受LLVM安装文件夹的路径。该文件如下所示:
图 1.13: 用于简单语法检查Clang工具的CMake文件
第2行:指定了项目名称(syntax-check)。这也是可执行文件的名称。
第4-7行:测试LLVM_HOME环境变量。
第10行:设置了LLVM CMake帮助器的路径。
第11行:从第10行指定的路径加载LLVM CMake包。
第14行:指定了编译的源文件。
第16行:设置了相应的编译标志:-fno-rtti。当LLVM没有构建RTTI时,为了减少代码和可执行文件大小
1,这个标志是必需的。
第18-22行:指定要链接到我们程序的必需库
工具源码如下:
#include "clang/Frontend/FrontendActions.h" // clang::SyntaxOnlyAction
#include "clang/Tooling/CommonOptionsParser.h" #include
"clang/Tooling/Tooling.h" #include "llvm/Support/CommandLine.h" //
llvm:🆑:extrahelp
namespace llvm:🆑:OptionCategory TestCategory("Test project");
llvm:🆑:extrahelp
CommonHelp(clang::tooling::CommonOptionsParser::HelpMessage); //
namespace
int main(int argc, const char **argv)
llvm::Expected<clang::tooling::CommonOptionsParser> OptionsParser =
clang::tooling::CommonOptionsParser::create(argc, argv, TestCategory);
if (!OptionsParser) llvm::errs() << OptionsParser.takeError(); return
1; clang::tooling::ClangTool Tool(OptionsParser->getCompilations(),
OptionsParser->getSourcePathList());
return Tool.run(
clang::tooling::newFrontendActionFactory<clang::SyntaxOnlyAction>()
.get());
图 1.14: SyntaxCheck.cpp
第7-9行:大多数编译器工具都有一套相同的命令行参数。LLVM命令行库 2
提供了一些API来处理编译器命令选项。第7行设置了该库,在第8-10行设置了相应的帮助信息。
第13-18行:解析命令行参数。
第19-24行:创建并运行Clang工具。
第22-23行:使用clang::SyntaxOnlyAction前端动作,将在输入文件上运行语法和语义检查。
必须指定LLVM安装文件夹的路径来构建工具。如之前所述,路径必须通过LLVM_HOME环境变量指定。配置命令(见图1.12)将路径指定为LLVM项目源树中的安装文件夹,所以可以按照以下方式构建工具:
export LLVM_HOME=<...>/llvm-project/install mkdir build cd build cmake
-G Ninja .. ninja
图 1.15: syntax-check构建命令
可以按照以下方式运行工具:
`cd build` ./syntax-check –help USAGE: syntax-check [options]
<source0> [... <sourceN>] ...
图 1.16: syntax-check –help 的输出
如果在一个C++源文件上运行程序,它将直接退出;但在一个有语法错误的C++文件上运行,会产生错误消息:
$`./syntax-check mainbroken.cpp -- -std=c++17
mainbroken.cpp:2:11: error: expected ';' after return statement
return 0
^
;
1 error generated.
Error while processing mainbroken.cpp.
\end{shell}
\begin{center}
图 1.17: 在语法错误文件上运行syntax-check
\end{center}
图1.17中使用'-{}-'将附加参数传递给编译器,具体指定C++17,选项'-std=c++17'。
还可以使用LLDB调试器运行工具:
\begin{shell}`$ <...>/llvm-project/install/bin/lldb ./syntax-check –
main.cpp – -std=c++17
图 1.18: 调试器下运行syntax-check
以syntax-check为主程序,将main.cpp源文件作为工具的参数(图1.18)。还可以向syntax-check可执行文件传递编译标志(-std=c++17)。
可以设置断点,并按照以下方式运行程序:
图 1.19: LLDB的交互演示,用于Clang工具测试项目
在clang::ParseAST函数中设置了一个断点(图1.19,第1行)。该函数是源代码解析的主要入口点。第3行运行程序,并在第16行继续执行断点后的程序。
本书的后续章节中,将使用相同的调试技术来研究Clang的源码。
LLVM社区. LLVM编码标准. 2023. URL
https://llvm.org/docs/CodingStandards.html ↩
LLVM社区. CommandLine 2.0库手册. 2023. URL
https://llvm.org/docs/CommandLine.html ↩