Python 自动化杂录: Makefile 等

Makefile

直接看原文

一个 Makefile 由若干条 rules 组成. 每条 rule 语法如下. 注意 recipes 前面要用 tab 而不是空格.

target1 [target2 ...]: [pre-req1 pre-req2 pre-req3 ...]
	[recipes
	...]

注意

  • 默认用 sh 而不是 bash, 可以通过 SHELL = /bin/bash 设置. 关于 :== 的区别, 参考 这个回答这个例子.
  • 默认 recipes 中每行都会开新的 sub-shell, 见 这里. 可以通过 .ONESHELL: 设置, 参考 这里 (为什么默认不是 oneshell).
  • recipes 中 command expansion 要加上 shell (待确认其他做法), 比如 $(shell ls), 见 这里.
  • shell 中的 $ 需要转义, 见 这里这里. 记得在 for 循环的时候用 $$.

其他语法略.

下面的例子来自 pandas (.PHONY 和不关心的项略了). 现在 pandas 已删除该文件, 可通过 查找 git 历史, 发现 这个更新 10 月 5 日删除了 Makefile.

all: develop

develop: build
	python -m pip install --no-build-isolation -e .
	
build: clean_pyc
	python setup.py build_ext

clean_pyc:
	-find . -name '*.py[co]' -exec rm {} \;
	
clean:
	-python setup.py clean
	
lint-diff:
	git diff upstream/main --name-only -- "*.py" | xargs flake8

black:
	black .

test-scripts:
	pytest scripts

其中 recipes 中开头的 - means ignore the exit status of the command that is executed (normally, a non-zero exit status would stop that part of the build). 参考 makefile - What do @, - and + do as prefixes to recipe lines in Make? - Stack Overflow

clean_pyc 中

-exec command {} ;

{} is a symbolic representation of the current pathname, and the semicolon is a required delimiter indicating the end of the command.

-exec rm '{}' ';'

另外可参考 find . -name -exec rm {} \; - 16bit

此外还有有趣的用法比如 streamlit

.PHONY: help
help:
	@# Magic line used to create self-documenting makefiles.
	@# See https://stackoverflow.com/a/35730928
	@awk '/^#/{c=substr($$0,3);next}c&&/^[[:alpha:]][[:alnum:]_-]+:/{print substr($$1,1,index($$1,":")),c}1{c=0}' Makefile | column -s: -t

.PHONY: all
# Get dependencies, build frontend, install Streamlit into Python environment.
all: init frontend install

它的 Makefile 很长, 可以参考一些写法.

其他自动化组件

TODO