代码之家  ›  专栏  ›  技术社区  ›  jfMR

如果编译器选项与以前使用的不同,则使目标过期

  •  2
  • jfMR  · 技术社区  · 6 年前

    请考虑下面的目录树,它是一个化妆玩具示例,说明了要解决的问题:

    - Makefile
    - lib.c
    + foo/
       |-- config.mk
    + bar/
       |-- config.mk
    
    • 内容 foo/config.mk :

      CFLAGS += -DFOO
      
    • 内容 bar/config.mk

      CFLAGS += -DBAR
      
    • 使命感 make 具有 Makefile foo bar foo/config.mk 包括在内(通过 include directive lib.o 正在建造,即:

      # build lib.o with the macro FOO defined
      $ make foo
      
      # build lib.o with the macro BAR defined
      $ make bar
      
      # build lib.o with both the macros FOO and BAR defined
      $ make foo bar
      $ make bar foo
      

    建筑的默认规则 使用变量 COMPILE.c ,定义为(根据调用 制作 有选择权 --print-data-base

    COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
    

    扩张 编译.c 除其他外,取决于变量的值 CFLAGS foo/config.mk bar/config.mk 由于这些生成文件修改了 CFLAGS 变量


    我想要达到的是对待目标 自由党 作为 如果变量展开,则返回目标 编译.c 当前使用的与上一版本的不同 . 例如:

    $ make foo
    
    # It shouldn't rebuild anything since lib.o should be up-to-date
    $ make foo
    
    # It should rebuild lib.o since it should be out-of-date
    $ make bar
    
    # It should rebuild lib.o since it is again out-of-date
    $ make foo bar
    
    # It shouldn't rebuild lib.o since it is up-to-date
    $ make bar foo   
    

    This solution

    3 回复  |  直到 6 年前
        1
  •  2
  •   Renaud Pacalet    6 年前

    ifeq ($(filter foo,$(MAKECMDGOALS)),foo)
    include foo/config.mk
    endif
    ifeq ($(filter bar,$(MAKECMDGOALS)),bar)
    include bar/config.mk
    endif
    -include old_compile.mk
    
    COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
    
    ifneq ($(COMPILE.c),$(OLD_COMPILE.c))
    FORCE := force
    endif
    
    lib.o: lib.c $(FORCE)
        $(COMPILE.c) $< -o $@
        echo 'OLD_COMPILE.c := $(COMPILE.c)' > old_compile.mk
    
    .PHONY: foo bar all force
    
    foo bar all: lib.o
    

    演示:

    $ make foo
    cc -DFOO   -c lib.c -o lib.o
    echo 'OLD_COMPILE.c := cc -DFOO   -c' > old_compile.mk
    $ make foo
    make: Nothing to be done for 'foo'.
    $ make foo bar
    cc -DFOO -DBAR   -c lib.c -o lib.o
    echo 'OLD_COMPILE.c := cc -DFOO -DBAR   -c' > old_compile.mk
    make: Nothing to be done for 'bar'.
    $ make bar foo
    make: Nothing to be done for 'bar'.
    make: Nothing to be done for 'foo'.
    
        2
  •  1
  •   n. m. could be an AI    6 年前

    这是我的原始模型,它直接在文件名中编码编译器/链接器标志。这只是一个想法,一个实际的实现应该更健壮一些。

    empty:=
    space:= $(empty) $(empty)
    comma:= ,
    
    LDFLAGS_NS=$(subst $(space),$(comma),$(LDFLAGS))
    CFLAGS_NS=$(subst $(space),$(comma),$(CFLAGS))
    
    EXEDIR=./test-exedir-cflags=$(CFLAGS_NS)-ldflags=$(LDFLAGS_NS)
    EXEDIR_PAT=./test-exedir-*
    OBJDIR=./test-objdir-cflags=$(CFLAGS_NS)
    OBJDIR_PAT=./test-objdir-*
    
    test.exe: $(EXEDIR)/test.exe
        rm -f test
        ln -s $< $@
    
    $(EXEDIR)/test.exe: test.o
        rm -rf $(EXEDIR_PAT)
        mkdir $(EXEDIR)
        cc $(LDFLAGS) -o $@ $<
    
    test.o: $(OBJDIR)/test.o
        rm -f test.o
        ln -s $< $@
    
    $(OBJDIR)/test.o: test.c
        rm -rf $(OBJDIR_PAT)
        mkdir $(OBJDIR)
        cc -c $(CFLAGS) -o $@ $<
    

    使用hello world test.c文件和以下命令进行测试:

    make test.exe
    make test.exe
    make test.exe CFLAGS="-g -Wall"
    make test.exe CFLAGS="-g -Wall"
    make test.exe
    
        3
  •  0
  •   jfMR    6 年前

    到目前为止,我的方法是生成一个文件, cc-options-dump COMPILE.c 每次变量 lib.o 是建的。

    编译.c 抄送选项转储 ,如果有(即,如果文件确实存在)。

    .PHONY: foo bar require-rebuild cc-options-dump
    
    # include the xxx/config.mk files
    # sort built-in function to make it independent of the order (i.e., "foo bar" or "bar foo")
    $(foreach opt,$(sort $(MAKECMDGOALS)),$(eval include $(opt)/config.mk))
    
    # obtain the MD5 hash of the previously used flags
    ifneq (,$(wildcard cc-options-dump))
    prev-cc-options-hash := $(shell md5sum cc-options-dump | cut -f1 -d' ')
    endif
    
    # obtain the MD5 hash of the current flags
    curr-cc-options-hash := $(shell echo "$(COMPILE.c)" | md5sum | cut -f1 -d' ')
    
    # Do these hashes differ?
    ifneq ($(prev-cc-options-hash),$(curr-cc-options-hash))
    # keep track of the fact that a rebuilt needs to be triggered
    does-need-rebuild := require-rebuild
    # just for displaying information
    $(info Rebuild required)
    else
    $(info Rebuild not required)
    endif
    
    # make both targets foo and bar dependent on the file with the flags
    # so that it has to be generated, since it is a phony target as well 
    foo bar: cc-options-dump
    
    # lib.o has now an additional prerequisite for determining whether it need to be rebuilt
    lib.o: $(does-need-rebuild)
    
    # save the used compiler flags for comparing them with the future flags
    cc-options-dump: lib.o
        @echo '$(COMPILE.c)' >$@
    

    make 针对目标 foo 和/或 bar 据我所知,与所需的一致:

    $ make foo
    Rebuild required
    cc -DFOO   -c -o lib.o lib.c
    
    $ make foo
    Rebuild not required
    
    $ make bar
    Rebuild required
    cc -DBAR   -c -o lib.o lib.c
    
    $ make bar
    Rebuild not required
    
    $ make foo bar
    Rebuild required
    cc -DBAR -DFOO   -c -o lib.o lib.c
    
    $ make bar foo
    Rebuild not required
    

    使用 sort 内置功能对于上述最后两种情况的正常工作至关重要。

    如果有人能提供一个更优雅的解决方案,那就太好了。