Makefile调用linter脚本失败 如何正确实现make lint命令
直接通过全路径调用linter失效,是因为linter脚本内部通过相对路径引用自身依赖的配置、附属工具文件。Make执行命令时的默认工作目录是你执行make命令所在的目录(通常是项目根目录),不是linter脚本自身的存放目录,导致脚本运行时找不到依赖资源报错。
你之前用分号连接cd和脚本执行的写法可以运行,但存在隐患:如果cd操作执行失败(比如目录不存在、权限不足),后续的linter命令依然会在错误的目录下执行,容易引发不可预期的问题。
按推荐优先级排序:
方案1:改造linter脚本(一劳永逸,最符合规范)
直接修改linter脚本,让它内部所有路径都基于脚本自身的存放位置解析,不依赖执行时的工作目录,这样就不需要在Makefile中做任何目录切换操作。
如果linter是Shell脚本,在脚本开头添加如下逻辑固定脚本自身目录即可:
#!/bin/bash # 获取脚本自身所在的绝对目录,不依赖执行时的工作路径 SCRIPT_PATH=$(readlink -f "${BASH_SOURCE[0]}") SCRIPT_DIR=$(dirname "$SCRIPT_PATH") # 后续所有引用同目录下资源的路径,都加上$SCRIPT_DIR前缀 # 示例:加载同目录下的lint规则配置,就写 source $SCRIPT_DIR/rules.sh
改造完成后,你最开始的全路径调用写法就可以正常运行:
.PHONY: lint lint: $(ROOT)/tools/Manage/linter
注意:你原来的写法里路径前多了冗余的
./和额外的/,如果$(ROOT)是项目相对路径,开头加/会从系统根目录开始寻址,很容易出现路径找不到的问题,直接去掉冗余前缀即可。
方案2:使用&&连接目录切换和执行命令(无侵入,通用惯例)
如果不想修改linter脚本,可以用&&替代分号连接cd和执行命令,只有目录切换成功后才会执行后续linter,避免cd失败导致的异常执行。Makefile中同一行的命令会在同一个子Shell中执行,目录切换仅对当前行的命令生效,不会影响Makefile其他任务的工作目录,是行业内通用的标准写法,不存在不符合规范的问题:
.PHONY: lint lint: cd $(ROOT)/tools/Manage && ./linter
注意:不要把cd和linter调用分成两行写,Makefile中每一行命令默认在独立的子Shell中执行,单独写一行cd不会对下一行的命令工作目录产生任何影响,属于常见写法错误。
方案3:传入工作目录参数(适合支持自定义路径的linter)
如果你的linter本身支持指定工作目录/项目根目录的参数,可以直接传入Make内置的CURDIR变量(代表执行make时的项目根目录绝对路径),不需要切换目录即可让linter正确找到资源:
.PHONY: lint lint: $(ROOT)/tools/Manage/linter --root=$(CURDIR)
- Makefile中所有命令行的缩进必须使用Tab制表符,不能用空格,否则会触发语法错误
- 拼接路径时不要随意在变量前加
/前缀,除非你明确需要使用系统根目录下的绝对路径 - 尽量避免在命令中使用相对路径的
./前缀拼接变量路径,容易出现路径拼接错误
内容的提问来源于stack exchange,提问作者Dev_Seb

