如何先编译程序再将其输出作为Makefile变量值?
问题描述
需要写一个Makefile实现以下流程:
- 先编译
print_name程序 - 把该程序的标准输出作为目录名,用于后续编译规则
- 执行
make all时,期望自动跑mkdir -p foo和gcc my_program.c -o foo/my_program
但当前写法执行make all时报错:
make: *** No rule to make target '/my_program', needed by 'all'. Stop
相关代码如下:
print_name.c
#include <stdio.h> int main() { printf("foo\n"); return 0; }
尝试的Makefile代码
all: $(MY_DIRECTORY_NAME)/my_program print_name: print_name.c | print_name gcc $^ -o $@ MY_DIRECTORY_NAME:=$(shell ./print_name) $(MY_DIRECTORY_NAME)/my_program: my_program.c mkdir -p $(MY_DIRECTORY_NAME) gcc $^ -o $@
解决方案
原写法的问题很明确:
$(shell ./print_name)是在Makefile解析阶段就执行的,这时候print_name还没编译,所以变量MY_DIRECTORY_NAME是空值,导致all的依赖变成/my_program,直接报错print_name规则里的| print_name是循环依赖,完全多余
要实现“先编译程序再拿目录名”的需求,不能用静态变量赋值,得用递归调用Makefile的方式,具体写法如下:
正确的Makefile
# 首次执行时先编译print_name,再递归传参调用 all: print_name @DIR=$$(./print_name); $(MAKE) --no-print-directory DIR=$$DIR real_all # 编译print_name程序 print_name: print_name.c gcc $^ -o $@ # 递归调用时执行的实际构建目标 real_all: $(DIR)/my_program # 创建目标目录并编译my_program $(DIR)/my_program: my_program.c mkdir -p $(DIR) gcc $^ -o $@ # 清理生成的文件和目录 clean: rm -f print_name rm -rf foo
逻辑说明
- 第一次跑
make all,先执行print_name规则编译出可执行文件 - 通过
$$(./print_name)获取程序输出的目录名,再用$(MAKE)递归调用自身,把目录名通过DIR=$$DIR传递给新的Make进程 - 新的Make进程里
DIR变量已经有正确值,会执行real_all目标,完成目录创建和my_program的编译
验证效果
执行make all后,会输出:
gcc print_name.c -o print_name mkdir -p foo gcc my_program.c -o foo/my_program
完全符合预期。
内容的提问来源于stack exchange,提问作者111111
相关产品推荐
相关产品推荐

