http://biokids.org/1d96fc.htmlどぶお/Pythonで遊ぼう!distutilsでコンパイラ関連オプションを変更する作成したモジュールやパッケージを配布する際に利用するモジュールは、標準モジュールであるdistutilsがあります。ここでは、配布用のバイナリパッケージを作成するbdistコマンドを使用するときにコンパイラやコンパイルオプションを変更する場合の方法を考えてみます。スタンダードな手段として、環境変数(CCやCFLAGS)にオプションを指定する方法が広く使えます。11.1を使う設定を試そうとしたとき、気になった点がありましたのでdistutilsの挙動を検証しつつ、エレガント(?)な対応方法を探ってみました。(?)強引と思われる方法で実現していますので、どの程度の汎用性があるかは不明です。2.5に付属のdistutilsで試しました。Compilerぐらいには対応しているかもしれませんが、それ以外、自分なりの特別なビルドオプションを配布時に組み込みたいときには役に立つかも。コンパイラの設定をいじるにはExtensionクラスのオプションを指定するdistutilsのドキュメントによると、distutils.core.Extensionクラスを使用する際に以下のオプションが使えます。"-static-intel"]こんな感じですね。これらを指定すれば、おそらく特に問題なくオプションを指定できるでしょう。環境変数を指定する一般によく用いられるconfigureでも環境変数で指定することができますが、distutilsでも同様です。setup.pyスクリプト中でも以下のようにすれば、指定することができます(Unixの場合)。-no-prec-div"これらの環境変数の読み取りはdistutils/sysconfig.pyのcustomize_compiler()(後述)中で指定されています。CPPFLAGSが使用されるようです。このようにすることで、とりあえずはオプションの制御ができるようです。Compilerにも関わらずgccのディフォルトオプション(赤字の部分)が読み込まれるため警告が出たり、最適化オプションの上書き(後から-O3を追加しているため)警告が出たりしました。無視すれば済むのですが、もうちょっと完全に制御できないかということで別のやり方を試すことにしました。CCompilerクラスの派生クラスで制御するdistutilsにおけるコンパイラの動作は一連のCCompiler派生クラスにより行われているようです。Compilerを使う場合UnixCCompilerの派生クラス(例えばMyIntelCCompiler)を定義し、使用すれば(おそらく)ビルド時の動作は好きなように制御できるはずです。そこで、CCompilerクラスがどのように実体化されるかを追跡してみました。実体であるコンパイラオブジェクトは通常拡張モジュールのビルドに使用されるため、distutils/command/build_ext.pyのbuild_ext#run()が使われます。その中でdistutils.ccompiler.new_compiler()が呼ばれ、これがCCompilerインスタンスを返します。new_compiler()内ではdistutils.ccompiler.compiler_classディクショナリ内で定義されているクラスを読み込みオブジェクトを生成しています。説明)が定義されているようです。ここでコンパイラタイプにunixを指定すればdistutils.unixccompiler.UnixCCompilerクラスが使用されるわけです。その後、distutils.sysconfig.customize_compiler()にオブジェクトが渡され、コンパイラタイプがunixの場合はディフォルトオプション等が読み込まれてセットされます。従ってgccのディフォルトオプション等を避けるためにはコンパイラタイプをunix以外に指定しなければなりません。このような仕組みなので、compiler_classに新しく、例えばintelというアイテムを追加すればよさそうですが、困ったことに、compiler_classを使用するnew_compiler()中で取得したモジュール名(例えばunixccompiler)にパッケージ名distutils.が付けられてしまうのでdistutilsパッケージ以下のモジュールしか指定できません。distutilsに直接モジュールを追加すれば実現できますが、それでは意味がないので、さらに他の方法を探ります。仕方がないのでそのnew_compiler()をデコレートしてCCompilerオブジェクト生成部を変更してしまいます。wrap_new_compiler(distutils.ccompiler.new_compiler)デコレータの作成方法はここでは触れませんが、このコード片で定義しているwrap_new_compilerで元々のnew_compilerをデコレートします。compiler_class中で指定したコンパイラタイプが存在しない場合、new_compilerはdistutils.errors.DistutilsPlatformError例外を送出します。それを捕捉することで、特別なコンパイラが指定されたと判断可能です。実際には、オプションでコンパイラタイプに何が指定されたか等を判断する部分を組み込みます。ここで返すためのMyIntelCCompilerクラスの定義を行います。Compilerを扱うためのクラスが作成できるはずです。})これでようやくMyIntelCCompilerクラスを使用できるようになりました。あ、ここまで来て気付きましたが、MyIntelCCompilerクラスなどを作らなくても、customize_compiler()をラップするなり置き換えてもよかったですね。拡張モジュールのビルドコマンドに組み込む上記の方法で使用するコンパイラは好きなように変更できるはずですが、実際に拡張モジュールのビルド段階で使用してみます。拡張モジュールのビルドはcommand.build_extなので、build_extクラスの派生クラスを作成し、runメソッドを実装します。Pythonモジュールであるdiffraction.pyと拡張モジュールであるdiffractionmod.soから構成されるモジュールセットのsetup.pyを書いてみたものです。Compilerを使用しています。コメントコメント等あればお願いします。