はじめに
こんにちは、Python界のSIGTERMです。先日CPython 3.2ソースコードリーディングに参加して「そもそもソース読む前にC/APIの書き方わかってないとだめだな」と痛感したので手習い的に書き始めてみました。題材は今や絶賛サンプルパッケージとしておなじみの bucho をC/APIで書きなおした cbucho です。
書き散らかしたもの
参考
とりあえず公式ドキュメントと既存のソースを読めばいいと思います。
はまったところ
ディレクトリ構造
次のようなディレクトリ構造にした。モジュール名のディレクトリを掘って、そこにCのソースを全部置きました。
% tree . ├── MANIFEST.in ├── README.rst ├── cbucho │ ├── cbuchomodule.c │ └── cbuchomodule.h └── setup.py
Cコンパイラに渡すオプションの自動チェック
setup.pyの書き方は公式ドキュメントにありますが、Cで読み込むライブラリのprefix等をどうやって取ってくるかではまりました。 id:mopemope が書いたソースを参考にさせてもらいました。
import sys import os from subprocess import Popen, PIPE def conf_option(config_cmd, option): cmd = ' '.join([config_cmd, option]) p = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE) res = p.stdout.read() p.wait(); opts = [] for opt in res.split(): opt = opt.strip() if opt.startswith("-l") and option == '--libs': opts.append(opt[2:]) elif opt.startswith("-L") and option == '--static-libs': opts.append(opt[2:]) elif opt.startswith("-I") and option == '--cflags': opts.append(opt[2:]) elif option == '--prefix': opts.append(opt) return opts libraries = conf_option('curl-config', '--libs') library_dirs = [opt + "/lib" for opt in conf_option('curl-config', '--prefix')] include_dirs = [opt + "/include" for opt in conf_option('curl-config', '--prefix')]
これでcurl-config --prefixやxml2-config --libsといったコマンド経由で得られる情報を取得できました。
開発時ビルド
初回のビルドは普通にbuildしてdevelopでインストールしておく。
% python setup.py build % python setup.py develop
2回目以降はbuildディレクトリ消してから再ビルドと再インストール。ほんとはrmじゃなくてsetup.py cleanでいけるはずなんだけど、どうもうまく消えてくれなかったのでこうしましたよ。
% rm -rf build && python setup.py build && python setup.py develop
ヘッダファイルの追加
setup.pyに書くのではなくMANIFEST.inに書くというのに気付かなかったのでsdistをつくってもうまいことビルドできずはまりました。Extensionのキーワード引数sourcesにはあくまで*.cのソースだけ渡すので、MANIFEST.inに読み込むヘッダファイルを書きました。
include README.rst include cbucho/cbuchomodule.h
ソース改変後に再ビルドする際は次のような形で。
% rm -rf build && python setup.py build && python setup.py develop
ドキュメントを見る限りclearオプションでうまくいくはずだけど、ちょっとはまったのでbuildディレクトリを消した。
PyPIへのアップロード
初回登録はregisterをしておく。
% python setup.py register
@shimizukawaの助言よりWindows以外ではbdist_eggは使わないようにしたほうがいいとの事なのでsdistのみを登録してみます。
% python setup.py sdist upload
uploadする前にsdistだけ行って、できたtar.gzでインストールを確認しておくこと。
これから
次の内容はまだやってない。
- ドキュメントの同梱
- 複数のオブジェクトを作成してのsetup.py経由での*.so作成
- setup.pyを用いてのtest