Austin Group Defect Tracker

Aardvark Mark IV


Viewing Issue Simple Details Jump to Notes ] Issue History ] Print ]
ID Category Severity Type Date Submitted Last Update
0000857 [1003.1(2013)/Issue7+TC1] Shell and Utilities Comment Omission 2014-07-08 10:14 2019-06-10 08:54
Reporter jammule View Status public  
Assigned To
Priority normal Resolution Accepted As Marked  
Status Closed  
Name Jarmo Jaakkola
Organization
User Reference
Section make
Page Number 2937
Line Number 97105-97113
Interp Status ---
Final Accepted Text Note: 0002393
Summary 0000857: Make rules which do not create the target file or do unexpected things with its timestamp
Description

I haven't been able to find clear answers from the standard to some behavior that seems to be taken for granted with make. These are all somewhat related, so I'll list them here instead of making a separate issue from each of them.



Case 1: It is customary to use the following idiom to force a target's related commands to always run:



foo: FORCE
    commands...

FORCE:


(This is what some implementations offer the ".PHONY: foo" special target as an extension for.)



My reading of the standard does not come clear why, or if at all, this should work (assuming FORCE does not exist). This is the current formulation on page 2937, lines 97105-97113:



The make utility attempts to perform the actions required to ensure that the specified targets are up-to-date. A target is considered out-of-date if it is older than any of its prerequisites or if it does not exist. The make utility shall treat all prerequisites as targets themselves and recursively ensure that they are up-to-date, processing them in the order in which they appear in the rule. The make utility shall use the modification times of files to determine whether the corresponding targets are out-of-date.



After make has ensured that all of the prerequisites of a target are up-to-date and if the target is out-of-date, the commands associated with the target entry shall be executed. If there are no commands listed for the target, the target shall be treated as up-to-date.



When "make foo" is issued this is what I think should happen:




  1. The rule for target foo is looked up and found. To determine if foo is out-of-date,first each of its dependencies becomes a target to update itself.

  2. The rule for FORCE is looked up and found. It has no dependencies, but it does not exist, so it is out-of-date.

  3. There are no commands listed for the target, so the target comes up-to-date.

  4. All of foo's prerequisites are now up-to-date, foo's out-of-dateness can be determined.

  5. The ONLY way for a target to be out-of-date is for any of its prerequisites to be newer than itself (based on timestamp) or the target not to exist. FORCE does not exist, so there is no timestamp to compare and now one of the inputs to the decision is unspecified. What should happen?



Based on tests with NetBSD and GNU make the convention is to regard, for the current run, the target as having a timestamp that is newer than any target it is a prerequisite for (i.e. force them out-of-date). The requirement of a target entry with no commands being considered up-to-date hints at this also.



Also, I think that in the sentence "If there are no commands listed for the target, [...]" the word "target" should be replaced with "target entry". As it now stands the sentence could be taken to mean "In the case there are no commands in the applicable rule or there is no applicable rule at all, the target shall be treated as up-to-date." This is because "target" is sometimes used for a single rule entry, sometimes for the collection of all matching rule entries and and sometimes for the target name.



Case 2: Extension of the previous one:



foo: bar
    commands...

bar:
    commands_that_do_not_create_bar...


What now? Nowhere is there a requirement that the executed commands actually create the target. Nor should there be, because of the convention of meta-targets "all", "clean", etc. Based on my tests, this works exactly the same as the previous case.



Of course, in both cases, if foo's commands actually try to use bar, it will fail and that is an error on the application's side.



Case 3: Assuming bar exists and is older than foo:



foo: bar
    commands...

bar:
    commands_that_do_not_update_bar's_modification_time


Or even better, assuming bar is newer than foo:



foo: bar
    commands...

bar:
    make_bar's_modification_time_older_than_foo's...


It is not necessarily immediately obvious that the timestamps of a target and its prerequisites are to be checked after the prerequisites have been brought up-to-date. First it is said: "A target is considered out-of-date if it is older than any of its prerequisites or if it does not exist." Later: "After make has ensured that all of the prerequisites of a target are up-to-date and if the target is out-of-date, [...]" These do not in my opinion forbid a naive implementation that would check the out-of-dateness of a target before its prerequisites are updated.



Case 4: It is not specified that it should be an error if there is no rule for target and there is no corresponding file. Neither is it specified that a target, for which no rule but a corresponding file exists, is effectively equivalent to



target:
Desired Action

If the observed implementation functionality is supposed to be standards compliant, the text on page 2937, lines 97105-97113 should be changed. Here is a suggestion, with the changes in bold:



The make utility attempts to perform the actions required to ensure that the specified targets are up-to-date. A target is considered out-of-date when all of its prerequisites are up-to-date and it is older than any of them, or if it does not exist. The make utility shall treat all prerequisites as targets themselves and recursively ensure that they are up-to-date, processing them in the order in which they appear in the rule. The make utility shall use the modification times of files to determine whether the corresponding targets are out-of-date.



After make has ensured that all of the prerequisites of a target are up-to-date and if the target is out-of-date, the commands associated with the target entry shall be executed. If there are no commands listed for the target entry, the target shall be treated as up-to-date. If a file corresponding to the target does not exist after the target has been successfully brought up-to-date, the target shall be treated as being newer than any target it is a prerequisite for.



When no rule matches a target for which a corresponding file exists, the target shall be treated as up-to-date. It is an error if there is no rule for a target that does not have a corresponding file.

Tags tc2-2008
Attached Files

- Relationships
related to 0000523Appliedajosey 1003.1(2008)/Issue 7 Add support for special target .PHONY in make 
related to 0000763Closedajosey 1003.1(2008)/Issue 7 If rule has no prerequisites or commands, and target is non-existent, imagine it's been updated 

-  Notes
(0002335)
eblake (manager)
2014-08-07 16:18

see 0000523 for case 1
(0002336)
mdempsky (reporter)
2014-08-07 17:16

It strikes me that there are two key issues here:

1. The "make" section doesn't adequately define "out-of-date", "up-to-date", or "bring a target up-to-date". It gives a [questionable] definition for "out-of-date", and it's somewhat implied that "up-to-date" means "not out-of-date", and what it means to "bring a target up-to-date" is only explicitly described for the case where the target has no commands.

2. The wording "After make has ensured that all of the prerequisites of a target are up-to-date and if the target is out-of-date" implies the "out-of-date" check is done *after* recursing on the prerequisites, whereas I believe existing make implementations determine "out-of-date"ness before running any commands.


Here's a quick test to try:

    $ cat Makefile
    .POSIX:
    one: two
    echo one
    two:
    echo two

    $ touch one

    $ make one

Strictly following POSIX's definition of "out-of-date", target "two" here is "out-of-date" because it does not exist, but target "one" *does* exist and its not older than any of its prerequisites. It stands to reason that a POSIX-compliant make utility should only run "echo two".

However, at least GNU make and NetBSD make (tested on Ubuntu 14.04) run both the "echo two" command and then also "echo one". I'd be interested in knowing if any other make implementations behave differently.


I'd suggest addressing this issue along the following lines:

  1. Define that "out-of-date" means the target does not exist, its file modification time is older than any of its prerequisites, or any of its prerequisites are "out-of-date". The determination of whether targets are "out-of-date" is made before "make" executes any commands.

  2. Define that to "bring a target up-to-date" for an "out-of-date" target means to bring each of its prerequisites up-to-date (in order) and then to execute the target's commands (if any). If a target is not "out-of-date", then nothing needs to be done to bring it up-to-date.
(0002337)
mdempsky (reporter)
2014-08-07 17:17

Mantis mangled my example Makefile, so here it is again (hopefully mangling free):

.POSIX:
one: two
        echo one
two:
        echo two
(0002338)
antoinel (reporter)
2014-08-08 10:41
edited on: 2014-08-08 10:51

see 0000763 for case 4, first part

(0002340)
jammule (reporter)
2014-08-08 11:44
edited on: 2014-08-08 11:47

Regarding mdempsky's comment in (Note: 0002336)

I believe existing make implementations determine "out-of-date"ness before running any commands.

This would be incorrect. Try running "make one" twice with this makefile:

one: two
        touch one
two: three
        [ -e two ] || touch two
three: FORCE
        touch three
FORCE:

If make would check the out-of-dateness before running any commands, all targets should be created every time. This does not happen with at least NetBSD or GNU make. On the second run "one" is not touched, because "two" is not actually updated even if it was out-of-date compared to "three". This is in my opinion what is expected and is reasonable and also at least one of the reasons why the "-t" command line switch exists.

Consider a case where a single file is used to generate multiple other files, which in turn are dependencies for other files. For example, some automatic code generation tool creates multiple header files for different modules. Just because the input for the code generator has changed does not mean that all or even any of the generated files have changed semantically.

Running the commands to generate the headers cannot be avoided because their dependencies are newer, but those rules may well utilize temporary files to check if the generated file has actually changed and only update the target when that happens. This will prevent make (at least GNU and NetBSD) from unnecessarily updating any of the targets, which might be numerous, that depend on the header.

Thus, I do not think it would be wise to add this requirement to the standard:

The determination of whether targets are "out-of-date" is made before "make" executes any commands.


(0002343)
mdempsky (reporter)
2014-08-08 17:10

Ah, I stand corrected. Thanks for that demonstration test case!
(0002351)
geoffclare (manager)
2014-08-21 15:35
edited on: 2014-09-04 16:06

On page 2937 line 97106 section make

Change from:

A target is considered out-of-date if it is older than any of its prerequisites or if it does not exist.

to:

A target is considered out-of-date when all of its prerequisites are up-to-date and it is older than any of them, or if it does not exist. A target may also be considered out-of-date when it has the same timestamp as any of its prerequisites.

On page 2937 line 97112 section make

Change from:

If there are no commands listed for the target, the target shall be treated as up-to-date.

to:

If there are no commands listed for the target entry, the target shall be treated as up-to-date. If a file corresponding to the target does not exist after the target has been successfully brought up-to-date, the target shall be treated as being newer than any target it is a prerequisite for.

When no rule matches a target for which a corresponding file exists, the target shall be treated as up-to-date. It shall be an error if there is no target rule for a prerequisite that does not have a corresponding file.

On page 2948 line 97603 add a new paragraph to the APPLICATION USAGE:

Shell command sequences like "make; cp original copy; make" may have problems on filesystems where the timestamp resolution is the minimum (1 second) required by the standard and where make considers identical timestamps to be up to date. Conversely, rules like "copy: original; cp -p original copy" will result in redundant work on make implementations that consider identical timestamps to be out of date.

On page 2954 line 97847 add a new paragraph to the RATIONALE:

On most historic systems, the make utility considered a target with a prerequisite that had an identical timestamp up-to-date. The HP-UX implementation of make treated it as out-of-date. The standard now allows either behavior, but implementations are encouraged to follow the example set by HP-UX. This is especially important on filesystems where the timestamp resolution is the minimum (1 second) required by the standard. All implementations of make should make full use of the finest timestamp resolution available on the filesystems holding targets and prerequisites to ensure that targets are up-to-date even for prerequisite files with timestamps that were updated within the same second.

(0002353)
eggert (reporter)
2014-08-21 16:13

There's a misspelling "implementaions" in the accepted text.

More importantly, the new paragraph of the rationale should not recommend the HP-UX behavior, as the traditional behavior is longstanding and has some performance advantages. For example, given the rule 'copy: original; cp -p original copy', if I run HP-UX 'make' twice, the second run will copy the file unnecessarily, but GNU 'make' will do the right thing. This comes up even more often on filesystems with coarse timestamps, because then even plain 'cp' can be affected.

I suggest changing this:

The standard now allows either behavior, but implementaions are encouraged to follow the example set by HP-UX. This is especially important on filesystems where the timestamp resolution is the minimum (1 second) required by the standard.

to this:

The standard now allows either behavior.

I also suggest appending the following text:

Shell command sequences like "make; cp original copy; make" may have problems on filesystems where the timestamp resolution is the minimum (1 second) required by the standard and where 'make' considers identical timestamps to be up to date. Conversely, rules like "copy: original; cp -p original copy" will result in redundant work on 'make' implementations that consider identical timestamps to be out of date.
(0002372)
geoffclare (manager)
2014-09-04 16:07

In the Sept 4 teleconference it was decided to include the final paragraph from Note: 0002353 as application usage, and Note: 0002351 has been updated accordingly.
(0002373)
jammule (reporter)
2014-09-05 08:33
edited on: 2014-09-05 08:37

I think that the accepted change just made all implementations non-compliant...

It shall be an error if there is no target rule for a prerequisite that does not have a corresponding file.

This would mean that it should always be an error if the target of an inference rule did not exist before make was run. I did leave the bolded word out from my proposal for just that reason. I'd suggest changing that sentence like this:

It shall be an error if there is no <del>target</del><ins>applicable</ins> rule for a prerequisite that does not have a corresponding file.

(It seems that the del and ins elements are not supported. Please render them properly in your mind.)

(0002376)
geoffclare (manager)
2014-09-11 16:18
edited on: 2014-09-11 16:37

On page 2937 line 97106 section make, change from:

A target is considered out-of-date if it is older than any of its prerequisites or if it does not exist.

to:

A target is considered out-of-date if it does not exist and has not already been made up-to-date by the current invocation of make, if it is older than any of its existing prerequisites, or if any of its existing prerequisites are out-of-date. A target may also be considered out-of-date when it has the same timestamp as any of its prerequisites that have not been made up-to-date by the current invocation of make.

On page 2937 line 97112 section make, change from:

If there are no commands listed for the target, the target shall be treated as up-to-date.

to:

If there are no commands listed for the target entry, the target shall be treated as up-to-date. If a file corresponding to the target does not exist after the target has been successfully brought up-to-date, the target shall be treated as being newer than any target for which it is a prerequisite.

When no rule matches a target for which a corresponding file exists, the target shall be treated as up-to-date. It shall be an error if make attempts to bring a target up-to-date, the target does not exist, and there is neither a target rule nor an inference rule for that target.

On page 2948 line 97603 add a new paragraph to the APPLICATION USAGE:

Shell command sequences like "make; cp original copy; make" may have problems on filesystems where the timestamp resolution is the minimum (1 second) required by the standard and where make considers identical timestamps to be up to date. Conversely, rules like "copy: original; cp -p original copy" will result in redundant work on make implementations that consider identical timestamps to be out of date.

On page 2954 line 97847 add a new paragraph to the RATIONALE:

On most historic systems, the make utility considered a target with a prerequisite that had an identical timestamp up-to-date. The HP-UX implementation of make treated it as out-of-date. The standard now allows either behavior, but implementations are encouraged to follow the example set by HP-UX. This is especially important on filesystems where the timestamp resolution is the minimum (1 second) required by the standard. All implementations of make should make full use of the finest timestamp resolution available on the filesystems holding targets and prerequisites to ensure that targets are up-to-date even for prerequisite files with timestamps that were updated within the same second.

(0002383)
Konrad_Schwarz (reporter)
2014-09-12 08:55

The proposed change of Note 2376 for line 97106 has the problem that it does not cover the case that a prerequisite does not exist.

This is easily rectified by using the following wording, as proposed in my E-mail from September 10, 2014.

> A target is considered out-of-date if it does not exist, is older than
> any of its existing prerequisites, or if any of its prerequisites are
> out-of-date. A target may also be considered out-of-date if it is as old
> as any of its existing prerequisites.

Also the wording in Note 2376 assumes that make rechecks the
time stamps of its targets during execution. My understanding has always
been that Make operates in two passes:

In the first pass, Make generates a dependency tree among its targets
using the prerequisite information,
and determines which targets are out-of-date.

In the second pass, Make executes the command blocks for the out-of-date
targets -- but only for those targets listed on the command line or the
default target and their prerequisites.

It is not an error for no command block to exist for such a target listed in a
rule (but it is an error for a non-existing prerequisite to have
no explicit rule and no applicable automatic rule). During this pass,
file timestamps are not reexamined and the dependency tree is not modified.

This two pass implementation manifests itself in the different ways macros
are expanded in dependency lines and command blocks. In dependency lines,
the current value of the macro is used, as defined just before reading
the dependency line. This corresponds to how variables are used in
conventional sequential programming semantics.
For command blocks however, the _final_ value
of the macro, as set after reading the entire Makefile and any included
files, is used.

It follows that the suggested change to line 97112 is superfluous
if not incorrect. If anything, I would add to the original line 97112:

It is an error if there is neither a target rule nor an inference rule for a
non-existing target to be built by make.
(0002388)
Konrad_Schwarz (reporter)
2014-09-15 10:24

As Geoff Clare and Note 2340 point out, Make rechecks the
time stamps of its targets during execution, in contrast
to my assertion in the previous note.

The seminal document (Make — A Program for Maintaining Computer Programs,
S.I. Feldman) states this as follows:

The basic operation of make is to update a target file by ensuring that
all of the files on which it depends exist and are up to date, then
creating the target if it has not been modified since its dependents were.

So I think it is safe and proper to codify this behavior into the
specification.
(0002390)
rhansen (manager)
2014-09-18 15:04

I have some revisions to Note: 0002376 in progress; I will post them when they're ready.
(0002393)
rhansen (manager)
2014-09-18 16:59
edited on: 2014-09-25 15:42

On page 2937 lines 97106-97107 (make Extended Description), change from:
A target is considered out-of-date if it is older than any of its prerequisites or if it does not exist.

to:
A target shall be considered up-to-date if it exists and is newer than all of its dependencies, or if it has already been made up-to-date by the current invocation of make (regardless of the target's existence or age). A target may also be considered up-to-date if it exists, is the same age as one or more of its prerequisites, and is newer than the remaining prerequisites (if any).

On page 2937 lines 97111-97113 (make Extended Description), change from:
After make has ensured that all of the prerequisites of a target are up-to-date and if the target is out-of-date, the commands associated with the target entry shall be executed. If there are no commands listed for the target, the target shall be treated as up-to-date.

to:
To ensure that a target is up-to-date, make shall ensure that all of the prerequisites of a target are up-to-date, then check to see if the target itself is up-to-date. If the target is not up-to-date, the target shall be made up-to-date by executing the rule's commands (if any). If the target does not exist after the target has been successfully made up-to-date, the target shall be treated as being newer than any target for which it is a prerequisite.

If a target exists and there is neither a target rule nor an inference rule for the target, the target shall be considered up-to-date. It shall be an error if make attempts to ensure that a target is up-to-date but the target does not exist and there is neither a target rule nor an inference rule for the target.

After page 2948 line 97603 add a new paragraph to the APPLICATION USAGE:
Shell command sequences like "make; cp original copy; make" may have problems on filesystems where the timestamp resolution is the minimum (1 second) required by the standard and where make considers identical timestamps to be up to date. Conversely, rules like "copy: original; cp -p original copy" will result in redundant work on make implementations that consider identical timestamps to be out of date.

After page 2954 line 97847 add a new paragraph to the RATIONALE:
On most historic systems, the make utility considered a target with a prerequisite that had an identical timestamp as up-to-date. The HP-UX implementation of make treated it as out-of-date. The standard now allows either behavior, but implementations are encouraged to follow the example set by HP-UX. This is especially important on filesystems where the timestamp resolution is the minimum (1 second) required by the standard. All implementations of make should make full use of the finest timestamp resolution available on the filesystems holding targets and prerequisites to ensure that targets are up-to-date even for prerequisite files with timestamps that were updated within the same second. However, if the timestamp resolutions of the filesystems containing a target and a prerequisite are different, the timestamp with the more precise resolution should be rounded down to the resolution of the less precise timestamp for the comparison.



- Issue History
Date Modified Username Field Change
2014-07-08 10:14 jammule New Issue
2014-07-08 10:14 jammule Name => Jarmo Jaakkola
2014-07-08 10:14 jammule Section => make
2014-07-08 10:14 jammule Page Number => 2937
2014-07-08 10:14 jammule Line Number => 97105-97113
2014-07-08 10:24 jammule Issue Monitored: jammule
2014-07-08 10:25 jammule Issue End Monitor: jammule
2014-08-07 16:18 eblake Note Added: 0002335
2014-08-07 16:18 eblake Relationship added related to 0000523
2014-08-07 17:16 mdempsky Note Added: 0002336
2014-08-07 17:17 mdempsky Note Added: 0002337
2014-08-08 10:41 antoinel Note Added: 0002338
2014-08-08 10:42 antoinel Note Edited: 0002338
2014-08-08 10:42 antoinel Note Edited: 0002338
2014-08-08 10:43 antoinel Note Edited: 0002338
2014-08-08 10:44 antoinel Note Edited: 0002338
2014-08-08 10:47 antoinel Note Edited: 0002338
2014-08-08 10:47 antoinel Note Edited: 0002338
2014-08-08 10:51 antoinel Note Edited: 0002338
2014-08-08 11:44 jammule Note Added: 0002340
2014-08-08 11:47 jammule Note Edited: 0002340
2014-08-08 12:22 eblake Relationship added related to 0000763
2014-08-08 17:10 mdempsky Note Added: 0002343
2014-08-21 15:35 geoffclare Note Added: 0002351
2014-08-21 15:39 geoffclare Interp Status => ---
2014-08-21 15:39 geoffclare Final Accepted Text => Note: 0002351
2014-08-21 15:39 geoffclare Status New => Resolved
2014-08-21 15:39 geoffclare Resolution Open => Accepted As Marked
2014-08-21 15:39 geoffclare Tag Attached: tc2-2008
2014-08-21 16:13 eggert Note Added: 0002353
2014-08-22 09:20 geoffclare Note Edited: 0002351
2014-09-04 16:06 geoffclare Note Edited: 0002351
2014-09-04 16:07 geoffclare Note Added: 0002372
2014-09-05 08:33 jammule Note Added: 0002373
2014-09-05 08:34 jammule Note Edited: 0002373
2014-09-05 08:35 jammule Note Edited: 0002373
2014-09-05 08:36 jammule Note Edited: 0002373
2014-09-05 08:37 jammule Note Edited: 0002373
2014-09-11 16:18 geoffclare Note Added: 0002376
2014-09-11 16:20 geoffclare Final Accepted Text Note: 0002351 => Note: 0002376
2014-09-11 16:37 geoffclare Note Edited: 0002376
2014-09-12 08:55 Konrad_Schwarz Note Added: 0002383
2014-09-15 10:24 Konrad_Schwarz Note Added: 0002388
2014-09-18 15:04 rhansen Note Added: 0002390
2014-09-18 15:05 nick Status Resolved => Under Review
2014-09-18 15:05 nick Resolution Accepted As Marked => Reopened
2014-09-18 16:59 rhansen Note Added: 0002393
2014-09-18 17:01 rhansen Note Edited: 0002393
2014-09-18 17:04 rhansen Note Edited: 0002393
2014-09-18 17:05 rhansen Note Edited: 0002393
2014-09-18 17:13 rhansen Note Edited: 0002393
2014-09-18 17:14 rhansen Note Edited: 0002393
2014-09-25 15:22 rhansen Note Edited: 0002393
2014-09-25 15:35 rhansen Note Edited: 0002393
2014-09-25 15:41 rhansen Note Edited: 0002393
2014-09-25 15:42 rhansen Note Edited: 0002393
2014-09-25 15:43 geoffclare Final Accepted Text Note: 0002376 => Note: 0002393
2014-09-25 15:43 geoffclare Status Under Review => Resolved
2014-09-25 15:43 geoffclare Resolution Reopened => Accepted As Marked
2019-06-10 08:54 agadmin Status Resolved => Closed


Mantis 1.1.6[^]
Copyright © 2000 - 2008 Mantis Group
Powered by Mantis Bugtracker