目的
C++ と cmake で作った実行ファイルを、pipでインストールできる形式にします。 加えて、pythonのライブラリも添付します。 なお、PyPIへのアップロード・配布は考慮していません。作り方
pythonの準備
skbuildを使うので、pip install scikit-build でインストールしておきます。 python 3.8.1 で動作確認しています。pipでインストールするC++のプログラムの準備
練習用C++プログラムを準備します。既存の、C++ & cmakeでビルドするプログラムがあれば、ここはスキップします。 まず、練習用C++プログラムの本体です。 [aaa.cpp]1 2 3 4 5 6 7 8 9 | #include <iostream>
int main(int argc, char *argv[]){
std::cout << "aaa bbb ccc" << std::endl;
for(int i=0; i<argc; ++i){
std::cout << argv[i] << std::endl;
}
return 0;
}
|
1 2 3 4 | cmake_minimum_required(VERSION 3.11.0)
project(projAAA)
add_executable(aaa aaa.cpp)
install(TARGETS aaa RUNTIME DESTINATION .)
|
setup.py
配布パッケージを作成するためのPythonスクリプト setup.py を作成します。1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | #!/usr/bin/env python
# -*- coding: utf-8 -*-
from skbuild import setup
setup(name="bdist-template", # パッケージの名前。pipでインストール後、pip list で表示される名前
version="0.0.0",
author="Your NAME",
author_email="your@name.com",
packages=["bdist_example"], # importするときに使う名前。nameと一致してなくても良い。
# 同じ方がユーザーには親切かも。
cmake_install_dir="bdist_example/bin", # 最初のディレクトリ名はpackagesで指定した名前と同じにする
entry_points={
"console_scripts": [
"cmdaaa=bdist_example:python_function_aaa"
]
# cmdaaa がpip install後にシェルから使えるコマンド名になる
# =と:の間は、packagesで指定した名前と同じにする
# :の右側は後ほど説明
},
url="http://yourname.abc",
download_url="https://yourname.abc/download",
description="Test package", # このパッケージの短い説明文
long_description="Test package !!!", # このパッケージの詳細な説明文
classifiers=[
"Programming Language :: C++",
'Programming Language :: Python'
],
license="???" # ライセンス名を記載(GPLとかApacheとか)
)
|
__init__.py
pipでインストールする場合、C++でビルドした実行ファイルをそのまま実行するのではなく、Pythonを一旦経由するので、 そのためのスクリプトを準備します。 まず、 setup.py のpackagesで指定した名前(ここではbdist_example)のディレクトリを作成します。 そこに次のような内容を含む __init__.py を作成します。 [bdist_example/__init__.py]1 2 3 4 5 6 7 8 | import os
import subprocess
import sys
CMAKE_BIN_DIR = os.path.join(os.path.dirname(__file__), "bin")
def python_function_aaa():
raise SystemExit(subprocess.call([os.path.join(CMAKE_BIN_DIR, "aaa")] + sys.argv[1:]))
|
同梱するスクリプト
次のスクリプトも同梱するようにします。バイナリのみの配布であれば、ここはスキップします。 [bdist_example/aaalib.py]1 2 | def print_aaaaa():
print("aaaaa")
|
.whlファイルの作成
ここまでそろうとパッケージを作ることができます。$ python setup.py bdist_wheelを実行すると、distディレクトリの中に.whlファイルが作成されます。
インストール
作成した.whlを次のようにしてインストールします。$ pip install dist/bdist_template-0.0.0-cp38-cp38-linux_x86_64.whl Processing ./dist/bdist_template-0.0.0-cp38-cp38-linux_x86_64.whl Installing collected packages: bdist-template Successfully installed bdist-template-0.0.0インストールされたことの確認は、
$ pip list Package Version -------------- ------- bdist-template 0.0.0 packaging 20.1 pip 20.0.2 pyparsing 2.4.6 scikit-build 0.10.0 setuptools 41.2.0 six 1.14.0 wheel 0.34.2でできます。bdist-templateがインストールされていることがわかります。
動作確認
先程作成したコマンドが呼び出せることを確認します。$ cmdaaa x y z aaa bbb ccc /home/user/.pyenv/versions/3.8.1/envs/py38/lib/python3.8/site-packages/bdist_example/bin/aaa x y zC++でビルドしたコマンドそのものは aaa でしたが、setup.pyで書いたコマンド名 cmdaaa が有効になっていることが確認できました。 同梱したスクリプトをpythonから実行してみます。
>>> import bdist_example.aaalib >>> bdist_example.aaalib.print_aaaaa() aaaaa
おまけ1
データを同梱したい場合は、次のようなコードを setup.py のsetup関数に渡す引数に追加します。setup(... include_package_data=True, package_data={ "bdist_example": ["data/*.dat"], } )ここでは、bdist_example/data/*.dat にデータがあると仮定しています。
おまけ2
.whlのファイル名でインストールできるpythonのバージョンが制限されるので、$ mv bdist_template-0.0.0-{cp38-cp38,py3-none}-linux_x86_64.whlのようにリネームしておくと、Python3ならインストールできるようになります。 ファイル名での制限を外すと、動作しないバージョンのPythonにインストールできてしまうので、代わりに、
setup(... python_requires='~=3.6' )のように指定しておきます。バージョン指定の書き方は
https://packaging.python.org/guides/distributing-packages-using-setuptools/#python-requires
が参考になります。
まとめ
skbuild により、 setup.py と __init__.py を準備するだけで .whl ファイルを作ることができました。参考文献
scikit-build (skbuild) のドキュメントhttps://scikit-build.readthedocs.io/en/latest/usage.html#basic-usage cmake-python-distributions のコード
https://github.com/scikit-build/cmake-python-distributions プロジェクトのパッケージングと配布
https://python-packaging-user-guide-ja.readthedocs.io/ja/latest/distributing.html
https://packaging.python.org/guides/distributing-packages-using-setuptools/
0 件のコメント :
コメントを投稿