[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

How to rebuild on recipe change?

From: Kirill Smelkov
Subject: How to rebuild on recipe change?
Date: Mon, 15 Feb 2010 20:57:01 +0300
User-agent: Mutt/1.5.18 (2008-05-17)

Hello CoMakers,

I'm trying to do reliable incremental build system, and this means that
those and only those parts which depend on changed environment have to
be remade.

However changed environment could be not only file changes, but also
changes to CFLAGS (global or target specific), or command recipe for
.cpp -> .o rule and the like.

This puts me out of scope make was originally developed for it seems...

I've tried to use second expansion and to add FORCE to targets whose
$(command) changed from previous run, but this turned out not to work,
since second expansion works differently for $<, $^ and $+ compared to
in-recipe expansion.

Then I've discovered Mr Make's article [1] about "Rebuilding When
CPPFLAGS Changes", but at least that approach does not seem to support
target-specific variables...

So the question is:

    How to do it? How to properly rebuild on recipe change without
    sacrificing clearness and performance?

The only thing I've could come up with so far [3] is to mark every
target as phony, and manually see whether it needs to be rebuild in
recipe. The same happens in Linux Kbuild [2], but does this qualify as
clear and make-way?

Please advice and thanks beforehand,



[3] here it is:

---- 8< ----
# Sample Makefile -- demonstrates how to rebuild on dependencies and recipe
# change.
# See also:

# from gmls
true    := T
false   :=
# not <arg>
not     = $(if $1,$(false),$(true))
# seq <str1> <str2> -> $(true)/$(false)
seq = $(if $(filter-out xx,x$(subst $1,,$2)$(subst $2,,$1)x),$(false),$(true))
sne = $(call not,$(call seq,$1,$2))

# last-run $@ dependencies and recipe commands are stored in aux file

# aux <file> -> aux-file-name
aux     = $(dir $1).$(notdir $1).aux
@.aux   = $(call aux,$@)

ccdepflags = -Wp,-MD,$(@.aux),-MT,$@,-MP
cmd_cc_o_c = $(CC) $(ccdepflags) $(CFLAGS) -c -o $@ $<


# The most interesting part:
# On target rebuild, we dump dependencies, and target command to aux file.
# Then, the only place, where we can correctly compare current run's cmd to
# previous cmd is in recipe (!) because for command line rule:
#   (1)  we want to support target-specific variables (this leaves
#        second-expansion & recipe), and
#   (2)  second expansion does not work the same way as in recipe for $<, $^
#        and $+ (this leaves recipe only)
# but make goes into recipe only when it already thinks target needs to be
# rebuilt... The trick here is to mark every target as FORCE, and manually
# check $? (whether we need to rebuild because prerequisite changed) and
# command line (whether we need to rebuild because $@ command changed).
# This sort-of works, but is tricky and inellegant and is against make original
# purpose in spirit.
# So am I missing something? How could this be done simpler?

# run-cmd <cmd-name>
define  run-cmd
  echo -e '\n\ncmd_$@ := $($1)' >> $(@.aux)

%.o: %.c        FORCE
        $(if $(or $?,$(call sne,$(cmd_cc_o_c),$(cmd_$@))),\
                $(call run-cmd,cmd_cc_o_c))

# --------------------------------------

CFLAGS  := -g
1.o:    CFLAGS += -fPIC -g3 -ffast-math

OBJS    := 1.o 2.o
all     : $(OBJS)

-include $(foreach obj,$(OBJS),$(call aux,$(obj)))

reply via email to

[Prev in Thread] Current Thread [Next in Thread]