LoginSignup
0

More than 5 years have passed since last update.

[Clang,libClang] exercise1 : FileManager

Posted at

怒涛の勢いで開発が進むclangですが、c++だけでなく、コンパイラとして必要な汎用的な機能を提供しています。
これらの機能はc++APIとして公開されていて、Pythonインターフェース等もあります。

なので、clangを使えば「ぼくのかんがえたさいきょうのぷろぐらみんぐげんご」を少ないコストで作ることができます。

今回はこのclangのc++APIの使い方を学んでいきたいと思います。

最初の一回はファイルIO周りです。
続くかは分かりません。

概要

clangはファイルIOを管理するクラスとしてFileManagerクラスとSourceManagerクラスを提供しています。
FileManagerは基本的なファイルIOやファイル名のキャッシング機能等を提供しています。
SourceManagerはさらにFileManagerに加えてCプリプロセッサーとコンパチなソースロケーション機能を備えています。
またSourceManagerはファイルそのもののキャッシング機能も持っています。

初回はFileManagerから見ていきましょう。

FileManager

FileManagerクラスは
$CLANG_ROOT/include/clang/Basics/FileManager.h
に宣言してあります。

早速FileManagerを作ってみましょう。
コンストラクタをみると

FileManager (const FileSystemOptions &FileSystemOpts, IntrusiveRefCntPtr< vfs::FileSystem > FS=nullptr)

となっています。
FileSystemOptionsは今の所、作業ディレクトリの情報のみを格納します。($CLANG_ROOT/include/clang/Basics/FileSystemOptions.h)
IntrusiveRefCntPtr< vfs::FileSystem >は気にしなくて良いです。
気になる人のために少しだけ補足しておくと、IntrusiveRefCntPtrはクラステンプレートでstd::shared_ptr等の参照カウント方式のスマートポインタをラップします。
vfs::FileSystemは基本的なファイルIOのヘルパー関数を備えた抽象クラスです。
FileManagerはデフォルトでRealFileSystemを選択します。
これはOSが提供するファイルシステムを使います。
もちろんその気になればメモリ上にファイルシステムを展開して、物理デバイスをシミュレートする事もできます。
もっともこういう使い方はOSのファイルシステム側でも簡単にできるので(少なくともLinuxは)、使うことはあまりないでしょう。

ではFileManagerを作ります。

#include <string>
#include "clang/Basic/FileManager.h"
#include "clang/Basic/FileSystemOptions.h"

int main()
{
  clang::FileSystemOptions fso;
  fso.WorkingDir = "./";
  clang::FileManager fm(fso);
  return 0;
}

ちゃんとコンパイルできましたか?
リンクエラーがでている様なら以前に、リンクオプションの見分け方のページを書きましたので、参考にしてください。

FileSystemOptionsのWorkingDirを設定しなくても上手く行きますが、FileManagerが相対パスを解決できなくなります。

それではFileManagerを使ってみましょう。
まず良くつかうのが

const DirectoryEntry* getDirectory (StringRef DirName, bool CacheFailure=true)
const FileEntry* getFile (StringRef Filename, bool OpenFile=false, bool CacheFailure=true)

の2つです。
DirectoryEntryやFileEntryはディレクトリやファイルを表すクラスで、ファイル名、サイズ、アクセス可能かどうかを取得できるハンドラーを提供します。
getDirectory(DiraName)やgetFile(FileName)で、DirectoryEntryやFileEntryを取得します。
また、FileManagerはファイルパスのキャッシング機能を持っていて、一度参照したパスは次回から高速に検索できます。
ファイルの中身をキャッシュする訳ではありません。
ディレクトリやファイルの検索に失敗するとnullを返します。

それではFileManagerからFileEntryを受け取り、ファイルの情報を参照してみましょう。

1  clang::FileSystemOptions fso;
2  fso.WorkingDir = "./";
3  clang::FileManager fm(fso);
4  auto fe_ptr = fm.getFile("test.cpp");
5  std::cout << fe_ptr << std::endl;
6  if(fe_ptr != nullptr){
7      std::cout << fe_ptr->getName() << std::endl;
8      std::cout << fe_ptr->getSize() << std::endl;
9      std::cout << fe_ptr->isValid() << std::endl;
10     std::cout << fe_ptr->getDir()->getName() << std::endl;
11     std::cout << fm.getCanonicalName(fe_ptr->getDir()).str() << std::endl;
12 }

意味は見ての通りです。
4行目で $WorkingDir/test.cppのFileEntryを受け取り、成功していれば、
ファイル名(7行目)
ファイルサイズ(8行目)
ファイルが存在するかどうか(9行目)
相対ディレクトリ名(10行目)
絶対ディレクトリ名(11行目)
を出力します。

FileEntryのgetDirメンバ関数はDirEntryへのポインタを返します。(10行目)
FileSystemのgetCanonicalName(DirEntry*)メンバ関数はllvm::StringRefという文字列参照のラッパクラスを返しますが、.str()でstd::stringを返します。(11行目)

以上がFileManagerの使い方です。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0