C/C++ から Cython によって生成されたコードを呼び出す(Windows版)

#本日は

C/C++ から Pythonを呼ぶ方法としてCythonを使う方法を紹介です．

高速化のためにPythonで外堀を書いてCoreな部分をC/C++ということをするというのはよくあります．今回はその**逆**です．逆のって公式ドキュメント以外あまりてがかりがないのよね・・・．ありましたら教えてくださいましOTL.

（追記：Mac版書きました．）

- [C/C++ から Cython によって生成されたコードを呼び出す(Mac版)](https://qiita.com/SatoshiTerasaki/items/6238fc075e8a47f44552)

# 環境
- OSはVisual Studio を使うためWindowsを用います．
- IDE Visual Studio 2017 Community
   - 特にCommunity, 2017で限る必要はないです．2013でも行けたので2015でもOKだと思います．
- Python3.5.4（Miniconda3) 
- Cython 0.26 

# Visual Studioによる環境作成
## ソルーション作成

![project.png](https://qiita-image-store.s3.amazonaws.com/0/135978/db3db8f7-ac86-77d3-5139-8045c5f87ad8.png)

Visual C++ -> 空のプロジェクトを選択->とりあえずOKボタンを押す．これで空のプロジェクトを生成できます．ソルーションおよび最初に作られるプロジェクト名はProject1となっています．

## ソースファイルにコードを追加
Ctrl+Shift+Aで空のC++ファイルを追加．デフォルト名はSource.cppとなっていますが，そのまま使用．
後でSource.cppにコードを書いていきます．いまは白紙のままで放置します．

## Python の場所を知る

ここからは各自の環境依存になるので注意です．

読者はPythonをよく使っている方だと思うので自分がどのPythonを使っているかはご存知だと思います．とはいえ，確認してみましょう．

コマンドプロンプトを開いて

```shell-session
> where python
```
を実行します．私の場合は`C:\ProgramData\Miniconda3\python.exe` でした．

`C:\ProgramData\Miniconda3`に移動しましょう．
下の写真では `include` と `libs` を選択しています．
![pythonhome.png](https://qiita-image-store.s3.amazonaws.com/0/135978/1f85d24e-059f-d7e4-b9a2-4a7418771d26.png)

このディレクトリのパスを次に使うのでメモしておいてください．

## プロパティ編集

プロパティー＞VC++ディレクトリー＞インクルードディレクトリに上でメモしたincludeのフルパスを追加．
私の場合は `C:\ProgramData\Miniconda3\include`
です．

プロパティー＞VC++ディレクトリー＞インクルードディレクトリに上でメモしたlibsのフルパスを追加．
私の場合は `C:\ProgramData\Miniconda3\libs` 
です．

下の図で囲んだ赤枠のようにしましょう．
あと，プラットフォームはｘ６４にしておきます．

![propety.png](https://qiita-image-store.s3.amazonaws.com/0/135978/577c0c49-e1e0-8787-8fe2-9e9109c62254.png)


## debug binaries, debugging symbols の導入

公式のPythonのホームページからインストーラをゲットしてインストーラーを起動します．
Customize installationをクリックしてNextボタンをクリック．
![install.png](https://qiita-image-store.s3.amazonaws.com/0/135978/4e4f5687-c727-0888-8007-6b370231d7d3.png)
![next.png](https://qiita-image-store.s3.amazonaws.com/0/135978/0d48d0cb-4054-942e-4641-1c56af907b6d.png)
![debug.png](https://qiita-image-store.s3.amazonaws.com/0/135978/b9beb042-75be-b61f-b206-6d64fd76a577.png)

download debug binaries, debugging symbols にチェックを入れます．
このPythonをメインに用いない場合はPATHの追加は不要です．

## ビルドチェック
Source.cppに次を記述

```c:source.cpp
#include<Python.h>
int main() {
	Py_Initialize();
	printf("Hello");
	Py_Finalize();
	return 0;
}
```

releaseモードでビルド出来たらひとまずOK．Python.hがないよーとか怒られたらインクルードディレクトリの追加が失敗しています．落ち着いて設定しなおしましょう．

そしてデバッグモードではpython35_d.libと同名のDLLなるものが必要なのでそれを入手する必要があります．

- [I cannot find python35_d.lib
](https://stackoverflow.com/questions/35250175/i-cannot-find-python35-d-lib)

上記のスタックオーバーフローを参考にPython公式ページからPython３のインストーラーを起動してオプションで"download debug binaries"を選択すると入手できます．探してみましょう．




# Cythonコード作成
上で作成したSource.cppと同階層に次を作ります．

- setup.py
- cytest.pyx

各々のコードは次の通りです．

```py3:setup.py
from distutils.core import setup 
from Cython.Build import cythonize

setup(ext_modules=cythonize("cytest.pyx"))
```

```py3:cytest.pyx
from libc.stdio cimport printf

cdef public struct Point:
    double x
    double y

cdef public Point DoubleCoord(Point p):
    cdef Point q
    q.x=2*p.x
    q.y=2*q.x
    printf("q.x=%f, q.y=%f\n",q.x,q.y)
    return q
```

とりあえず頂点構造体を定義して座標を2倍にして返す関数をCythonで作りました．

## setup 
コマンドプロンプトを開いてCythonコードをビルドしましょう．

```shell-session
> python setup.py build_ext --inplace
```

## 生成コード追加
このときに生成される
cytest.c cytest.hをVisual Studioのソースファイルとヘッダーファイルに各々追加します．

## Source.cpp 編集

```C++:Source.cpp
#include<Python.h>
#include<stdio.h>
#include "cytest.h"

int main() {
	Py_Initialize();
	struct Point p;
	p.x = 3.5;
	p.y = 7.0;
	struct Point q = DoubleCoord(p);
	printf("q.x=%f,q.y=%f", q.x, q.y);
	Py_Finalize();
}
```

ここまでの成果物としてVisual Studio上では下図のようになっているはずです．

![vstotal.png](https://qiita-image-store.s3.amazonaws.com/0/135978/cf170eb7-da07-2651-d5f2-d53ced457d70.png)

実行すると次のようになります．

![result.png](https://qiita-image-store.s3.amazonaws.com/0/135978/9402411e-61e4-d352-dc41-ac172a95b434.png)

# 最後に

大変だーね・・・．
リファレンスとして

- [Interfacing with External C Code]
(http://cython.readthedocs.io/en/latest/src/userguide/external_C_code.html)

を挙げておきます．