6
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

HomebrewでPythonアプリのFormulaを作る時に気をつけること

Last updated at Posted at 2018-02-09

やったこと

最近FlatCAMというオープンソース基板CAM(ガーバーデータを読んでGコードとかを出力してくれるやつ)ソフト用の野良Homebrew Formulaを作りました。

https://github.com/tomoyanonymous/homebrew-flatcam

というのも、LinuxとWindowsにはビルドされたバイナリがあるのにMacには無く、自力で依存パッケージをbrewでインストールして、Python依存パッケージはpipでインストールして自力で立ち上げてね、とのことだったので、流石にちょっとめんどくさいな…と思ったからです。

しかもFlatCAMは現在まだGUIに使っているのPyqtのバージョンが4と一つ古いバージョンで、公式のHomebrewではすでに提供されていません。こういうものは本家リポジトリにFormula
リクエストしても承認されないので野良リポジトリとして作るのが懸命です。

参考にしたもの

インストールステップ自体は概ねこの手順に従いました。

Installing FlatCam on macOS Sierra
https://wolfgang.reutz.at/2017/04/25/installing-flatcam-on-macos-sierra/

あとFormula作る時は本家のFormula Cookbookを穴が空くほど読みましょう。野良リポジトリにしても有用な話がたくさんあります。

それから今回の本題であるPythonアプリに関してのTipsはここに情報がまとまっています。

手順

まずformulaのファイルを作りましょう。

bash
brew create flatcam

こうすると/usr/local/Homebrew/Library/Taps/homebrew/homebrew-core/Formula/flatcam.rbというファイルが出来上がると思います。後で移動しますがこの場所で作業していたほうが楽なのでとりあえずここに置いて直接編集します。ある程度雛形は作ってくれているので、必要なところを埋めていきます。

基本情報

flatcam.rb
class Flatcam < Formula
  version "8.5.0"
  desc "FlatCAM: 2D Computer-Aided PCB Manufacturing"
  homepage "http://flatcam.org/"

このあたりの基本情報は野良リポジトリならシビアになる必要はないですが何も入れないと警告が出たりするので(特にバージョン名はフォルダ名につながるので)入れましょう。

本体のURL

flatcam.rb
  url "https://bitbucket.org/jpcgt/flatcam.git"

これはビルドされたバイナリが配布されていたりすればその.tar.gzファイルと、そのSHA256キーを書く事が推奨されますが、特にない場合はGitリポジトリのURLそのまんまでも大丈夫です。ブランチは標準でmasterですが、特定のブランチやタグ、コミットハッシュを指定することも出来ます1

Homebrew依存パッケージ

flatcam.rb
  depends_on "python" => "with-tcl-tk"
  depends_on "cartr/qt4/qt@4"
  depends_on "cartr/qt4/pyqt@4"
  depends_on "cartr/qt4/pyside"
  depends_on "geos"
  depends_on "spatialindex"
  #for matplotlib
  depends_on "pkg-config"
  depends_on "freetype"
  #for scipy(fortran compiler)
  depends_on "gcc"

ここからが本題。tapしなければいけない非公式リポジトリは例えば、

bash
brew tap cartr/qt4 # Github上のユーザーcartrのhomebrew-qt4というリポジトリを指定
brew install qt@4

というものは depends_on cartr/qt4/qt@4として書いておけばいいです。バージョン古いぞとwarningは出ますがそういう目的なので仕方ない。
geosとspatialindexは普通に最新版でいいのでそのようにしています。あと参考記事では書いてなくて引っかかりましたが、python上でmatplotlibを動かすためにはpkg-configとfreetypeが、scipyを動かすためにはgfortranが、つまりそれが入っているgccが(何かのfftライブラリが依存してるらしいです…)必要なので書いておきます。

仮にHomebrewで自分のマシンにgccとかがインストール済みになっていても、明示的に依存を指定しておかないとパスが通りません。余談ながらgccはビルドに1時間ぐらいかかるので初回インストールでは罠になります。

HomebrewにおけるPythonのバージョン達

本題中の本題です。
まず前提として、Homebrewを使っている人のMac上には大体3種類のPythonがインストールされていると思ってください。これらはごっちゃにならないようにそれぞれのコマンド名が分けられています。パッケージマネージャpipも同様に、それぞれインストールされるパッケージのフォルダも異なります。

インストール元 系列 コマンド名 pipコマンド pipインストールディレクトリ
システム標準 2.7 python (標準では付属せず)
Homebrew python 2.7 python2 pip/pip2 /usr/local/lib/python2.7/site-packages
Homebrew python3 3.x python3 pip3 /usr/local/lib/python3.x/site-packages

pyenvやvirtualenvを使っている人は更にこれに加えて幾つかのバージョンがインストールされていたり、エイリアスが変更されていたりします。ここは突っ込み始めると泥沼なのでノータッチです。
HomebrewでPythonアプリを扱う場合、特別なことがなければシステムのpythonを使うようにやってくれるのですが、今回のアプリではtcl-tkのインタプリタが入っていないとダメで、Homebrewの2.7に--with-tcl-tkオプションを付けてインストールすることになります。
というわけでdepends_on "python" => "with-tcl-tk"という物を書いておく必要があります。

Homebrewでpipパッケージの管理

さてFlatCAMが依存していたpipでインストールすべきパッケージは以下です。

numpy matplotlib rtree scipy shapely simplejson svg.path

例えばここでインストールスクリプトにpip install <packages>と直打ちしてしまうのも一つの手ですが、HomebrewではHomebrew以外の何かをDLするツールを使用しない事が原則となっています。それに、Homebrewでインストールしていたら知らない間に/usr/local/lib/python2.7/site-packagesの中に知らないライブラリが山のように溜まっている…という状況も嫌なものです。

そこでHomebrewではvirtualenvを用いてpython/python2/python3のどれかをベースにしたPythonの仮想実行環境を作り、パッケージはその仮想環境内にそれぞれインストールする形を取っています。
スクリーンショット 2018-02-10 0.22.13.png

/usr/local/Cellar/flatcam/8.5.0/libexec/lib内にPythonの仮想環境のが構築され、画像のような感じでsite-packagesが作られ、その中にpipでインストールしたものが入るというわけです。

homebrew-pypi-poetを使ってpipパッケージをURLに

では具体的にpipコマンドを使わずにこのフォルダにパッケージをDLするために、pipがインストールする時に取ってくるpypiのリポジトリから.tar.xzファイルとそのSHA256ハッシュを拾い集めなければなりません。それを手動で…?と思ったらhomebrew-pypi-poetという便利スクリプトがあるようです。使い方を説明したほうが速いと思うのでそうすると、

bash
# virtualenvwrapperという仮想環境作成ユーティリティを入れる(これだけはグローバルで入れてしまって下さい)
brew install python
python -m pip install virtualenvwrapper #システムのpythonからpython2のpipを呼び出している
source $(brew --prefix)/bin/virtualenvwrapper.sh

# 一時的な仮想環境を作ります
mkdir ~/hoge && cd ~/hoge
mktmpenv

# homebrew-pypi-poetと、Formulaに必要なpackage達を一時的にインストール
pip install homebrew-pypi-poet numpy matplotlib rtree scipy shapely simplejson svg.path

# poetコマンドでFormulaに必要な文言を出力(2個以上のパッケージに依存する場合は-aと共に列挙します)
poet numpy -a matplotlib -a rtree -a scipy -a shapely -a simplejson -a svg.path

# 全部終わったら一時的な仮想環境を消去
deactivate
cd ~ && rm -rf ~/hoge

poetコマンドを実行した結果こんな文が帰ってきます。

flatcam.rb
resource "backports.functools_lru_cache" do
    url "https://files.pythonhosted.org/packages/57/d4/156eb5fbb08d2e85ab0a632e2bebdad355798dece07d4752f66a8d02d1ea/backports.functools_lru_cache-1.5.tar.gz"
    sha256 "9d98697f088eb1b0fa451391f91afb5e3ebde16bbdb272819fd091151fda4f1a"
  end

  resource "Cycler" do
    url "https://files.pythonhosted.org/packages/c2/4b/137dea450d6e1e3d474e1d873cd1d4f7d3beed7e0dc973b06e8e10d32488/cycler-0.10.0.tar.gz"
    sha256 "cd7b2d1018258d7247a71425e9f26463dfb444d411c39569972f4ce586b0c9d8"
  end

  resource "matplotlib" do
    url "https://files.pythonhosted.org/packages/6d/bd/3e8cec37bcf71cfd81fe798cf733c046b1ceb123e7dddf6d3435cf03b506/matplotlib-2.1.2.tar.gz"
    sha256 "725a3f12739d133adfa381e1b33bd70c6f64db453bfc536e148824816e568894"
  end

  resource "numpy" do
    url "https://files.pythonhosted.org/packages/ee/66/7c2690141c520db08b6a6f852fa768f421b0b50683b7bbcd88ef51f33170/numpy-1.14.0.zip"
    sha256 "3de643935b212307b420248018323a44ec51987a336d1d747c1322afc3c099fb"
  end

  resource "pyparsing" do
    url "https://files.pythonhosted.org/packages/3c/ec/a94f8cf7274ea60b5413df054f82a8980523efd712ec55a59e7c3357cf7c/pyparsing-2.2.0.tar.gz"
    sha256 "0832bcf47acd283788593e7a0f542407bd9550a55a8a8435214a1960e04bcb04"
  end

  resource "python-dateutil" do
    url "https://files.pythonhosted.org/packages/54/bb/f1db86504f7a49e1d9b9301531181b00a1c7325dc85a29160ee3eaa73a54/python-dateutil-2.6.1.tar.gz"
    sha256 "891c38b2a02f5bb1be3e4793866c8df49c7d19baabf9c1bad62547e0b4866aca"
  end

  resource "pytz" do
    url "https://files.pythonhosted.org/packages/60/88/d3152c234da4b2a1f7a989f89609ea488225eaea015bc16fbde2b3fdfefa/pytz-2017.3.zip"
    sha256 "fae4cffc040921b8a2d60c6cf0b5d662c1190fe54d718271db4eb17d44a185b7"
  end

  resource "Rtree" do
    url "https://files.pythonhosted.org/packages/b0/6c/6cc8d738f14d5efa0c38ec29403bbd9c75e64b3fe84b53290178dda0dbd9/Rtree-0.8.3.tar.gz"
    sha256 "6cb9cf3000963ea6a3db777a597baee2bc55c4fc891e4f1967f262cc96148649"
  end

  resource "scipy" do
    url "https://files.pythonhosted.org/packages/d0/73/76fc6ea21818eed0de8dd38e1e9586725578864169a2b31acdeffb9131c8/scipy-1.0.0.tar.gz"
    sha256 "87ea1f11a0e9ec08c264dc64551d501fa307289460705f6fccd84cbfc7926d10"
  end

  resource "Shapely" do
    url "https://files.pythonhosted.org/packages/7d/3c/0f09841db07aabf9cc387662be646f181d07ed196e6f60ce8be5f4a8f0bd/Shapely-1.6.4.post1.tar.gz"
    sha256 "30df7572d311514802df8dc0e229d1660bc4cbdcf027a8281e79c5fc2fcf02f2"
  end

  resource "simplejson" do
    url "https://files.pythonhosted.org/packages/0d/3f/3a16847fe5c010110a8f54dd8fe7b091b4e22922def374fe1cce9c1cb7e9/simplejson-3.13.2.tar.gz"
    sha256 "4c4ecf20e054716cc1e5a81cadc44d3f4027108d8dd0861d8b1e3bd7a32d4f0a"
  end

  resource "six" do
    url "https://files.pythonhosted.org/packages/16/d8/bc6316cf98419719bd59c91742194c111b6f2e85abac88e496adefaf7afe/six-1.11.0.tar.gz"
    sha256 "70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9"
  end

  resource "subprocess32" do
    url "https://files.pythonhosted.org/packages/b8/2f/49e53b0d0e94611a2dc624a1ad24d41b6d94d0f1b0a078443407ea2214c2/subprocess32-3.2.7.tar.gz"
    sha256 "1e450a4a4c53bf197ad6402c564b9f7a53539385918ef8f12bdf430a61036590"
  end

  resource "svg.path" do
    url "https://files.pythonhosted.org/packages/1d/6c/cf484a95b895a7acd3989082501c67c8f43b6f91181f2a0b7aa634d1df6f/svg.path-2.2.tar.gz"
    sha256 "bc7b75606e76f910bf0045d09a5f8415aaafff3cedd0a3ce9f0d474fe2007722"
  end

この文章をdepends_onの後に続けて書いておけば良いだけです。後はインストールステップで

flatcam.rb
  include Language::Python::Virtualenv #実際にはclass先頭に書いてます
  def install
    virtualenv_install_with_resources
  end

とやるとHomebrewがよしなにやってくれます。このvirtualenv_install_with_resources

flatcam.rb
venv = virtualenv_create(libexec)
venv.pip_install resources
venv.pip_install_and_link buildpath

のエイリアスになっていて、例えば今回はFlatCAM自体がsetup.pyというファイルを持っているのでpipがそれに従ってリソースファイルの移動などをやってくれるのですが、./configureやmakeなどをしなければいけない場合はよくあるhomebrew formulaのようにsystem "make", "arg1"bin.install("file1")などと組み合わせていく必要があります。

テストと公開

実際にインストール出来るかテストするのに便利なコマンド達を紹介しておきます。

bash
brew info flatcam
brew install --debug flatcam
brew install --interactive flatcam
brew audit --strict flatcam

まずシンタックスエラーがあればbrew infoの時点でエラーが出ます。幾つかWarningもここで出してくれます。brew install --debugはインストール中の情報を全部表示してくれたり、エラーで止まった時にシェルに入れたりします。brew install --interactiveは必要なリソースをDLし展開終わったところでtmpフォルダに移動してシェルに入れます(その後は全部手動です)。brew auditはFormulaのフォーマットとしておかしいところがないかチェックしてくれます。--strictは公式リポジトリにプルリクする時は付けたほうがいいですが野良リポジトリならそこまで気にする必要ない部分まできっちりチェックしてくれます。

で、大丈夫だったら元々flatcam.rbが作られた場所はhomebrew-coreという公式のGitリポジトリそのものなのでこれを置いているとbrew updateなどに支障がでます。適当にフォルダを作って逃がしてやりましょう。

bash
mkdir ~/homebrew-flatcam #適当です
mv /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core/Formula/flatcam.rb ~/homebrew-flatcam

出来上がったらGithub上にhomebrew-xxというリポジトリ名で公開しておきましょう。
brew tap username/xxでtapしてインストールできるようになります。

希望

Formulaの中にpip install hogehogeって書いたらサーバサイドとかでhomebrew-pypi-poetが自動で全部解決して欲しい…

  1. 今回は最終リリース版の8p5というブランチがあったのですが、setup.pyがそれ以降に整備されていたようなのでheadバージョンを使っています。ブランチ指定は本来はいつ変更があるかわからないのでコミット指定の方がいいとは思います…。

6
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?