【问题标题】:How to print out a variable in makefile如何在makefile中打印出一个变量
【发布时间】:2013-05-04 06:42:50
【问题描述】:

在我的 makefile 中,我有一个变量 'NDK_PROJECT_PATH',我的问题是如何在编译时将其打印出来?

我阅读了Make file echo displaying "$PATH" string 并尝试过:

@echo $(NDK_PROJECT_PATH)
@echo $(value NDK_PROJECT_PATH)

两个都给我

"build-local.mk:102: *** missing separator.  Stop."

有人知道为什么它不适合我吗?

【问题讨论】:

    标签: makefile gnu-make


    【解决方案1】:

    您可以在 make 文件中创建一个 vars 规则,如下所示:

    dispvar = echo $(1)=$($(1)) ; echo
    
    .PHONY: vars
    vars:
        @$(call dispvar,SOMEVAR1)
        @$(call dispvar,SOMEVAR2)
    

    这里有一些更强大的方法可以转储所有变量:gnu make: list the values of all variables (or "macros") in a particular run

    【讨论】:

      【解决方案2】:

      根据GNU Make manual 并在以下答案中由“bobbogo”指出, 您可以使用 info / warning / error 来显示文字。

      $(error   text…)
      $(warning text…)
      $(info    text…)
      

      要打印变量,

      $(error   VAR is $(VAR))
      $(warning VAR is $(VAR))
      $(info    VAR is $(VAR))
      

      'error' 将在显示错误字符串后停止 make 执行

      【讨论】:

      • 哇,不知道这个。比 echo 好得多,它会在日志中复制命令。
      【解决方案3】:

      如果我想查看变量值,我通常会报错。(仅当您想查看该值时。它将停止执行。)

      @echo $(错误 NDK_PROJECT_PATH= $(NDK_PROJECT_PATH))

      【讨论】:

        【解决方案4】:

        您可以使用此方法(使用名为“var”的变量)在读取 makefile 时打印出变量(假设 GNU make,因为您已适当地标记了此问题):

        $(info $$var is [${var}])
        

        您可以将此构造添加到任何配方中,以查看 make 将传递给 shell:

        .PHONY: all
        all: ; $(info $$var is [${var}])echo Hello world
        

        现在,这里发生的是 make 将整个配方 ($(info $$var is [${var}])echo Hello world) 存储为单个递归扩展变量。当 make 决定运行配方时(例如,当您告诉它构建 all 时),它会扩展变量,然后将每个结果行分别传递给 shell。

        所以,痛苦的细节:

        • 扩展$(info $$var is [${var}])echo Hello world
        • 为此,它首先扩展$(info $$var is [${var}])
          • $$ 变为文字 $
          • ${var} 变成 :-)(比如说)
          • 副作用是$var is [:-)] 出现在标准输出中
          • $(info...) 的扩展虽然是空的
        • 留下echo Hello world
          • 首先在标准输出上打印echo Hello world,让你知道它会要求shell做什么
        • shell 在标准输出上打印Hello world

        【讨论】:

        • 应该是(点).PHONY 而不是 PHONY?
        【解决方案5】:

        无需修改 Makefile。

        $ cat printvars.mak
        print-%:
                @echo '$*=$($*)'
        
        $ cd /to/Makefile/dir
        $ make -f ~/printvars.mak -f Makefile print-VARIABLE
        

        【讨论】:

          【解决方案6】:

          如果你只是想要一些输出,你想单独使用$(info)。您可以在 Makefile 中的任何位置执行此操作,它会在评估该行时显示:

          $(info VAR="$(VAR)")
          

          每当 make 处理该行时将输出VAR="<value of VAR>"。此行为非常依赖于位置,因此您必须确保 $(info) 扩展发生在所有可以修改 $(VAR) 的事情已经发生之后!

          一个更通用的选项是创建一个特殊的规则来打印变量的值。一般来说,规则是在分配变量后执行的,因此这将显示实际使用的值。 (虽然,它是possible for a rule to change a variable。)良好的格式将有助于阐明变量的设置,$(flavor) 函数会告诉您某物是什么类型的变量。所以在这条规则中:

          print-% : ; $(info $* is a $(flavor $*) variable set to [$($*)]) @true
          
          • $* 扩展为 % pattern 在规则中匹配的词干。
          • $($*) 扩展为名称由 $* 给出的变量的值。
          • [] 清楚地描述了变量扩展。 您也可以使用 "" 或类似名称。
          • $(flavor $*) 告诉你它是什么类型的变量。注意:$(flavor) 接受一个变量 name,而不是它的扩展。 所以如果你说make print-LDFLAGS,你会得到$(flavor LDFLAGS), 这就是你想要的。
          • $(info text) 提供输出。 Make 在其标准输出上打印 text 作为扩展的副作用。 $(info) 的扩展虽然是空的。 你可以把它想象成@echo, 但重要的是它不使用外壳, 因此您不必担心 shell 引用规则。
          • @true 只是为规则提供命令。 没有那个, make 也会输出print-blah is up to date。我觉得@true 更清楚地表明它是禁止操作的。

          运行它,你得到

          $ make print-LDFLAGS
          LDFLAGS is a recursive variable set to [-L/Users/...]
          

          【讨论】:

          • 这没有提供问题的答案。要批评或要求作者澄清,请在他们的帖子下方发表评论 - 您可以随时评论自己的帖子,一旦您有足够的reputation,您就可以comment on any post。 - From Review
          • 感谢您的评论。我知道一旦我有足够的声誉,我可以发表评论,但我应该在此期间做什么?我相信我的答案提供了额外的价值,所以我不应该添加它吗?
          • 我建议将其重写为与您正在评论的答案竞争的独立答案,而不是将其表述为对该答案的不合适的评论。
          • @JimNasby 是的,查尔斯的建议。实际上,简单地删除“抱歉没有足够的代表发表评论”之类的部分可能会有所帮助,因为它是一个危险信号。如果你把它变成一个完整的答案(可以随心所欲地编辑它),它应该做得很好。干杯。
          • 非常好——现在这是一个更好的答案。 :)
          【解决方案7】:

          如果您使用 android make (mka) @echo $(NDK_PROJECT_PATH) 将无法正常工作并给您错误 *** missing separator. Stop." 如果您尝试在 android make 中打印变量,请使用 this answer

          NDK_PROJECT_PATH := some_value
          $(warning $(NDK_PROJECT_PATH))
          

          对我有用

          【讨论】:

            【解决方案8】:

            如果不想修改Makefile本身,可以使用--eval添加新目标,然后执行新目标,例如

            make --eval='print-tests: @echo TESTS $(TESTS) ' print-tests

            您可以使用CTRL-V, TAB在命令行中插入所需的TAB字符

            上面的 Makefile 示例:

            all: do-something
            
            TESTS=
            TESTS+='a'
            TESTS+='b'
            TESTS+='c'
            
            do-something:
                    @echo "doing something"
                    @echo "running tests $(TESTS)"
                    @exit 1
            

            【讨论】:

            • 我正在尝试运行您的脚本,但出现错误make: *** missing separator. Stop.
            • 啊,抱歉,已修复。 “打印测试”目标末尾缺少冒号。
            • 其实你不需要换行和制表符,分号就足够了:make --eval='print-tests: ; @echo TESTS $(TESTS)' print-tests
            【解决方案9】:

            这可以通过通用方式完成,并且在调试复杂的 makefile 时非常有用。按照another answer 中描述的相同技术,您可以将以下内容插入到任何makefile 中:

            # if the first command line argument is "print"
            ifeq ($(firstword $(MAKECMDGOALS)),print)
            
              # take the rest of the arguments as variable names
              VAR_NAMES := $(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS))
            
              # turn them into do-nothing targets
              $(eval $(VAR_NAMES):;@:))
            
              # then print them
              .PHONY: print
              print:
                      @$(foreach var,$(VAR_NAMES),\
                        echo '$(var) = $($(var))';)
            endif
            

            然后你可以做“make print”来转储任何变量的值:

            $ make print CXXFLAGS
            CXXFLAGS = -g -Wall
            

            【讨论】:

              【解决方案10】:

              问题是 echo 只能在执行块下工作。即“xx:”之后的任何内容

              所以第一个执行块之上的任何东西都只是初始化,所以不能使用任何执行命令。

              所以创建一个执行块

              【讨论】:

                【解决方案11】:

                来自“Mr. Make post” https://www.cmcrossroads.com/article/printing-value-makefile-variable

                将以下规则添加到您的 Makefile:

                print-%  : ; @echo $* = $($*)
                

                那么,如果你想找出某个makefile变量的值,只需:

                make print-VARIABLE
                

                它会返回:

                VARIABLE = the_value_of_the_variable
                

                【讨论】:

                • 你解释得比作者好。竖起大拇指!
                【解决方案12】:

                运行make -n;它显示了变量的值..

                生成文件...

                all:
                        @echo $(NDK_PROJECT_PATH)
                

                命令:

                export NDK_PROJECT_PATH=/opt/ndk/project
                make -n 
                

                输出:

                echo /opt/ndk/project
                

                【讨论】:

                【解决方案13】:

                makefile 将生成“缺少分隔符”错误消息:

                all
                    @echo NDK_PROJECT_PATH=$(NDK_PROJECT_PATH)
                
                done:
                        @echo "All done"
                

                @echo "All done" 之前有一个标签(尽管done: 规则和操作在很大程度上是多余的),但@echo PATH=$(PATH) 之前没有。

                问题在于以all 开头的行应该有一个冒号: 或一个等于= 以表明它是目标行或宏行,而两者都没有,所以缺少分隔符.

                回显变量值的操作必须与目标相关联,可能是虚拟目标或 PHONEY 目标。并且该目标行上必须有一个冒号。如果您在示例makefile 中的all 之后添加:,并将下一行的前导空格替换为制表符,它将正常工作。

                您可能在原始makefile 的第 102 行附近有类似的问题。如果您在失败的回显操作之前显示 5 个非空白、非注释行,则可能可以完成诊断。但是,由于该问题是在 2013 年 5 月提出的,因此损坏的 makefile 现在不太可能仍然可用(2014 年 8 月),因此无法正式验证此答案。它只能用来说明问题发生的合理方式。

                【讨论】:

                  【解决方案14】:

                  make 的所有版本都要求命令行以 TAB(而不是空格)作为行中的第一个字符缩进。如果您向我们展示了整个规则,而不仅仅是有问题的两行,我们可以给出更清晰的答案,但应该是这样的:

                  myTarget: myDependencies
                          @echo hi
                  

                  第二行的第一个字符必须是 TAB。

                  【讨论】:

                    【解决方案15】:

                    @echo $(NDK_PROJECT_PATH) 是这样做的好方法。 我不认为错误来自那里。 通常,当您输入错误的意图时会出现此错误:我认为您应该有一个制表符的空格。

                    【讨论】:

                    • 我试过'@echo $(NDK_PROJECT_PATH)',我仍然收到错误“build-local.mk:102: *** missing separator. Stop.”。我在“echo”之后只有 1 个空格,“@echo”之前没有空格或制表符。
                    • 你确定错误来自这一行吗?这条线是规则吗?她可能必须缩进......
                    猜你喜欢
                    • 1970-01-01
                    • 2021-01-29
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2021-08-21
                    • 1970-01-01
                    相关资源
                    最近更新 更多