Windows環境で CUDAnative.jl を使う

Juliaの[CUDANative.jl](https://github.com/JuliaGPU/CUDAnative.jl)でCUDA9.1を動かしたという[記事](https://qiita.com/SFyomi/items/74e9cb5b440a3af4fba2)を見て、Windows環境のCUDA9.1でもできるかと思ってやってみました。
いろいろ試行錯誤した結果、なんとか動きました。
[CUDAnative.jl](https://github.com/JuliaGPU/CUDAnative.jl)を動かすには、依存ライブラリである[LLVM.jl](https://github.com/maleadt/LLVM.jl)をいれる必要があるのですが、そのためには、Juliaをソースからビルドする必要がある、ということになっています。
ですが、結論から言うと、自分でビルドすることなく、[公式のダウンロードページ](https://julialang.org/downloads/)にあるv0.6.2のWindows 64bitのバイナリで動かすこともできました。ただし、LLVM.jlにパッチをあてたりと、いろいろと面倒な手順はいります

ちなみに、上の[参考記事](https://qiita.com/SFyomi/items/74e9cb5b440a3af4fba2)では、LLVMのバージョンを4.0.1にする必要があるとのことですが、LLVMは公式の3.9.1のままでも動きました。（LLVM 4.0.1も試したのですが、windows環境では、thread関係のエラー？でsegfaultで落ちてしまって動きません。）

# インストール手順
前提とする環境は、[公式のダウンロードページ](https://julialang.org/downloads/)にあるv0.6.2のWindows 64bitの[バイナリ](https://julialang-s3.julialang.org/bin/winnt/x64/0.6/julia-0.6.2-win64.exe)です。
Juliaを起動して、`versioninfo()` した結果は以下です。

```jl
julia> versioninfo()
Julia Version 0.6.2
Commit d386e40c17* (2017-12-13 18:08 UTC)
Platform Info:
  OS: Windows (x86_64-w64-mingw32)
  CPU: xxxxxxxxxxxxxxxxx
  WORD_SIZE: 64
  BLAS: libopenblas (USE64BITINT DYNAMIC_ARCH NO_AFFINITY Prescott)
  LAPACK: libopenblas64_
  LIBM: libopenlibm
  LLVM: libLLVM-3.9.1 (ORCJIT, broadwell)
```

## 1. [LLVM.jl](https://github.com/maleadt/LLVM.jl) のインストール
まず、LLVM.jl を `Pkg.add` で追加してみます。

```jl
julia> Pkg.add("LLVM")
INFO: Cloning cache of LLVM from https://github.com/maleadt/LLVM.jl.git
INFO: Installing LLVM v0.5.1
INFO: Building LLVM
...（略）
LoadError: Unknown OS
```
とエラーがでるはずです。LLVM.jl の v0.5.1 はWindows環境をいっさい考慮していないので。（最新のLLVM.jl の v0.9.xではwindows環境の考慮もされていますが、Julia v0.6.x では動作しません）

### LLVM.jlにパッチあて
というわけで、LLVM.jlを無理やりWindowsに対応させるパッチを作りました。
https://github.com/yatra9/LLVM.jl.v0.5.1.patch にあります。

Juliaを起動して、以下のコマンドを実行してください。

```julia
pkgdir = Pkg.dir("LLVM")
sourceurl = "https://raw.githubusercontent.com/yatra9/LLVM.jl.v0.5.1.patch/v0.0.1/"
repo = LibGit2.GitRepo(pkgdir)
if string(LibGit2.head_oid(repo)) == "c67f4c19e52ca89553ef80fec67700f613b7424d" && !LibGit2.isdirty(repo)
    for path in ("deps/build.jl", "deps/compile.jl", "deps/discover.jl", "deps/llvm-extra/Makefile", "src/LLVM.jl", "src/base.jl")
        download(sourceurl * path, joinpath(pkgdir, split(path, '/')...))
    end
end
```

### LLVM.jl の build
あらためて、LLVM.jl を build します。

```jl
julia> Pkg.build("LLVM")
```

テストもすべてパスするはずです。

```jl
julia> Pkg.test("LLVM")
```

## 2. [CUDAnative.jl](https://github.com/JuliaGPU/CUDAnative.jl) のインストール
あらかじめ、NVidia の CUDA Toolkit をインストールしておきます。
あとは、LLVM.jl がインストールされていれば、CUDAnative.jl を `Pkg.add` するだけです。

```jl
julia> Pkg.add("CUDAnative")
```

これで、GPU が使えます。

# LLVM_extras.dll を自分でビルドする場合
LLVM.jl を動かすには LLVM_extras.dll というDLLが必要です。
上のインストール手順では、私がビルドした LLVM_extras.dll のバイナリを、
https://github.com/yatra9/LLVM.jl.v0.5.1.patch/releases
からダウンロードしてくるようにしています。

LLVM_extras.dll を自分でビルドするには、Juliaをソースからビルドする必要があります。
https://github.com/JuliaLang/julia/blob/v0.6.2/README.windows.md
のCygwin-to-MinGW cross-compiling というsectionにしたがって、Cygwin環境を用いてJuliaをソースからビルドしてください。
参考までに Make.user を示します。

```
XC_HOST = x86_64-w64-mingw32
override USE_LLVM_SHLIB = 1

#  HASWELL以降のCPU (Broadwell, Skylake, KabyLake, CoffeLake等）は、すべて OPENBLAS_TARGET_ARCH=HASWELL にする
OPENBLAS_TARGET_ARCH = HASWELL
```

Juliaのビルドが無事終了したら、Juliaを起動して、上記のパッチまで実行してください。
その後、環境変数`LLVM_JL_COMPILE` を `"true"` にセットしてから、`Pkg.build("LLVM")` すれば、LLVM_extras.dll ができるはずです。

```jl
julia> ENV["LLVM_JL_COMPILE"] = "true"
julia> # ENV["CYGWINROOT"] = "C:\\cygwin64"  # optional
julia> Pkg.build("LLVM")
```
Cygwin の場所は自動的に検出するようになっていますが、失敗する場合には、環境変数`CYGWINROOT` にCygwinの場所を設定してください。