On 03.11.2017 12:43, Steven Watanabe via Boost-build wrote:
AMDG

On 11/03/2017 09:35 AM, Stefan Seefeld via Boost-build wrote:
I'm investigating an issue with bjam's handling of temporaries. It seems I'm 
still not understanding how bjam handles them. Consider this code snippet:

actions make {
   touch $(<)
}

actions cat {
   cat $(>) > $(<)
}

make A ;
cat B : A ;
cat C : A ;
cat D : B C ;

TEMPORARY B ;

DEPENDS B : A ;
DEPENDS D : B C ;

UPDATE D ;


Running `bjam` on this the first time creates A, B, C, and D, as expected. 
Calling it again updates D again, and I don't understand why. If I remove the 
TEMPORARY flag on B, D isn't updated, so this forceful update of D seems to be 
caused by B being a temp.

The second issue seems even more serious: if I remove B, and call bjam again, 
nothing is updated, as expected. But if I remove B and C and call bjam, I get an 
error as D is attempted to be updated after C is remade, but B wasn't updated 
(it's marked "temporary stable" in the debug output). Why isn't B updated first ?

The logic in make.c suggest's that, despite B's binding is set to PARENT (i.e., 
D), its fate is determined before that of D, and thus is found to be stable, 
even though a little later D's fate is set to update. Shouldn't a temporary's 
fate be determined *after* its parent ?

What am I missing ?

Two things:

First of all, a TEMPORARY target is supposed to be
deleted:

actions RmTemps {
  rm $(>)
}
...
cat D : B C ;
RmTemps D : B ;

  Rebuilding when a temporary is present seems to be
deliberate, though I'm not quite clear on the logic
behind this.
#define T_FATE_SPOIL          4       /* >= SPOIL rebuilds parents */
#define T_FATE_ISTMP          4       /* unneeded temp target oddly
present */

Yeah, I have wondered about that, too. I think this is manifest in code as https://github.com/boostorg/build/blob/develop/src/engine/make.c#L621-L624, which I have tentatively commented out, as I don't follow the rationale of existing temps being considered tainted. (Quite the opposite, actually: if I keep a temp around, perhaps I'm in the middle of a debug session where I do want to inject code into the otherwise automated process. So I'd rather treat existing "temps" as ordinary (non-temp) targets.)
Second, TEMPORARY is really designed to be used with the
`updated` actions flag:

actions piecemeal updated ar {
  ar rc $(<) $(>)
}

TEMPORARY x.o y.o z.o ;
ar x.a : x.o y.o z.o ;
RmTemps x.a : x.o y.o z.o ;

In this case, rebuilding x.a because of one changed source,
should not force the other object files to be created.

Are you saying that TEMPORARY isn't used anywhere else ? What about the case of a library metatarget built from sources, where object files are marked as TEMPORARY ?
In my original (faber) case, I build a "binary" B from a source B.c and a library L, with a temporary object file B.o being removed after a successful build. If I then touch the library sources L.c, the library is rebuilt, and the binary relinked, but its object file B.o not being recompiled (this is the symptom I narrowed down to the above minimal test case), this fails.
Are you saying I shouldn't be using the TEMPORARY flag for B.o (et al.) ? How is b2 solving this case ?

Thanks,

Stefan
-- 

      ...ich hab' noch einen Koffer in Berlin...