【问题标题】:Getting the name of the makefile from the makefile从 makefile 中获取 makefile 的名称
【发布时间】:2009-09-09 14:26:46
【问题描述】:

如何获取makefile中makefile的名称?

谢谢。

注意:

我需要它,因为我希望我的 makefile 调用自己,但 makefile 不称为 Makefile,所以我想写这样的东西:

target:
    ($MAKE) -f ($MAKEFILENAME) other_target

【问题讨论】:

    标签: makefile


    【解决方案1】:
    location = $(CURDIR)/$(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))
    WHERE_ART_THOU := $(location)
    $(warning $(WHERE_ART_THOU))
    

    我也相信这是 GNU make-specific,但我不太确定。

    【讨论】:

    • 如果您在包含另一个 makefile 后检查 makefile 名称,此解决方案将不起作用! (复制粘贴评论)
    • "如果您在包含另一个 makefile 后检查 makefile 名称,此解决方案将不起作用!"这不是一个大问题。我可以在 Makefile 的开头编写这段代码的前两行,它正确设置了 WHERE_ART_THOU 变量。然后我可以在 Makefile 的任何地方使用该变量,它将正确包含我的 Makefile 的名称。
    • 但是对于包含的 makefile,您必须使用不同的名称:WHERE_ART_THOU 用于一个 makefile,WHERE_ART_THOU_2 用于另一个等。我的目标是为所有 makefile 引入一个名称,该名称不仅在使用时有效在一个的顶部。
    • 你说得对,帕维尔。 现在我了解您的解决方案:)
    【解决方案2】:

    (如果您有任何疑问,请参阅惊人的写作GNU make manual。但请记住,就像 Makefile 一样,在将概念付诸实践之前应完整阅读本手册)。

    我无法弄清楚它是如何轻松完成的。据我了解,您必须做一些体力活。

    稍后我将描述它是如何完成的,并展示引入current_makefile 变量的脚本。但首先我想强调一个重要的概念。

    你应该明白,如果我们有某种变量current_makefile,它会扩展为当前的makefile 名称,那么它在读取makefile 的过程中必须改变。这意味着它应该在“即时”扩展上下文中使用——即在读取makefile期间执行的命令中。然而,大多数命令是在读取 makefile 之后执行的。因此,某些命令会顺利打印出正确的值,而在某些使用“deferred”扩展的地方,它总是会扩展为根 makefile 名称。

    例如,如果您想在规则文本中使用此变量,则必须采取一些技巧,因为规则文本始终具有延迟扩展。所以,如果你有规则

    rule:
            echo In makefile $(current_makefile):
            echo Making target $@
    

    它将始终打印根 makefile 的名称。相反,要强制立即扩展,您必须创建另一个具有特定于 makefile 名称的变量(即,每个 makefile 中此类变量的名称应该不同):

    this_makefile_unique_name := $(current_makefile)
    rule:
            echo In makefile $(current_makefile):
            echo Making target $@
    

    或使用 eval:.

    define make_rule
    rule:
            echo In makefile $(1):
            echo Making target $$@
    
    $(eval $(call make_rule,$(current_makefile)))
    

    如果您只想将当前 makefile 的名称用于调试目的,请考虑特殊的调试功能,例如警告或信息:。

    $(warning We're in makefile $(current_makefile))
    

    这些函数使用“立即”展开并且会打印正确的值。


    如何定义这样的$(current_makefile)?

    您必须手动维护 makefile 包含的堆栈。当你包含一个 makefile 时,它​​的名字被放在栈顶;当您从包含的 makefile 返回到外部时,最顶层的名称会从堆栈中弹出。这是通过在 makefile 的开头和结尾插入特殊调用来实现的:

    # Beginning of makefile
    $(eval $(makefile_names_push))
    #... makefile text
    $(warning $(current_makefile))
    #...
    $(eval $(makefile_names_pop))
    #End of file
    

    现在在根 makefile 的开头定义函数。

    lastword=$(word $(words $(1)),$(1))
    
    define makefile_names_push
    current_makefile := $$(CURDIR)/$$(call lastword,$$(MAKEFILE_LIST))
    makefile_stack :=$$(makefile_stack) $$(current_makefile)
    endef
    
    define makefile_names_pop
    makefile_stack := $$(filter-out $$(current_makefile),$$(makefile_stack))
    current_makefile := $$(call lastword,$$(makefile_stack))
    endef
    

    如果您确定您的品牌足够新(版本 3.81+),请将 lastword 调用替换为内置函数:。

    #inctead of $$(call lastword,$$(MAKEFILE_LIST))
    $$(lastword $$(MAKEFILE_LIST))
    

    有用吗?

    完全没用。在这里可能有用的唯一用途是制作 100 个作为符号链接到一个 makefile 的 makefile,这些 makefile 中的规则取决于它们的名称。但它可以在手册中描述的一个 makefile 和 foreach-eval 技术中实现。所以我的帖子完全是浪费时间,虽然我玩得很开心:-)

    【讨论】:

      【解决方案3】:

      这将返回第一个调用的 Makefile 的名称,即调用堆栈底部的名称:

      MAKEFILE_JUSTNAME := $(firstword $(MAKEFILE_LIST))
      MAKEFILE_COMPLETE := $(CURDIR)/$(MAKEFILE_JUSTNAME)
      

      在非交叉递归情况下使用时(例如用于 makedepend),它只是当前 makefile 的名称。

      【讨论】:

        【解决方案4】:

        当我使用 Make 管理简单的重复性任务时,我想做类似的事情(用于回显 Makefile 的内容)。我偶然发现了这个页面,发现它正是我所追求的,并且对我对 make 的有限理解非常有用。

        我阅读此页面后的结果:

            # Makefile - 'make' and 'make help' now echo the makefile.
            help:
                cat $(lastword $(MAKEFILE_LIST))
            start:
                sudo -u www /path/to/webapp/myhttpd restart
            stop:
                sudo kill `cat /path/to/webapp/data/httpd.pid`
        

        【讨论】:

          【解决方案5】:

          快速浏览Google 表明this 网站有答案。

          【讨论】:

          • 仅适用于 GNU Make - 通常不适用于非 GNU Make。
          • 如果您在包含另一个 makefile 后检查 makefile 名称,此解决方案将不起作用!
          • 这篇文章有一个suggested edit。由于编辑的内容太大,我无法确认您的目标是否保留。如果你自己审查它会更好。
          • 由于建议的编辑只留下了一个链接,并且链接的博客现在重定向到其主页内容,这个答案不再是一个
          【解决方案6】:

          生日,

          如果您复制原始 makefile,请说 makefile_test,然后输入命令:

          make -np -f makefile_test 2>&1 | tee output
          

          这将评估 makefile 和您的 make 环境,但不会执行任何命令。查看输出文件中对 makefile_test 的引用将显示在 make 环境中设置的内容以及设置该值的位置。

          注意这可以产生很多信息!并且不要添加 -d(调试)开关,它会生成大量关于 make 决策过程的额外输出,但会生成关于 make 环境的极少额外信息。

          HTH

          【讨论】:

          • 这很有趣,但它如何回答实际问题?
          • 环境列表。 vars 包含各种信息。 $(MAKEFILE_LIST) 包含由 make 解析的 makefile 的名称。 HTH
          【解决方案7】:

          这里的解决方案解决了 1) POSIX make with 2) Invoked, non included, makefile in 3) A Unix alike platform。

          OP 要求什么:

          target:
              @pid=$$$$; \
              while test `ps -ocomm= $$pid` != make; do \
                  pid=`ps -oppid= $$pid`; \
              done; \
              MAKEFILENAME=`ps -oargs= $$pid|sed 's/^.* -f *\([^ ]*\).*$$/\1/'`; \
              test -z "$$MAKEFILENAME" -a -f Makefile && MAKEFILENAME=Makefile; \
              test -z "$$MAKEFILENAME" -a -f makefile && MAKEFILENAME=makefile; \
              export MAKEFILENAME; \
              $(MAKE) -e -f $$MAKEFILENAME other_target
          

          目标取决于makefile,有点臃肿:

          TARGET1_MAKEFILENAME = target1_preamble
          
          all: target1 target2...
          
          target1: $(TARGET1_MAKEFILENAME) other_dependencies...
              @test $(TARGET1_MAKEFILENAME) == target1_preamble && exit 0; \
              built_instructions_for_target1;
          
          target1_preamble:
              @pid=$$$$; \
              while test `ps -ocomm= $$pid` != make; do \
                  pid=`ps -oppid= $$pid`; \
              done; \
              MAKEFILENAME=`ps -oargs= $$pid|sed 's/^.* -f *\([^ ]*\).*$$/\1/'`; \
              test -z "$$MAKEFILENAME" -a -f Makefile && MAKEFILENAME=Makefile; \
              test -z "$$MAKEFILENAME" -a -f makefile && MAKEFILENAME=makefile; \
              export MAKEFILENAME; \
              $(MAKE) -e -f $$MAKEFILENAME target1;
          

          如果只为所有目标调用 make,可以稍微简化一下。

          MAKEFILENAME = invoked_makefile_placeholder
          
          all: target1 target2...
          
          target1: $(MAKEFILENAME) other_dependencies...
              @test $(MAKEFILENAME) == invoked_makefile_placeholder && exit 0; \
              built_instructions_for_target1;
          
          invoked_makefile_placeholder:
              @pid=$$$$; \
              while test `ps -ocomm= $$pid` != make; do \
                  pid=`ps -oppid= $$pid`; \
              done; \
              MAKEFILENAME=`ps -oargs= $$pid|sed 's/^.* -f *\([^ ]*\).*$$/\1/'`; \
              test -z "$$MAKEFILENAME" -a -f Makefile && MAKEFILENAME=Makefile; \
              test -z "$$MAKEFILENAME" -a -f makefile && MAKEFILENAME=makefile; \
              export MAKEFILENAME; \
              $(MAKE) -e -f $$MAKEFILENAME
          

          对于基于grep包含的makefile 和makefile 中包含的独特模式,使用前面的方法实现解决方案很简单。

          当我觉得问题得到了适当的解决时,我从不回答。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-03-31
            • 1970-01-01
            • 1970-01-01
            • 2012-01-24
            • 1970-01-01
            相关资源
            最近更新 更多