为什么Makefile使用变量时不构建依赖项,写死显式路径却可以正常工作?
Makefile 变量依赖不生效问题原因及解决方案
核心原因
问题出在GNU Make的变量展开时机和你写的变量定义顺序不匹配:
- Make解析阶段会立即展开所有目标、依赖列表里的变量,只有目标对应的执行脚本(recipe)里的变量会等到执行阶段再展开
- 你的代码里变量定义顺序是错的:
- 先定义
IDL_HEADERS、IDL_CPPS时,IDL_INPUTS还没有被赋值,所以这两个变量在解析阶段是空值 - 随后定义
all: $(IDL_HEADERS) $(IDL_CPPS)时,依赖列表立即展开为空,相当于all没有任何依赖,所以make判定没有任务需要执行 - 最后才给
IDL_INPUTS追加内容,此时all的依赖列表已经解析完成,追加的内容不会生效 - 执行脚本里的
info打印是执行阶段才展开变量,此时IDL_INPUTS已经有值,所以会出现「打印出来依赖存在,但实际没有执行生成动作」的矛盾,和你补充测试里$^(实际依赖列表)为空的现象完全吻合。
- 先定义
- 直接写死依赖能正常运行,是因为不需要展开变量,Make解析阶段就能直接识别到依赖的文件,再匹配到你写的模式规则触发生成逻辑。
修复方法
调整变量定义顺序,先给IDL_INPUTS赋值,再推导输出文件变量、定义all目标即可,示例如下:
# 第一步:先定义所有IDL输入文件 IDL_INPUTS += ../idl/common_api/CommonTypes.yml # 第二步:根据输入文件推导输出的头文件、cpp文件列表 IDL_HEADERS=$(IDL_INPUTS:../idl/%.yml=../api/%.h) IDL_CPPS=$(IDL_INPUTS:../idl/%.yml=../api/%.cpp) # 第三步:定义模式生成规则(顺序不影响,只要在用到之前定义即可) ../api/%.h ../api/%.cpp : ../idl/%.yml $(info Generating api files from $<) $(IDL_TO_CPP_EXE) --input $< --output $(basename $@) # 第四步:定义all目标 all: $(IDL_HEADERS) $(IDL_CPPS) $(info The dependencies are $^)
内容的提问来源于stack exchange,提问作者fizzybones
相关产品推荐
相关产品推荐

