MacでC#(Mono)からlibclangのライブラリを読み込む方法


## 背景
+ MacでCソースの構文解析を行いたくて、libclangで解析することに
+ libclang(C言語)で解析用ソースを書くのは大変そう
+ C#でlibclangを使用できる[ClangSharp]("https://github.com/SimonRichards/clang-sharp")がNuGetで公開されているのを発見
+ [公式]("http://llvm.org/releases/3.6.0/clang+llvm-3.6.0-x86_64-apple-darwin.tar.xz")で公開されているビルド済みの`libclang.dylib`だと`DllNotFoundException`が発生して使えない

## 原因と解決策
原因は`libclang.dylib`が`x86_64(64bit)`向けにビルドされているのに対して、Xamarin Studioでビルドして生成される実行ファイルが`i386(32bit)`向けになっているため、アーキテクチャが異なると怒られる

Xamarin Studio は現状`x86_64`向けの実行ファイルは生成できないようなので、clangのソースコードをビルドして`i386`向けの`libclang.dylib`を生成する。

またソースに標準で付いている`make`環境で`i386`向けのバイナリをビルドしようとしたところ途中でビルドエラーが発生したため、`Cmake` + `ninja`[^1]でビルドする。

[^1]: `ninja` : `make`より高速なビルドシステム

## 環境
+ Mac OSX 10.10 Yosemite
+ Xamarin Studio 5.7.1
+ clang 3.6

## clangビルド

+ LLVMのSVNリポジトリから最新版ソースをチェックアウト

```bash
$ svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm
$ cd llvm/tools
$ svn co http://llvm.org/svn/llvm-project/cfe/trunk clang
$ cd ../../
$ cd llvm/tools/clang/tools
$ svn co http://llvm.org/svn/llvm-project/clang-tools-extra/trunk extra
$ cd ../../../../
$ cd llvm/projects
$ svn co http://llvm.org/svn/llvm-project/compiler-rt/trunk compiler-rt
$ cd ../../
```

+ `Cmake`をインストール

```bash
$ cd llvm
$ git clone git://cmake.org/stage/cmake.git
$ cd cmake
$ git checkout next
$ ./bootstrap
$ make
$ sudo make install
```

+ `ninja`をインストール

```bash
$ cd llvm
$ git clone https://github.com/martine/ninja.git
$ cd ninja
$ git checkout release
$ ./bootstrap.py
$ sudo cp ninja /usr/bin/
```

+ `Cmake`で`ninja`用コンフィグファイルを生成しビルド[^2][^3]

[^2]: `-DCMAKE_BUILD_TYPE=Release` : Releaseビルド
[^3]: `-DCMAKE_C_FLAGS="-arch i386" -DCMAKE_CXX_FLAGS="-arch i386"` : i386向けのバイナリを生成

```bash
$ mkdir llvm/build
$ cd llvm/build
$ cmake -G Ninja ../llvm -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_FLAGS="-arch i386" -DCMAKE_CXX_FLAGS="-arch i386"
$ ninja
```

+ `llvm/build/lib`以下に`libclang.3.6.dylib`が生成される

## 使い方

1. Xamarin Studioを起動して、新規C# コンソールプロジェクトを作成
2. メニューの`プロジェクト`->`Add NuGet Packages...`を開く
3. `clang.sharp`で検索し、`Add Package`でインストール
4. 実行フォルダと同じディレクトリに`libclang.3.6.dylib`をコピー
5. `libclang.dylib`にリネーム
5. 解析用のソースを記述する

```c:main.c
#include <stdio.h>

int main(void)
{
	printf("Hello, World!");
}
```

```c#:Program.cs
using System;
using ClangSharp;

namespace ClangNet
{
	class MainClass
	{
		/// <summary>
		/// Main Method
		/// </summary>
		/// <param name="args">The command-line arguments.</param>
		public static void Main(string[] args)
		{
			/* Create Index */
			var index = new Index(true, true);

			/* Clang Arguments */
			var arg = new string[1]{ "" };

			/* Create Translation Units */
			var tu = index.CreateTranslationUnit("src/main.c", arg, null, TranslationUnitFlags.DetailedPreprocessingRecord);

			/* Creation Success */
			if(tu != null)
			{
				/* Get Translation Unit Cursor */
				var cursor = tu.Cursor;

				/* Visit Children */
				cursor.VisitChildren(VisitChildrenCallback);

				/* Dispose Translation Unit */
				tu.Dispose();
			}

			/* Dispose Index */
			index.Dispose();
		}

		/// <summary>
		/// Visit Children
		/// </summary>
		/// <returns>Child Visit Result</returns>
		/// <param name="cursor">Cursor</param>
		/// <param name="parent">Parent</param>
		public static Cursor.ChildVisitResult VisitChildrenCallback(Cursor cursor, Cursor parent)
		{
			/* Dump Cursor Kind & Cursor Spelling */
			Console.WriteLine("{0} : {1}", cursor.Kind, cursor.Spelling);

			/* Visit Recursively */
			return Cursor.ChildVisitResult.Recurse;
		}
	}
}

```

```bash:実行結果
MacroDefinition : __llvm__
MacroDefinition : __clang__
MacroDefinition : __clang_major__

~ 省略 ~

FunctionDecl : main
CompoundStmt : 
CallExpr : printf
UnexposedExpr : printf
DeclRefExpr : printf
UnexposedExpr : 
UnexposedExpr : 
StringLiteral : "Hello, World!"
```