使用 clang 工具获取文件的相对包含路径

问题描述 投票:0回答:1

我正在使用 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
对象。

有没有办法获取特定翻译单元的包含路径中的目录列表?或者,有更好的方法来做我想做的事吗?

c++ clang code-generation clang++ libclang
1个回答
0
投票

问题中建议的方法是正确的:

获取翻译单元中的目录列表,包括路径和 然后看看我是否能找到与之相关的东西

标头搜索路径存储在

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 实用程序的集合。

© www.soinside.com 2019 - 2024. All rights reserved.