我正在使用 clang 工具从现有代码库自动生成一些代码。
在某些情况下,我想使用枚举类型,因此我想包含它。我可以通过执行以下操作来获取要包含的文件的路径:
const EnumType *enumType = ...;
auto defineFileLoc =
enumType->getDecl()->getDefinition()->getLocation();
const auto defineFilePath =
sourceManager.getFilename(sourceManager.getExpansionLoc(defineFileLoc))
.str();
这会生成文件的完整路径。我可以包含完整路径,但这很丑陋且不可移植,所以我想知道是否有一种方法可以生成文件的相对包含路径。
我在想一种方法是获取翻译单元包含路径中的目录列表,然后看看是否可以找到与之相关的内容,但我无法找到一种使用 clang 工具来获取此内容的方法。我使用游行者,因此特定比赛的整个上下文是一个
clang::ast_matchers::MatchFinder::MatchResult
对象。
有没有办法获取特定翻译单元的包含路径中的目录列表?或者,有更好的方法来做我想做的事吗?
问题中建议的方法是正确的:
获取翻译单元中的目录列表,包括路径和 然后看看我是否能找到与之相关的东西
HeaderSearchOptions
类,特别是
UserEntries
场地。 它有一个向量
HeaderSearchOptions::Entry
,
每个都有一个
std::string Path
.
HeaderSearchOptions
可以从
CompilerInvocation
使用
getHeaderSearchOpts
.
CompilerInvocation
获得
CompilerInvocation
的程序因情况而异
您的工具是如何启动的。
createInvocation()
得到 CompilerInvocation
,然后使用
ASTUnit::LoadFromCompilerInvocation
运行解析器并获取 AST。
ClangTool::buildASTs
,
你将会有一个ASTUnit
并可以调用它的
getHeaderSearchOpts
方法。
ClangTool::runInvocation
然后你的回调被交给
CompilerInvocation
(上面提到了 getHeaderSearchOpts
)。
newFrontendActionFactory
(这就是教程的内容
确实如此),那么您需要修改调用站点以也传递
SourceFileCallbacks
其 handleBeginSource
从 中检索 CompilerInvocation
CompilerInstance
致电 getInvocation
。
例如,定义一个类:
// Intercept `handleBeginSource` so we can get the invocation.
class MySourceFileCallbacks : public clang::tooling::SourceFileCallbacks {
public:
virtual bool handleBeginSource(clang::CompilerInstance &ci)
{
llvm::outs() << "in handleBeginSource, hasInvocation: "
<< ci.hasInvocation() << "\n";
clang::CompilerInvocation &invoc = ci.getInvocation();
clang::HeaderSearchOptions &hso = invoc.getHeaderSearchOpts();
for (clang::HeaderSearchOptions::Entry const &entry : hso.UserEntries) {
llvm::outs() << " " << entry.Path << "\n";
}
return true;
}
};
然后修改对
newFrontendActionFactory
的调用为:
MySourceFileCallbacks sfCallbacks; // <--- add
return Tool.run(newFrontendActionFactory(&finder, &sfCallbacks).get());
// ^^^^^^^^^^^^ add
将文件名指定为
std::string
和 a
HeaderSearchOptions
,
创建相对路径的过程大多很简单。
但是,您可能需要考虑哪些
Group
每个 Entry
都在,反映
它是如何作为搜索路径出现的。
下面是我用来执行此操作的代码,生成完整的输出
#include
指令:
string ClangUtil::getIncludeSyntax(
clang::HeaderSearchOptions const &headerSearchOptions,
string const &fname,
int * NULLABLE userEntryIndex)
{
// Avoid having to awkwardly check the pointer below.
int dummy = 0;
if (!userEntryIndex) {
userEntryIndex = &dummy;
}
// Use naive ordered search. This isn't 100% correct in certain
// scenarios (e.g., involving -iquote), but should suffice for my
// purposes.
*userEntryIndex = 0;
for (auto const &e : headerSearchOptions.UserEntries) {
if (beginsWith(fname, e.Path)) {
// Get the name without the path prefix. The path is assumed to
// end with a directory separator, and that is stripped from
// 'fname' too.
string relative = fname.substr(e.Path.size() + 1);
if (e.Group == clang::frontend::Angled) {
// Perhaps ironically, paths specified with the -I option are
// classified by clang as "angled", but conventionally the
// names in such directories are referenced using quotes.
return string("\"") + relative + "\"";
}
else {
return string("<") + relative + ">";
}
}
++(*userEntryIndex);
}
if (beginsWith(fname, "./")) {
*userEntryIndex = -1;
// Drop the "." path component.
string trimmed = fname.substr(2);
return string("\"") + trimmed + "\"";
}
// Not found among the search paths, use the absolute name with quotes.
*userEntryIndex = -2;
return string("\"") + fname + "\"";
}
上面的代码是我的一部分 打印-clang-ast 存储库,其最初目的是打印 AST 详细信息,但也 作为 clang 实用程序的集合。