【问题标题】:Change Makefile variable value inside the target body更改目标主体内的 Makefile 变量值
【发布时间】:2011-02-12 07:23:39
【问题描述】:

有没有办法在目标主体内重新分配 Makefile 变量值?

我想做的是为调试编译添加一些额外的标志:

%.erl: %.beam
    $(ERLC) $(ERLFLAGS) -o ebin $<

test: clean debug_compile_flag compile compile_test

debug_compile:
    $(ERLCFLAGS) += -DTEST

所以如果我调用 test 目标,我想清理我的环境,添加一些新标志(如 -DTEST 到现有标志),编译整个代码再一次(首先是源代码,然后是测试模块)。

我不想复制/粘贴带有一些新标志集的编译代码,因为这里和那里有很多逻辑。

是否有一些简单的方法可以重新定义变量值,以便我可以重用现有代码?

【问题讨论】:

标签: makefile target


【解决方案1】:

是的,有一种简单的方法可以做到这一点,并且无需重新运行 Make。使用target-specific variable value:

test: clean debug_compile

debug_compile: ERLCFLAGS += -DTEST
debug_compile: compile compile_test;

【讨论】:

  • 这里保证执行顺序吗?或者 make -j2 会搞砸吗?
  • Docs: "请注意,每次调用 make 时,给定的先决条件最多只会构建一次。如果同一个文件是多个目标的先决条件,并且每个目标都有一个相同目标特定变量的不同值,则要构建的第一个目标将导致构建该先决条件,并且先决条件将从第一个目标继承目标特定值。它将忽略来自任何其他目标的特定于目标的值目标。”
【解决方案2】:

另一个答案在这里:Define make variable at rule execution time。

对于懒惰的人,你可以有如下规则(FLAG 和 DEBUG 是我的变量):

.DBG:
    $(eval FLAG += $(DEBUG))

【讨论】:

  • 我对@9​​87654326@ 有很多问题,还有很多奇怪的副作用。它似乎不像“真正的” Makefile 变量赋值那样工作。
  • 我遇到了eval 函数的问题 - 我的变量为空值,因为使用 eval 定义的变量在目标执行开始时获取它的值,而不是在到达此行时。例如,如果您在目标的开头创建一些文件,然后尝试使用eval FILES=$(shell ls) 填充一些变量,那么您的 FILES 变量将为空
  • 在目标内部我相信你需要 $(eval FILES=$(shell ls)) 但我的 makefile 有一些问题,具体取决于 make 的版本。
  • 更多问题,请考虑pastebin.com/L1gYhHk5。如果你选择make a b,Make 会抱怨需要 bar。如果你然后touch bar,那么echo在b执行将打印baz:依赖的计算和主体的执行是在不同的点进行的。
【解决方案3】:

这是我使用的解决方案:

PASSWORD = abc123

main: sub
    @echo "in main" $(PASSWORD)

sub:
    @echo "in sub" $(PASSWORD)
    $(eval PASSWORD=qwerty)
    @echo "in sub" $(PASSWORD)

如果您运行make main,则输出为:

in sub abc123
in sub qwerty
in main qwerty

您可以看到sub 中的原始值"abc123" 被覆盖,而"qwerty" 的新值在main 级别可见。

【讨论】:

    【解决方案4】:

    要在命令行上覆盖,请尝试以下操作:

    make prefix=<path to new dir> install
    

    这不会改变 Makefile,但会改变变量。

    【讨论】:

    • 让调用 make 命令的内容通过更改调用时的变量来决定,这对于简单的用例来说是一个很好的解决方案,就像提供的示例一样。我会说对于任何复杂的东西,最好将其编码,但我喜欢这个解决方案的简单性!
    【解决方案5】:

    我想在 makefile 中添加一个目标来运行测试,这意味着使用一些调试标志重新编译源代码。 Ian 的回答:https://stackoverflow.com/a/15561911/ 是唯一有效的解决方案。

    这是我想出来的Makefile,它保证了运行make tests时的执行顺序:

    TARGET     = a.out
    
    CC         = g++
    GENERIC_F  = -Wall -Wextra -I. -Idoctest/doctest/
    
    CFLAGS     = -O0 -std=c++11 $(GENERIC_F)
    DEBUG_MODE = -DDEBUG
    
    LINKER     = g++
    LFLAGS     = $(GENERIC_F) -lm
    
    SRCDIR     = src
    OBJDIR     = build
    BINDIR     = bin
    
    SOURCES    = $(wildcard $(SRCDIR)/*.cc)
    INCLUDES   = $(wildcard $(SRCDIR)/*.h)
    OBJECTS    = $(SOURCES:$(SRCDIR)/%.cc=$(OBJDIR)/%.o)
    rm         = rm -f
    
    .PHONY: clear_screen tests extend_cflags
    
    $(BINDIR)/$(TARGET): $(OBJECTS) $(INCLUDES)
        $(LINKER) $(OBJECTS) $(LFLAGS) -o $@
        @echo -e "Linking complete!\n"
    
    $(OBJECTS): $(OBJDIR)/%.o : $(SRCDIR)/%.cc $(INCLUDES)
        @mkdir -p $(OBJDIR) $(BINDIR)
        $(CC) $(CFLAGS) -c $< -o $@
        @echo -e "Compiled "$<" successfully!\n"
    
    .PHONY: clean
    clean:
        @$(rm) $(OBJECTS)
        @echo "Cleanup complete!"
    
    .PHONY: remove
    remove: clean
        @$(rm) $(BINDIR)/$(TARGET)
        @echo "Executable removed!"
    
    clear_screen:
        @clear
    
    extend_cflags:
        $(eval CFLAGS += $(DEBUG_MODE))
    
    tests: | remove extend_cflags $(BINDIR)/$(TARGET) clear_screen
        @$(BINDIR)/$(TARGET)
    

    【讨论】:

      【解决方案6】:

      编辑:正如 Beta 在other answer 中解释的那样,这是可能的。


      没有。在 Makefile 中没有办法做到这一点。但是,您可以在make 命令行上更改变量的值。如果你重写你的 Makefile 如下:

      ERLCFLAGS += $(ERLCFLAGSADDED)
      
      %.erl: %.beam
          $(ERLC) $(ERLCFLAGS) -o ebin $<
      
      test: clean compile compile_test
      

      然后,您可以调用 make 来执行测试:

      make ERLCFLAGSADDED=-DTEST test
      

      【讨论】:

      • 是的,我按照您的建议解决了问题,在 debug_compile 中运行 submake:ERLC_FLAGS=$(ERLC_DEBUG_FLAGS) $(MAKE) compile 谢谢!
      • 哦,是的,太好了。我没有考虑过这个 submake 调用。
      • 如果您想使用不同的标志值多次运行目标,submake 调用仍然很有用。请参阅我在下面的评论中引用的文档。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-17
      • 2013-02-22
      相关资源
      最近更新 更多