如何在makefile中获得目标列表?
我曾经使用过rake(一个Ruby make程序),它有一个选项可以获取所有可用目标的列表,例如如何在makefile中获得目标列表?,makefile,gnu-make,targets,Makefile,Gnu Make,Targets,我曾经使用过rake(一个Ruby make程序),它有一个选项可以获取所有可用目标的列表,例如 > rake --tasks rake db:charset # retrieve the charset for your data... rake db:collation # retrieve the collation for your da... rake db:create # Creates the databases defined in y...
> rake --tasks
rake db:charset # retrieve the charset for your data...
rake db:collation # retrieve the collation for your da...
rake db:create # Creates the databases defined in y...
rake db:drop # Drops the database for your curren...
...
但在GNU make中似乎没有这样做的选项
很明显,从2007年开始,代码就差不多在那里了
无论如何,我做了一点小技巧,从makefile中提取目标,您可以将其包含在makefile中
list:
@grep '^[^#[:space:]].*:' Makefile
它将为您提供一个已定义目标的列表。这只是一个开始——例如,它不会过滤掉依赖项
> make list
list:
copy:
run:
plot:
turnin:
我结合了这两个答案:和 并进行了一些转义,以便可以从makefile内部使用
.PHONY: no_targets__ list
no_targets__:
list:
sh -c "$(MAKE) -p no_targets__ | awk -F':' '/^[a-zA-Z0-9][^\$$#\/\\t=]*:([^=]|$$)/ {split(\$$1,A,/ /);for(i in A)print A[i]}' | grep -v '__\$$' | sort"
在Bash下(至少),这可以通过制表符完成自动完成:
make
spacetab如果安装了make
的bash completion,则完成脚本将定义一个函数\u make\u target\u extract\u script
。此函数用于创建一个sed
脚本,该脚本可用于以列表形式获取目标
像这样使用它:
# Make sure bash completion is enabled
source /etc/bash_completion
# List targets from Makefile
sed -nrf <(_make_target_extract_script --) Makefile
.PHONY: target1 # Target 1 help text
target1: deps
[... target 1 build commands]
.PHONY: target2 # Target 2 help text
target2:
[... target 2 build commands]
...
.PHONY: help # Generate list of targets with descriptions
help:
@grep '^.PHONY: .* #' Makefile | sed 's/\.PHONY: \(.*\) # \(.*\)/\1 \2/' | expand -t20
#确保已启用bash完成
来源/etc/bash_完成
#列出Makefile中的目标
sed-nrf这是对以下方面进行改进的尝试:
- 使用一个更健壮的命令来提取目标名称,这有望防止任何误报(同时也消除了不必要的
sh-c
)
- 不总是以当前目录中的makefile为目标;使用
-f
- 排除隐藏目标-按照惯例,这些目标的名称既不以字母开头,也不以数字开头
- 用一个假目标凑合
- 在命令前面加上
@
,以防止在执行前回显该命令
奇怪的是,GNUmake
没有只列出makefile中定义的目标名称的特性。当-p
选项生成包含所有目标的输出时,它将这些目标隐藏在许多其他信息中,并执行默认目标(可以使用-f/dev/null
抑制)
将以下规则放置在GNUmake
的makefile中,以实现名为list
的目标,该目标仅按字母顺序列出所有目标名称,即:调用为makelist
:
.PHONY: list
list:
@$(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null | awk -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' | sort | egrep -v -e '^[^[:alnum:]]' -e '^$@$$'
重要信息:粘贴时,确保最后一行正好缩进1个实际制表符。(空格不起作用)
请注意,对生成的目标列表进行排序是最好的选择,因为不进行排序不会产生有用的排序,因为目标在makefile中的显示顺序不会被保留。
此外,包含多个目标的规则的子目标总是单独输出,因此,由于排序,通常不会出现在彼此旁边;e、 例如,如果存在其他目标,则以a z:
开头的规则将不会在输出中相邻列出目标a
和z
规则解释:
.PHONY: list
list:
@$(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null | awk -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' | sort | egrep -v -e '^[^[:alnum:]]' -e '^$@$$'
- .
PHONY:list
- 声明目标列表为虚假目标,即未引用文件的目标,因此应无条件调用其配方
$(MAKE)-pRrq-f$(lastword$(MAKEFILE_LIST)):2>/dev/null
- 再次调用
make
,以打印和解析从makefile派生的数据库:
-p
打印数据库
-Rr
禁止包含内置规则和变量
-q
仅测试目标的最新状态(无需重新生成任何内容),但这本身并不妨碍在所有情况下执行配方命令;因此:
-f$(lastword$(MAKEFILE_LIST))
确保以原始调用中相同的MAKEFILE为目标,而不管它是以-f…
隐式还是显式为目标
警告:如果makefile包含include
指令,则此命令将中断;要解决此问题,请在任何包含指令之前定义变量此文件:=$(lastword$(MAKEFILE\u LIST))
,并改用-f$(此文件)
。
:
是一个故意无效的目标,用于确保不执行任何命令<代码>2>/dev/null
抑制生成的错误消息。注意:这依赖于-p
打印数据库,GNU make 3.82就是这种情况。遗憾的是,gnumake没有提供直接选项来打印数据库,也没有执行默认(或给定)任务;如果不需要针对特定的Makefile,可以使用make-p-f/dev/null
,如man
页面中所建议的那样
-vrs=
- 这是一个awk习惯用法,它将输入分成连续的非空行块
/^文件/,/^成品制作数据库/
- 匹配包含所有目标的输出中的行范围(自GNU make 3.82起为true)-通过将解析限制在此范围内,无需处理来自其他输出部分的误报
if($$1!~“^[#.]”)
- 选择性地忽略块:
。。。忽略非目标,其块以#
开头#不是目标:
。。。忽视特殊目标
- 所有其他块都应以一行开头,该行仅包含明确定义的目标的名称,后跟
:
egrep-v-e'^[^[:alnum:]'-e'^$@$$'
从输出中删除不需要的目标:
。。。排除隐藏目标,根据惯例-“^[^[:alnum:][]”
list: cat Makefile | grep "^[A-z]" | awk '{print $$1}' | sed "s/://g"
$ make help The following are some of the valid targets for this Makefile: ... all (the default if no target is provided) ... clean ... depend ... install etc
.PHONY: target1 # Target 1 help text target1: deps [... target 1 build commands] .PHONY: target2 # Target 2 help text target2: [... target 2 build commands] ... .PHONY: help # Generate list of targets with descriptions help: @grep '^.PHONY: .* #' Makefile | sed 's/\.PHONY: \(.*\) # \(.*\)/\1 \2/' | expand -t20
$ make help target1 Target 1 help text target2 Target 2 help text ... help Generate list of targets with descriptions
cat Makefile | egrep "^[[:alnum:][:punct:]]{0,}:[[:space:]]{0,}[[:alnum:][:punct:][:space:]]{0,}$"
make -p 2&>/dev/null | grep -A 100000 "# Files" | grep -v "^$" | grep -v "^\(\s\|#\|\.\)" | grep -v "Makefile:" | cut -d ":" -f 1
.PHONY: list ls ls list : @# search all include files for targets. @# ... excluding special targets, and output dynamic rule definitions unresolved. @for inc in $(MAKEFILE_LIST); do \ echo ' =' $$inc '= '; \ grep -Eo '^[^\.#[:blank:]]+.*:.*' $$inc | grep -v ':=' | \ cut -f 1 | sort | sed 's/.*/ &/' | sed -n 's/:.*$$//p' | \ tr $$ \\\ | tr $(open_paren) % | tr $(close_paren) % \ ; done # to get around escaping limitations: open_paren := \( close_paren := \)
= Makefile = includes ls list = util/kiss/snapshots.mk = rotate-db-snapshots rotate-file-snapshots snap-db snap-files snapshot = util/kiss/main.mk = dirs install %MK_DIR_PREFIX%env-config.php %MK_DIR_PREFIX%../srdb
.PHONY: all all: build : "same as 'make build'" .PHONY: build build: @echo "Build the project" .PHONY: clean clean: @echo "Clean the project" .PHONY: help help: @echo -n "Common make targets" @echo ":" @cat Makefile | sed -n '/^\.PHONY: / h; /\(^\t@*echo\|^\t:\)/ {H; x; /PHONY/ s/.PHONY: \(.*\)\n.*"\(.*\)"/ make \1\t\2/p; d; x}'| sort -k2,2 |expand -t 20
$ make help Common make targets: make all same as 'make build' make build Build the project make clean Clean the project make help Common make targets
cat Makefile | awk '!/SHELL/ && /^[A-z]/ {print $1}' | awk '{print substr($0, 1, length($0)-1)}'
install_targets = install-xxx1 install-xxx2 ... etc
make -qp | awk -F':' '/^[a-zA-Z0-9][^$#\/\t=]*:([^=]|$)/ {split($1,A,/ /);for(i in A)print A[i]}'
make -qp | awk -F':' '/^[a-zA-Z0-9][^$#\/\t=]*:([^=]|$)/ {split($1,A,/ /);for(i in A)print A[i]}' | sort -u
help: @grep -B1 -E "^[a-zA-Z0-9_-]+\:([^\=]|$$)" Makefile \ | grep -v -- -- \ | sed 'N;s/\n/###/' \ | sed -n 's/^#: \(.*\)###\(.*\):.*/\2###\1/p' \ | column -t -s '###' #: Starts the container stack up: a b command #: Pulls in new container images pull: c d another command make-target-not-shown: # this does not count as a description, so leaving # your implementation comments alone, e.g TODOs also-not-shown:
> make help up Starts the container stack pull Pulls in new container images
grep : Makefile | awk -F: '/^[^.]/ {print $1;}'
help: make -qpRr $(lastword $(MAKEFILE_LIST)) | egrep -v '(^(\.|:|#|\s|$)|=)' | cut -d: -f1
RANDOM_VARIABLE := this will be expanded in help text .PHONY: target1 # Target 1 help with $(RANDOM_VARIABLE) target1: deps [... target 1 build commands] # TARGETDOC: $(BUILDDIR)/real-file.txt # real-file.txt help text $(BUILDDIR)/real-file.txt: [... $(BUILDDIR)/real-file.txt build commands]
.PHONY: help # Generate list of targets with descriptions help: @# find all help in targets and .PHONY and evaluate the embedded variables $(eval doc_expanded := $(shell grep -E -h '^(.PHONY:|# TARGETDOC:) .* #' $(MAKEFILE_LIST) | sed -E -n 's/(\.PHONY|# TARGETDOC): (.*) # (.*)/\2 \3\\n/'p | expand -t40)) @echo @echo ' TARGET HELP' | expand -t40 @echo ' ------ ----' | expand -t40 @echo -e ' $(doc_expanded)'
# vim:ft=make # Makefile .DEFAULT_GOAL := help .PHONY: test help help: ## these help instructions @sed -rn 's/^([a-zA-Z_-]+):.*?## (.*)$$/"\1" "\2"/p' < $(MAKEFILE_LIST) | xargs printf "make %-20s# %s\n" lint: ## style, bug and quality checker pylint src test private: # for internal usage only @true test: private ## run pytest with coverage pytest --cov test
$ make make help # these help instructions make lint # style, bug and quality checker make test # run pytest with coverage
APPS?=app1 app2 bin: $(APPS:%=%.bin) @# Help: A composite target that relies only on other targets $(APPS:%=%.bin): %.bin: echo "build binary" @# Help: A target with variable name, value = $* test: echo $(MAKEFLAGS) echo "starting test" @# Help: A normal target without variables # A target without any help description clean: echo $(MAKEFLAGS) echo "Cleaning..." MAKEOVERRIDES = help: @printf "%-20s %s\n" "Target" "Description" @printf "%-20s %s\n" "------" "-----------" @make -pqR : 2>/dev/null \ | awk -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' \ | sort \ | egrep -v -e '^[^[:alnum:]]' -e '^$@$$' \ | xargs -I _ sh -c 'printf "%-20s " _; make _ -nB | (grep -i "^# Help:" || echo "") | tail -1 | sed "s/^# Help: //g"'
$ make help Target Description ------ ----------- app1.bin A target with variable name, value = app1 app2.bin A target with variable name, value = app2 bin A composite target that relies only on other targets clean test A normal target without variables
help: @echo "\nTARGETS:\n" @make -qpRr | egrep -e '^[a-z].*:$$' | sed -e 's~:~~g' | sort @echo ""