makefileにhelpを付けるワンライナー
makeファイルはデフォルトではhelpが存在しない。bashの補完の設定などを入れているとタブで利用可能なタスクの一覧が出る環境もあるが、その設定もしていない場合には利用可能なタスクの一覧も表示できない。
タスクに対するcommentの流派
似たようなことを考える人はいるもので、help
というタスク(ターゲット)を定義してhelpメッセージを表示しようという試みをしている人たちがいる。
ちょっとだけ検索してみた所以下の2つの流派があるみたい。
<task>: ## <comment>
派
- https://marmelab.com/blog/2016/02/29/auto-documented-makefile.html (和訳)
- https://qiita.com/po3rin/items/7875ef9db5ca994ff762
- https://gist.github.com/prwhite/8168133
- https://nedbatchelder.com/blog/201804/makefile_help_target.html
## <comment>\n<task>:
派
<task>: ## <comment>
派が多いように見えたけれど、概ね元となる一番上の記事のコピーのようだった。
雰囲気
前者は(<task>: ## <comment>
派) 以下の様に書く形。依存するターゲットがあった場合には ##
の前に書く。
task0: ## comment of task0 .. do something task1: ## comment of task1 .. do something task2: task0 task1 ## comment of task2 .. do something
後者(## <comment>\n<task>:
派)は以下の様に書く形。依存の記述方法で特に気をつけることは存在しない。
## comment of task0 task0: .. do something ## comment of task1 task1: .. do something ## comment of task2 task2: task0 task1 .. do something
個人的には、後者(## <comment>\n<task>:
派)の方が良いのだけれど。これを導入するために新たなコマンドのインストールが必要というのは微妙だなーと思ったりした。
.DEFAULT_GOAL
と MAKEFILE_LIST
ちなみにこれはtips的な話だけれど。両者は共に.DEFAULT_GOAL
と MAKEFILE_LIST
を使っている。
.DEFAULT_GOAL
.DEFAULT_GOAL
は引数無しで make
を実行した時に実行されるターゲットのこと。
.DEFAULT_GOAL := bar foo: @echo foo bar: @echo bar
ちなみにこれは、-p
(--print-data-base
)オプションで調べられる
$ make -p | grep -i default_goal .DEFAULT_GOAL := bar
そして通常は先頭のタスク。
--- 00defaultgoal/Makefile 2019-04-15 21:58:29.207999840 +0900 +++ 01defaultgoal/Makefile 2019-04-15 21:58:24.384597546 +0900 @@ -1,5 +1,3 @@ -.DEFAULT_GOAL := bar - foo: @echo foo bar:
.DEFAULT_GOAL := bar
の指定がない時にはfoo
$ make -p | grep -i default_goal .DEFAULT_GOAL := foo
MAKEFILE_LIST
これはmakeで渡されたファイルのこと。通常はMakefile
なりmakefile
などが入る。ファイル名を気にせずタスクを記述できるようになっている。
build.mk
default: echo @@ $(MAKEFILE_LIST) @@
例えば以下の様に -f
付きでファイルを指定したときなどに値が変わる。
$ make -f build.mk echo @@ build.mk @@ @@ build.mk @@
ちなみに同様のものとして $(MAKE)
というものもある。
## <comment>\n<task>:
をワンライナーで
個人的には ## <comment>\n<task>:
の方がMakefileとしては扱いやすい気がするので好みなのだけれど、気持ちparseするのが面倒なので正直な所unixのコマンドの範囲だとツライ。なにかテキトーなLLでのワンライナーでやってしまいたくなる。
このあたりになるとお里が知れるという感じになるかもしれない。
python自体はワンライナーに向いている言語ではないけれど、慣れているのでpythonでやってみる。rubyで言うeash_consに似たものを作るのにitertoolsのteeとchainを使うのはかなりオーバーエンジニアリング(?)感がある。まぁどこにでもpythonくらいは入っていそうなので。
help: @cat $(MAKEFILE_LIST) | python -u -c 'import sys; import re; from itertools import tee,chain; rx = re.compile(r"^[a-zA-Z0-9\-_]+:"); xs, ys = tee(sys.stdin); xs = chain([""], xs); [print(f"""\x1b[36m{line.split(":", 1)[0]:20s}\x1b[0m\t{prev.lstrip("# ").rstrip() if prev.startswith("##") else "" }""") for prev, line in zip(xs, ys) if rx.search(line)]'
一応こんな感じで表示される様になる。
ちなみに個人的にはソートされずにファイルに記述された順序でhelpメッセージが出るほうが好きだったりします。
横着な人のための逆引きpipでpackageをinstallするときの細かな試行錯誤のメモ
横着な人(自分)のためのpipのメモ。
試行錯誤のためのフレッシュな環境が欲しい
正に今がそれ。pipの実行を試すために /tmp/foo
に仮想環境を作る。
$ mkdir -p /tmp/foo $ python -m venv /tmp/foo $ cd /tmp/foo
activateせずに直接./bin/pip
や./bin/python
で使っても良い(存在しない場合はエラーになるのでバッチなどで指定する場合にはむしろこの方が良いと思っていたりする)。
前提
$ python -V Python 3.7.2
現在のインストール対象のパッケージ(marshmallow)は以下の様な状態
name | version | status |
---|---|---|
marshmallow | 2.19.1 | 古い |
marshmallow | 2.19.2 | pypiで最新(stable) |
marshmallow | 3.0.0rc5 | pypiで最新(pre-release) |
marshmallow | 3.0.0rc5 | githubのdevブランチ上のコード |
mecab-python | 0.996 | 壊れている |
mecab-python3 | 0.996.1 | python3でinstall可能 |
packageのinstall
versionを指定してのinstallは==
$ pip install marshmallow==2.19.1
installされているpackageのversionが知りたい
pip freezeとgrep
$ pip freeze marshmallow==2.19.1
outdatedなpackageを探したい場合はlist --outdated
$ pip list --outdated Package Version Latest Type ----------- ------- ------ ----- marshmallow 2.19.1 2.19.2 wheel pip 18.1 19.0.3 wheel setuptools 40.6.2 41.0.0 wheel You are using pip version 18.1, however version 19.0.3 is available. You should consider upgrading via the 'pip install --upgrade pip' command.
pip自体の更新もあった。
packageの更新をしたい場合には --upgrade
--upgrade
を付けないと新しいバージョンが存在してもpackageをupdateしてくれない。
$ pip install marshmallow Requirement already satisfied: marshmallow in ./lib/python3.7/site-packages (2.19.1)
--upgrade
付きで実行でupdate
$ pip install --upgrade marshmallow pip $ pip freeze marshmallow==2.19.2
(細かい話で--upgrade-strategy
などもあるが省略)
constraintsの指定はconstraints.txt
constraintsを満たしていたら何もしない
$ echo "marshmallow>2.19" >> constraints.txt $ pip install marshmallow -c constraints.txt Requirement already satisfied: marshmallow>2.19 in ./lib/python3.7/site-packages (from -c constraints.txt (line 1)) (2.19.1)
packageをどうしても特定のpackageのversionにしたい場合には --force-reinstall
versionを直接してinstallしようとしてもdowngradeはできない。
$ pip install --upgrade -c constraints.txt marshmallow==2.19.1 Requirement already satisfied: marshmallow>2.19 in ./lib/python3.7/site-packages (from -c constraints.txt (line 1)) (2.19.2) $ pip install -c constraints.txt marshmallow==2.19.1 Requirement already satisfied: marshmallow>2.19 in ./lib/python3.7/site-packages (from -c constraints.txt (line 1)) (2.19.2) $ pip freeze marshmallow==2.19.1
--force-reinstall
を付ける
$ pip install --force-reinstall -c constraints.txt marshmallow==2.19.2 $ pip freeze marshmallow==2.19.2
githubのrepositoryなどにアクセスする場合
VCSで管理されているpackageから直接リポジトリを指定してinstallする方法は幾つかある(@<branch>
で該当するブランチを指定)。
以下はgithubの例。
$ pip install "git+ssh://git@github.com/marshmallow-code/marshmallow.git@dev#egg=marshmallow" $ pip install "git+https://github.com/marhshmallow-code/marshmallow.git@dev#egg=marshmallow" $ pip install "git+git://github.com/marhshmallow-code/marshmallow.git@dev#egg=marshmallow"
場合によっては --upgrade
や --force-reinstall
が必要。
$ pip install --upgrade "git+ssh://git@github.com/marshmallow-code/marshmallow.git@dev#egg=marshmallow" $ pip freeze marshmallow==3.0.0rc5
特定のrepositoryのsubdirectoryにある場合
&subdirectory=<subdirectory>
という形で指定する。
$ pip "git+https://github.com/marhshmallow-code/marshmallow.git@dev#egg=marshmallow&subdirectory=<subdirectory>"
詳しくはこのあたり
元に戻したい場合
元のpypiに登録されているpackageに戻したい場合には --force-reinstall
を指定してあげれば良い。
$ pip install marshmallow --force-reinstall marshmallow==2.19.2
pre-release packageを指定したい場合
--pre
を付ける。
$ pip install --upgrade --pre marshmallow $ pip freeze marshmallow==3.0.0rc5
pre-releasepackageかどうかはversionの付け方で決まる。詳しくはこのあたり
packageをdownloadだけしたい
pip download
でできる。
$ pip download marshmallow $ ls marshmallow-2.19.2-py2.py3-none-any.whl marshmallow-2.19.2-py2.py3-none-any.whl
packageのinstallが失敗した場合の対処方法
$ pip install mecab-python Collecting mecab-python Using cached https://files.pythonhosted.org/packages/86/e7/bfeba61fb1c5d1ddcd92bc9b9502f99f80bf71a03429a2b31218fc2d4da2/mecab-python.tar.gz Complete output from command python setup.py egg_info: /bin/sh: mecab-config: command not found Traceback (most recent call last): File "<string>", line 1, in <module> File "/tmp/pip-install-d9mp9gn_/mecab-python/setup.py", line 13, in <module> version = cmd1("mecab-config --version"), File "/tmp/pip-install-d9mp9gn_/mecab-python/setup.py", line 7, in cmd1 return os.popen(str).readlines()[0][:-1] IndexError: list index out of range ---------------------------------------- Command "python setup.py egg_info" failed with error code 1 in /tmp/pip-install-d9mp9gn_/mecab-python/
詳しく状況をトレースしたい場合には -v
などを付ける。
$ pip install -v mecab-python # 標準出力以外にもログを残したい場合には --log $ pip instal --log=x.log mecab-python
エラー対応の試行錯誤には --no-clean
ふつうにpip install
をして失敗したときには、かっこいいことに、エラーメッセージで言及されているディレクトリが消されている!!
このエラーメッセージ部分の /tmp
Command "python setup.py egg_info" failed with error code 1 in /tmp/pip-install-d9mp9gn_/mecab-python/
探してみるとない。
$ ls /tmp/pip-install-d9mp9gn_/mecab-python/ ls: cannot access '/tmp/pip-install-d9mp9gn_/mecab-python/': No such file or directory
--no-clean
を付けると消さずに残してくれる。
$ pip install --no-clean mecab-python $ ls /tmp/pip-install-xjdxqail/mecab-python/ MeCab.py PKG-INFO pip-delete-this-directory.txt setup.py MeCab_wrap.cxx README pip-egg-info
なのでここでgit管理して手元で試行錯誤するのが早い。
$ cd /tmp/pip-install-xjdxqail/mecab-python/ $ git init $ git add . $ git commmit -m hmm $ pip install -e . Command "python setup.py egg_info" failed with error code 1 in /tmp/pip-install-xjdxqail/mecab-python/
暗黙に依存したpackageをインストールしない方法
依存packageのinstallを止めたい場合は --no-deps
を付ける。
$ pip install --no-deps statsmodels Collecting statsmodels Using cached https://files.pythonhosted.org/packages/3c/68/bebc0f0e412fc8375f7daffc7ec2946acc20ac1a55fb4949098df23b9768/statsmodels-0.9.0-cp37-cp37m-manylinux1_x86_64.whl Installing collected packages: statsmodels Successfully installed statsmodels-0.9.0
本来は以下の様な感じに
$ pip install --cache-dir=xxx statsmodels ... Installing collected packages: numpy, six, patsy, python-dateutil, pytz, pandas Successfully installed numpy-1.16.2 pandas-0.24.2 patsy-0.5.1 python-dateutil-2.8.0 pytz-2019.1 six-1.12.0
参考
まじめな人はこのあたりを全部読むと良い
- https://packaging.python.org/tutorials/installing-packages/
- https://pip.pypa.io/en/stable/user_guide
- https://pip.pypa.io/en/stable/reference/pip_install
あと拡張packageのbuildが壊れた時にどうやって直すかは昔書いていた