【问题标题】:Not all variables recursively expanded in Makefile并非所有变量都在 Makefile 中递归扩展
【发布时间】:2018-06-27 08:52:31
【问题描述】:

我只是在玩 Makefile,我试图理解为什么有些变量会扩展两次,而另一些变量只扩展一次。假设以下 Makefile:

FILE := $(shell mktemp)
TEMP = $(shell mktemp)
CONTENTS = $(shell cat $(FILE))
test:
    echo $(TEMP)
    echo $(CONTENTS)
    echo test > $(FILE)
    echo $(CONTENTS)
    echo $(TEMP)

运行 make test 输出以下内容:

echo /tmp/tmp.ZWFtOiCG9v
/tmp/tmp.ZWFtOiCG9v
echo

echo test > /tmp/tmp.FEubzF4Gwa
echo

echo /tmp/tmp.OIKSGVvY1l
/tmp/tmp.OIKSGVvY1l

为什么TEMP每次调用都会扩展,而CONTENTS只会扩展一次?

我正在运行 GNU Make 3.82

【问题讨论】:

    标签: makefile


    【解决方案1】:

    当配方开始执行时,配方的变量全部展开:

    #forcing `bash` to prevent `make` from using its builtin shell
    $ strace -t -e execve -f make -d SHELL=/bin/bash test >output 2>&1
    $ cat output # with irrelevant bits elided
    17:20:48 execve("/usr/bin/make", ["make", "-d", "SHELL=/bin/bash", "test"], [/* 52 vars */]) = 0
    GNU Make 4.1
    Built for x86_64-pc-linux-gnu
    Copyright (C) 1988-2014 Free Software Foundation, Inc.
    License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
    This is free software: you are free to change and redistribute it.
    There is NO WARRANTY, to the extent permitted by law.
    Reading makefiles...
    Reading makefile 'Makefile'...
    Updating makefiles....
     Considering target file 'Makefile'.
     <lots of lines omitted>
     No need to remake target 'Makefile'.
    Updating goal targets....
    
    # prepare the recipe
    Considering target file 'test'.
     File 'test' does not exist.
     Finished prerequisites of target file 'test'.
    Must remake target 'test'.
    
    # expand $(DATE) the first time
    strace: Process 32729 attached
    [pid 32729] 17:20:48 execve("/bin/bash", ["/bin/bash", "-c", "date"], [/* 52 vars */]) = 0
    [pid 32729] 17:20:48 execve("/bin/date", ["date"], [/* 52 vars */]) = 0
    [pid 32729] 17:20:48 +++ exited with 0 +++
    17:20:48 --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=32729, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
    
    # expand $(FILE) the first time
    strace: Process 32730 attached
    [pid 32730] 17:20:48 execve("/bin/bash", ["/bin/bash", "-c", "mktemp"], [/* 52 vars */]) = 0
    [pid 32730] 17:20:48 execve("/bin/mktemp", ["mktemp"], [/* 52 vars */]) = 0
    [pid 32730] 17:20:48 +++ exited with 0 +++
    17:20:48 --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=32730, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
    
    # expand $(DATE) the second time
    strace: Process 32731 attached
    [pid 32731] 17:20:48 execve("/bin/bash", ["/bin/bash", "-c", "date"], [/* 52 vars */]) = 0
    [pid 32731] 17:20:48 execve("/bin/date", ["date"], [/* 52 vars */]) = 0
    [pid 32731] 17:20:48 +++ exited with 0 +++
    17:20:48 --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=32731, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
    
    # expand $(FILE) the second time
    strace: Process 32732 attached
    [pid 32732] 17:20:48 execve("/bin/bash", ["/bin/bash", "-c", "mktemp"], [/* 52 vars */]) = 0
    [pid 32732] 17:20:48 execve("/bin/mktemp", ["mktemp"], [/* 52 vars */]) = 0
    [pid 32732] 17:20:48 +++ exited with 0 +++
    17:20:48 --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=32732, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
    
    # begin executing the recipe
    strace: Process 32733 attached
    Putting child 0x5629c95cb0c0 (test) PID 32733 on the chain.
    Live child 0x5629c95cb0c0 (test) PID 32733 
    [pid 32733] 17:20:48 execve("/bin/bash", ["/bin/bash", "-c", "echo Tue Jun 26 17:20:48 PDT 201"...], [/* 56 vars */]) = 0
    Tue Jun 26 17:20:48 PDT 2018
    [pid 32733] 17:20:48 +++ exited with 0 +++
    17:20:48 --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=32733, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
    Reaping winning child 0x5629c95cb0c0 PID 32733 
    strace: Process 32734 attached
    Live child 0x5629c95cb0c0 (test) PID 32734 
    [pid 32734] 17:20:48 execve("/bin/bash", ["/bin/bash", "-c", "echo /tmp/tmp.nWxcC4KeVf"], [/* 56 vars */]) = 0
    /tmp/tmp.nWxcC4KeVf
    [pid 32734] 17:20:48 +++ exited with 0 +++
    17:20:48 --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=32734, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
    Reaping winning child 0x5629c95cb0c0 PID 32734 
    
    # significant time doesn't pass until here
    sleep 3
    strace: Process 32735 attached
    Live child 0x5629c95cb0c0 (test) PID 32735 
    [pid 32735] 17:20:48 execve("/bin/bash", ["/bin/bash", "-c", "sleep 3"], [/* 56 vars */]) = 0
    [pid 32735] 17:20:48 execve("/bin/sleep", ["sleep", "3"], [/* 56 vars */]) = 0
    [pid 32735] 17:20:51 +++ exited with 0 +++
    17:20:51 --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=32735, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
    Reaping winning child 0x5629c95cb0c0 PID 32735 
    strace: Process 32736 attached
    Live child 0x5629c95cb0c0 (test) PID 32736 
    [pid 32736] 17:20:51 execve("/bin/bash", ["/bin/bash", "-c", "echo Tue Jun 26 17:20:48 PDT 201"...], [/* 56 vars */]) = 0
    Tue Jun 26 17:20:48 PDT 2018
    [pid 32736] 17:20:51 +++ exited with 0 +++
    17:20:51 --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=32736, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
    Reaping winning child 0x5629c95cb0c0 PID 32736 
    strace: Process 32737 attached
    Live child 0x5629c95cb0c0 (test) PID 32737 
    [pid 32737] 17:20:51 execve("/bin/bash", ["/bin/bash", "-c", "echo /tmp/tmp.QgNem5ezr0"], [/* 56 vars */]) = 0
    /tmp/tmp.QgNem5ezr0
    [pid 32737] 17:20:51 +++ exited with 0 +++
    17:20:51 --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=32737, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
    Reaping winning child 0x5629c95cb0c0 PID 32737 
    Removing child 0x5629c95cb0c0 PID 32737 from chain.
    Successfully remade target file 'test'.
    17:20:51 +++ exited with 0 +++
    

    这是有道理的,即使没有.ONESHELL,因为变量可以扩展到多行,需要单独执行。

    【讨论】:

    • 编辑了我原来的问题,使@o11c 的答案更清晰。由于变量在实际完成之前就已经展开,这意味着文件在展开时仍然是空的。解决它的一种方法是$(eval CONTENTS:=$(shell cat $(FILE)))
    • 非常清楚,变量CONTENTS 正在被多次扩展。只是它的所有实例都在调用任何配方之前被扩展,因此它们都扩展为相同的东西。
    • 是的,我只是更改了问题,以便更清楚地知道CONTENTS 如果在调用它而不是在配方开始时被扩展,它应该是非常不同的
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-11
    相关资源
    最近更新 更多