使用LLVM中的命令行参数处理接口
LLVM中提供了一组便捷好用的命令行参数处理接口,本文针对不同的场景介绍如何使用它们。
头文件llvm/Support/CommandLine.h
声明了这些接口,这些接口在命名空间llvm
的cl
里面。因此,使用它们时,代码像下面这个样子。
#include "llvm/Support/CommandLine.h"
using namespace llvm;
int main(int argc, char **argv) {
cl::ParseCommandLineOptions(argc, argv);
}
上面的代码中已经使用了接口cl::ParseCommandLineOptions(argc, argv)
,它的作用是读取并解析用户通过命令行传入的参数,检测其是否符合代码指定的参数规范,并将传入的参数赋值给代码定义的变量。上面的代码还没有定义一些参数,你需要像声明全局变量那样声明参数。下面通过模仿Linux中的ls
命令来分享如何使用这些接口。
实现 ls /home
我们可以通过使用ls /home
来列出/home
目录下所有的文件和文件夹。你可以这样使用cl
里的接口来模拟这种单个字符串参数:
#include "llvm/Support/CommandLine.h"
using namespace llvm;
cl::opt<std::string> DirName(cl::Positional, cl::desc("<dir>"));
int main(int argc, char **argv) {
cl::ParseCommandLineOptions(argc, argv);
errs() << DirName.c_str() << "\n";
}
其中DirName是一个string型参数,可以被转换为string,你也可以指定为其它类型。在声明该参数时,cl::Positional
表明该参数是一个位置型参数,cl::desc
和为程序的--help
选项提供信息。假设生成的程序为main
,则交互情况如下:
-> ./main /home
/home
-> ./main --help
USAGE: main [options] <dir>
......
在声明DirName
时里面的像cl::Positional
这样的参数之间是没有顺序要求的。对于上述程序,如果不指定一个参数,会生成字符串型的默认构造函数的生成值。你也可以在声明时通过cl::init("you set a value")
来指定一个默认值,或者通过cl::Required
强制用户输入参数。
实现 ls /home /etc
上面的代码只能接受一个位置型字符串,ls
是可以接受多个文件夹作为参数的。这时,就要用cl::list<>
代替cl::opt
了。
#include "llvm/Support/CommandLine.h"
using namespace llvm;
cl::list<std::string> DirName(cl::Positional, cl::desc("<dirs>"), cl::OneOrMore);
int main(int argc, char **argv) {
cl::ParseCommandLineOptions(argc, argv);
for (auto S : DirName) {
errs() << S << "\n";
}
}
我们通过cl::list<std::string>
指定了一个接受多个字符串的参数。其中cl::OneMore
强制用户输入至少一个参数。在main
函数中,可以像使用vector<std::string>
一样使用DirName
。
实现 ls -a
用户还可以通过ls -a
来显示隐藏的文件与文件夹。我们额外声明一个bool型的a
参数,代码如下:
#include "llvm/Support/CommandLine.h"
using namespace llvm;
cl::opt<bool> Hidden("a", cl::desc("Show hidden entries"), cl::init(false));
cl::list<std::string> DirName(cl::Positional, cl::desc("<dirs>"), cl::OneOrMore);
int main(int argc, char **argv) {
cl::ParseCommandLineOptions(argc, argv);
errs() << "Show hidden: " << Hidden << "\n";
for (auto string : DirName) {
errs() << string << "\n";
}
}
用户可以通过-a=false
、-a=FALSE
、-a=0
来将变量Hidden
设置为false,或者通过-a
,-a=1
,-a=true
,-a=TRUE
来将其设置为true。
实现 ls –hide=XX
通过ls --hide=<PATTERN>
还可以设置不显示的文件与文件夹。于是我们再用cl::opt<std::string>
定义一个这样的参数hide
,如下:
#include "llvm/Support/CommandLine.h"
using namespace llvm;
cl::opt<bool> Hidden("a", cl::desc("Show hidden entries"), cl::init(false));
cl::opt<std::string> Filter("hide", cl::desc("Filter some pattern"), cl::Required);
cl::list<std::string> DirName(cl::Positional, cl::desc("<dirs>"), cl::OneOrMore);
int main(int argc, char **argv) {
cl::ParseCommandLineOptions(argc, argv);
errs() << "Filter output: " << Filter << "\n";
errs() << "Show hidden: " << Hidden << "\n";
for (auto string : DirName) {
errs() << string << "\n";
}
}
与命令行交互如下:
-> ./main -a -hide=*hide* /home /opt
Filter output: *hide*
Show hidden: 1
/home
/opt
-> ./main --help
USAGE: main [options] <dirs>
......
General options:
-a - Show hidden entries
--hide=<string> - Filter some pattern
除了上面介绍的,LLVM还包含很多灵活的接口,详见文档https://llvm.org/docs/CommandLine.html#quick-start-guide。