make-alpha
[Top][All Lists]
Advanced

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

Re: A simple patch.


From: Ramón García
Subject: Re: A simple patch.
Date: Sat, 14 Apr 2007 20:50:26 +0200

First of all, there is not a definitive decision about the user
interface. So this is just an idea of the intention.

There are two purposes of this project, somewhat related: user defined
out of date detection, and persistent variables.

Normally make uses file dates for deciding if a target must be rebuilt
or not. This extension will allow the user to decide how is it
determined. The current proposal consists in that the variable name
.OUT_OF_DATE, if defined, contains an expression that will be
evaluated, and if true (in the sense of the built in function if),
then the recipe will be run. This has the advantage that one can
define a global .OUT_OF_DATE, or one local to a target, or out of the
Makefile as a command line argument or environment variable.

Use cases include:
1) Determining if file changed since last compilation. There are
issues with date accuracy: in fast systems compilations can last less
than a second, and thus target and recipes have exactly

2) Determining if specific parts of a file changed. For instance, a
java byte code file includes both an interface and an implementation.
A change in the java source may cause a change in implementation
without interface change. In that case, other source files which
depend on the interface only need not be recompiled.

3)  Recompiling if CFLAGS changed

and so on.

It will be necessary to define new functions, such as comparison
functions for dates. Here are some suggestion of new functions or
function syntax:

 - The function args: We have functions for booleans and, or. But
this functions expect a list of comma separated arguments instead of a
list (that is, space separated arguments, which is how a list is
usually represented in make). The function args is actually a syntax
for inserting the members of a list in the arguments of a function.

- Comparison functions: lt a b, gt a b: compare two numbers, intended
to be used for comparing file timestamps. eq a b returns true if a and
b are equal.

- The function mtime gets the modification time of a file

- A builtin variable $.RECIPE that returns the expanded recipe as a
string. This is useful for dependecies on the compilation commands.

- Cached function calls: A function can be declared cached so that if
it is called several times with the same arguments, the result wil be
remembered rather than evaluated. The idea comes from Maple. A
suggested syntax is:
   function |= definition
  for inline definitions or, for multiline definitions:
         cached define function
             body
         endef

 Cached functions calls will be useful to avoid expensive
evaluations, such as the md5sum of a source used for several targets.

- The assign function assigns a value to a variable. It returns the value.

An example that illustrates the usage of these two extensions would be
a value of OUT_OF_DATE that express the default method of make. In
order to see if the target is more recent than a single source:
${gt ${mtime $src} ${mtime $target}}

Now, do this for all sources in $^, and the target is $ @:
${foreach src,$^,${gt ${mtime $src} ${mtime address@hidden

Now we have a list or booleans (where false is empty). We want to "or"
them, but it is a list rather than a,b,c. We use the function args:
${args ${foreach src,$^,${gt ${mtime $src} ${mtime address@hidden

This "expression" cannot be used isolately. It is only intended to be
inserted in the list of function arguments. The complete expression
is:

.OUT_OF_DATE=${or ${args ${foreach src,$^,${gt ${mtime $src} ${mtime 
address@hidden

Note the usage of args. "or" would work with ${or 1,0,0}, but not with
${or 1 0 0 0}. The args function makes it possible to write ${or
$args{1 0 0}}. It is possible that this example requires some touches
for ensuring that the expansion of functions and variables take place
at the right time.

Let us apply this method for determining evaluation depending on
content change. We need somewhere where we can store the md5sums in
the previous compilation. I know that you will have much better ideas,
but for now let us use $persist_varname, and assume make magically
stores variables with this name in persistent storage.

Let us assume that the md5sum prints only the hash value. The
expression for evaluating the sum is:
${shell md5sum $src}

For accessing the stored sum we would use $persist_src, except that
src is variable. So we want to write something like $persist_$src,
which is (IHMO) ${value persist_$src}

Now for comparing the stored value with the evaluated one:
${eq ${shell md5sum $src}, ${value persist_$src}}

And repeat for every src in $^:

${foreach src,$^,${eq ${shell md5sum $src}, ${value persist_$src}}}

And a logical or:

${or ${args ${foreach src,$^,${eq ${shell md5sum $src}, ${value
persist_$src}}}}}

There is a fault with this method: the md5sum stored is not updated
after this rule is run.

One issue observed when experimenting is that the variables like
.OUT_OF_DATE are automatically propagated from the compilation rule of
a target to the rules of its sources. Sometimes this might be
desirable, but often .OUT_OF_DATE will contain elements specific for
some specific rule. Thus I suggest a syntax for defining variables
that does not propagate the definition to its children. A possible
syntax would be

.target: variable *= value

though other methods would be also possible.

As we have shown, this extension needs persistent variables to be
useful. This raises two issues: how to express them, and how to store
them.

For storage I would suggest to use plain text files. This is used by
the Linux kernel compilation system, which stores CFLAGS for compiling
ai.o as ai.o.cflags. This is can be inspected by the developer. And it
is simple.

Persistent variables will be most often be associated with some file
(perhaps a target or source). Thus a possible syntax is to use a built
in function persist, which takes two arguments, a file name and a
name, so one would write ${persist filename name}. This is a somewhat
unusual function, since it can be used as a lvalue:

${persist filename name} := value

As you have seen, many of the ideas require experimentation. This is
just a draft.




reply via email to

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