automake
[Top][All Lists]
Advanced

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

Re: builddir vs. srcdir


From: Stepan Kasal
Subject: Re: builddir vs. srcdir
Date: Wed, 16 Mar 2005 18:13:38 +0100
User-agent: Mutt/1.4.1i

Hello,

On Sat, Mar 12, 2005 at 06:56:20PM +0200, Paul Pogonyshev wrote:
> Everything seems to work just fine and as expected,

your code, which is in whole cited below, doesn't actually know
about the dependency
foo.c foo.h: foo.list

So if you change the .list file, the other files won't be rebuilt.
This might be a dangerous bug.

In general, stamps are always dangerous, so it's good to avoid them if
possible.  I'd try something like this:

[file `aux/list.make']
SUFFIXES = .list
.list.c: Makefile $(PARSE_LIST_COMMAND)
        $(PARSE_LIST_BUILD_RULE)
.list.h: Makefile $(PARSE_LIST_COMMAND)
        $(PARSE_LIST_BUILD_RULE)
PARSE_LIST_BUILD_RULE =                                         \
        $(PARSE_LIST_COMMAND) $(PARSE_LIST_FLAGS)               \
        `test -f '$<' || echo '$(srcdir)/'`$< $*.h $*.c &&      \
        touch $*.h

[usage]
LIST_FILES = foo.list bar.list
# Prevent problems with parallel make:
foo.h: foo.c
bar.h: bar.c

PARSE_LIST_COMMAND = ...
PARSE_LIST_FLAGS   = ...

noinst_LIBRARIES = libfoo.a
libfoo_a_SOURCES = ... $(LIST_FILES)

# This hint is needed only for included files; *.c files
# are handled by normal target dependencies:
BUILT_SOURCES = $(LIST_FILES:.list=.h)

MOSTLYCLEANFILES =  $(LIST_FILES:.list=.h) $(LIST_FILES:.list=.c)

include $(top_srcdir)/aux/list.make


Let me add some comments:
1) The maintainer of Automake said that $(LIST_FILES:.list=.h) is safe,
   and I trust him.
2) nodist_libfoo_a_SOURCES was redundant, especially the .c files.
   Automake knows how to transform .list to .o, and listing the
   intermediate files again could cause problems.
3) I try to have the BUILT_SOURCES hist as small as possible, so when
   the .c file is a prerequisite of the corresponding .o, there is no
   need to pre-build it using BUILT_SOURCES.
4) With parallel make, the PARSE_LIST_COMMAND cnnot be run twice in
   parallel, because of the "foo.c: foo.h" dependency.  So we are safe.

One more comment:
5) It looks that the PARSE_LIST_COMMAND will be executed twice:
forst to create foo.c and then again to create foo.h.

But this is actually not the case with GNU make: when command is to
be called for the second time, make discovers, that the file foo.h
has somehow appeared there, and that it's newer then its prerequisities,
foo.list and foo.c (see the touch command in PARSE_LIST_BUILD_RULE),
so there is no longer any need to rebuild it.

Even if some inferior implementations of make were not that clever, 
the only problem would be that each pair of the files would be created
twice.  I think we can live with that.

What if we used such an "inferior" make implementation for parallel
build?  Well, in general, this could bring problems.  But I think this
combination simply won't happen.

Happy making,
        Stepan

--- your code:
> [file `aux/list.make']
> 
> SUFFIXES = .list
> 
> $(LIST_STAMP_FILES) : Makefile $(PARSE_LIST_COMMAND)
> 
> # `PARSE_LIST_COMMAND' and `PARSE_LIST_FLAGS' should be set by the
> # includer.
> #
> PARSE_LIST = $(PARSE_LIST_COMMAND) $(PARSE_LIST_FLAGS)
> 
> # We use `cmp' here to avoid unneeded recompilations of files that
> # depend on generated ones (only really useful for `.h' files.)
> #
> PARSE_LIST_BUILD_RULE =                                               \
>       if $(PARSE_LIST) `test -f '$<' || echo '$(srcdir)/'`$<  \
>                        $*.h.new $*.c.new; then                \
>         if cmp -s $*.c.new $*.c;                              \
>           then rm -f $*.c.new; else mv -f $*.c.new $*.c;      \
>         fi;                                                   \
>         if cmp -s $*.h.new $*.h;                              \
>           then rm -f $*.h.new; else mv -f $*.h.new $*.h;      \
>         fi;                                                   \
>         echo timestamp > $@;                                  \
>       else                                                    \
>         (rm -f $*.c $*.c.new $*.h $*.h.new ; exit 1)          \
>       fi
> 
> .list.stamp:
>       $(PARSE_LIST_BUILD_RULE)
> 
> # Since $(LIST_GENERATED_FILES) defined by the includer don't (at
> # least shouldn't) have any dependencies, if this rule is being
> # executed, it probably means that one of the files was removed.
> # Then all we can do is to force rebuilding of corresponding stamp
> # file, which builds the required sources ``by side-effect.''
> #
> $(LIST_GENERATED_FILES):
>       rm -f $*.stamp;
>       $(MAKE) $(AM_MAKEFLAGS) $*.stamp
> 
> 
> [usage]
> 
> noinst_LIBRARIES = libfoo.a
> 
> LIST_FILES = foo.list bar.list
> 
> LIST_STAMP_FILES = foo.stamp bar.stamp
> 
> LIST_GENERATED_FILES = foo.c bar.c foo.h bar.h
> 
> PARSE_LIST_COMMAND = ...
> PARSE_LIST_FLAGS   = ...
> 
> include $(top_srcdir)/aux/list.make
> 
> libfoo_a_SOURCES = ... $(LIST_FILES)
> 
> nodist_libfoo_a_SOURCES = $(LIST_GENERATED_FILES)
> 
> BUILT_SOURCES = $(LIST_STAMP_FILES)
> 
> MOSTLYCLEANFILES = $(LIST_STAMP_FILES) $(LIST_GENERATED_FILES)




reply via email to

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