You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何先编译程序再将其输出作为Makefile变量值?

问题描述

需要写一个Makefile实现以下流程:

  1. 先编译print_name程序
  2. 把该程序的标准输出作为目录名,用于后续编译规则
  3. 执行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

相关代码如下:

#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

逻辑说明

  1. 第一次跑make all,先执行print_name规则编译出可执行文件
  2. 通过$$(./print_name)获取程序输出的目录名,再用$(MAKE)递归调用自身,把目录名通过DIR=$$DIR传递给新的Make进程
  3. 新的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 08:15:36