我基本上是在研究一个有问题的makefile,这让我对以下情况感到困惑。
default:
echo "Build started with $@ at $(ENV_VAR)";\
ENV_VAR=$(NEW_DIR); \
cd $(ENV_VAR); \
$(MAKE);
程序员的目标:
程序员基本上打算用新值(目录路径) NEW_DIR 覆盖环境变量 ENV_VAR ,然后在该目录中以递归方式执行make。
此makefile中的错误:
我看到的错误是编码器使用“cd $(ENV_VAR)”而不是“cd $$(ENV_VAR)”。因此,我们实际上并没有在“cd”命令中使用overriden make变量,而是在执行$(MAKE)之前仍然使用环境变量的值。 cd命令也因为不存在的路径而失败。最后我们最终做了递归make。
我的问题
正如我在上一段中所提到的,我们处于递归make的场景中。有趣的是,我看到第二次调用相同的目标时,我看到$(ENV_VAR)反映了NEW_DIR的覆盖值。这让我感到困惑。
示例输出:
假设:
NEW_DIR = / new-dir OLD-DIR = / old-dir
输出:
Build started with default at /old-dir
bin/sh /old-dir: no such file (or) directory
Build started with default at /new-dir
对此有任何建议。
答案 0 :(得分:1)
$(ENV_VAR)
不对,你是对的。但$$(ENV_VAR)
也不正确。
make扩展命令中的变量,然后将命令传递给shell,后者执行自己的扩展。所以
default:
echo "Build started with $@ at $(ENV_VAR)";\
ENV_VAR=$(NEW_DIR); \
cd $(ENV_VAR); \
$(MAKE);
成为shell命令
echo "Build started with $@ at /old_dir";\
ENV_VAR=/new_dir; \
cd /old_dir; \
make
此命令尚未执行;这项任务尚未进行,而且已经太晚了。
建议的解决方案也不起作用。这样:
default:
echo "Build started with $@ at $(ENV_VAR)";\
ENV_VAR=$(NEW_DIR); \
cd $$(ENV_VAR); \
$(MAKE);
成为这个:
echo "Build started with $@ at /old_dir";\
ENV_VAR=/new_dir; \
cd $(ENV_VAR); \
make
这看起来不错,但请注意cd $(ENV_VAR);
是 Make 语法,而不是shell语法(至少不是bash)。正确的shell语法是cd $ENV_VAR
,因此规则应为:
default:
echo "Build started with $@ at $(ENV_VAR)";\
ENV_VAR=$(NEW_DIR); \
cd $$ENV_VAR; \
$(MAKE);
根据the manual,“默认情况下,只有来自环境或命令行的变量才会传递给递归调用”(但如果您选择,则可以覆盖此行为)。由于ENV_VAR
是一个环境变量,它将被传递给子make,如果你在命令shell中修改它,sub-make将收到修改后的值。
最后,我建议你这样试试:
default:
echo "Build started with $@ at $(ENV_VAR)";
Make -C $(NEW_DIR) ENV_VAR=$(NEW_DIR);