gmake是否会自动定义$(INSTALL)变量?Makefile使用问题咨询
问题解答
1. $(INSTALL) 是否有默认值
GNU Make 没有为$(INSTALL)设置内置默认值,这和内置预定义的$(CC)(默认值为cc)、$(CFLAGS)这类编译相关变量不同。
你看到很多示例Makefile没有显式定义该变量,通常是因为这些Makefile由Autotools、CMake等构建工具自动生成,构建工具会在生成阶段注入INSTALL相关变量;部分手写Makefile省略定义属于不严谨写法,会直接触发你遇到的错误——从运行日志可以看到,$(INSTALL)展开后为空,执行的命令直接变成了/home/<username>/ helloworld,最终触发权限错误。
2. $(INSTALL) 相关最佳实践
手写Makefile时建议按以下规则处理安装逻辑:
- 用条件赋值符
?=给INSTALL设置兜底值,允许用户在执行make时通过命令行参数自定义覆盖,标准写法为INSTALL ?= install - 按文件类型拆分专用安装变量,避免每次写安装命令时重复加权限参数:
- 可执行程序:
INSTALL_PROGRAM ?= $(INSTALL) -m 755(默认赋予可执行权限) - 普通文档、配置、数据文件:
INSTALL_DATA ?= $(INSTALL) -m 644(默认去除可执行权限) - 目录创建:
INSTALL_DIR ?= $(INSTALL) -d(自动递归创建不存在的父目录)
- 可执行程序:
- 安装路径支持
DESTDIR、prefix这类标准变量,方便做分阶段安装、自定义安装路径,不要硬编码${HOME}/这类绝对路径 - 注意
install命令的参数顺序:源文件在前,目标路径在后,示例中参数顺序写反了,也是触发错误的原因之一。
修正后的最小可用示例Makefile如下:
INSTALL ?= install INSTALL_PROGRAM ?= $(INSTALL) -m 755 helloworld: echo 'hello, world' > helloworld chmod +x helloworld install: helloworld $(INSTALL_PROGRAM) helloworld $(HOME)/
3. 为什么优先用install而非cp
install是POSIX标准中专门为软件安装场景设计的命令,相比通用的cp有明显优势:
- 复制文件的同时可以直接设置文件权限、属主、属组,不需要复制后额外调用
chmod、chown,精简安装步骤 - 替换目标位置已存在的文件时,会先写入临时文件再完成原子替换,不会出现
cp直接覆盖正在运行的可执行文件时触发的「Text file busy」错误 - 自带
-d参数支持递归创建目录,不需要额外调用mkdir -p - 跨Unix-like系统的行为一致性更高,比不同发行版带不同扩展参数的
cp可移植性更好。
问题复现参考
原始错误Makefile
helloworld: echo 'hello, world' >helloworld install: $(INSTALL) ${HOME}/ helloworld
运行错误日志
$ make helloworld $ make install /home/<username>/ helloworld make: /home/kevins/: Permission denied make: *** [Makefile:5: install] Error 127
环境版本
GNU Make 4.3
Built for x86_64-pc-linux-gnu
内容的提问来源于stack exchange,提问作者kevinnlsamuel
相关产品推荐
相关产品推荐

