@@ -609,6 +609,18 @@ bool FakeCommandRunner::StartCommand(Edge* edge) {
609
609
if (fs_->ReadFile (edge->inputs_ [0 ]->path (), &content, &err) ==
610
610
DiskInterface::Okay)
611
611
fs_->WriteFile (edge->outputs_ [0 ]->path (), content);
612
+ } else if (edge->rule ().name () == " cp-plus-bis" ) {
613
+ assert (!edge->inputs_ .empty ());
614
+ assert (edge->outputs_ .size () >= 1 );
615
+ string content;
616
+ string err;
617
+ if (fs_->ReadFile (edge->inputs_ [0 ]->path (), &content, &err) ==
618
+ DiskInterface::Okay) {
619
+ fs_->Tick ();
620
+ fs_->WriteFile (edge->outputs_ [0 ]->path () + " .bis" , content);
621
+ fs_->Tick ();
622
+ fs_->WriteFile (edge->outputs_ [0 ]->path (), content);
623
+ }
612
624
} else if (edge->rule ().name () == " touch-implicit-dep-out" ) {
613
625
string dep = edge->GetBinding (" test_dependency" );
614
626
fs_->Tick ();
@@ -4312,3 +4324,173 @@ TEST_F(BuildTest, ValidationWithCircularDependency) {
4312
4324
EXPECT_FALSE (builder_.AddTarget (" out" , &err));
4313
4325
EXPECT_EQ (" dependency cycle: validate -> validate_in -> validate" , err);
4314
4326
}
4327
+
4328
+ TEST_F (BuildTest, RebuildMissingDynamicOutputs) {
4329
+ string err;
4330
+ BuildLog build_log;
4331
+
4332
+ {
4333
+ FakeCommandRunner command_runner (&fs_);
4334
+ State state;
4335
+ DepsLog deps_log;
4336
+ ASSERT_TRUE (deps_log.OpenForWrite (" ninja_deps" , &err));
4337
+ ASSERT_EQ (" " , err);
4338
+ Builder builder (&state, config_, &build_log, &deps_log, &fs_, &status_, 0 );
4339
+ builder.command_runner_ .reset (&command_runner);
4340
+
4341
+ ASSERT_NO_FATAL_FAILURE (
4342
+ AssertParse (&state,
4343
+ " rule cp-plus-bis\n "
4344
+ " command = cp $in $out && cp $in $out.bis\n "
4345
+ " dynout = $out.dynout\n "
4346
+ " build out: cp-plus-bis in\n " ));
4347
+
4348
+ fs_.Tick ();
4349
+ fs_.Create (" in" , " " );
4350
+ fs_.Create (" out.dynout" , " out.bis\n " );
4351
+
4352
+ EXPECT_TRUE (builder.AddTarget (" out" , &err));
4353
+ EXPECT_TRUE (builder.Build (&err));
4354
+ ASSERT_EQ (" " , err);
4355
+ ASSERT_EQ (1u , command_runner.commands_ran_ .size ());
4356
+ ASSERT_GT (fs_.Stat (" out" , &err), 0 );
4357
+ ASSERT_GT (fs_.Stat (" out.bis" , &err), 0 );
4358
+ // Make sure the dynout file has been removed after its
4359
+ // information has been extracted in the deps log.
4360
+ ASSERT_EQ (fs_.Stat (" out.dynout" , &err), 0 );
4361
+
4362
+ // all clean, no rebuild.
4363
+ command_runner.commands_ran_ .clear ();
4364
+ state.Reset ();
4365
+ EXPECT_TRUE (builder.AddTarget (" out" , &err));
4366
+ EXPECT_EQ (" " , err);
4367
+ EXPECT_TRUE (builder.AlreadyUpToDate ());
4368
+
4369
+ // Test dynamic output are rebuilt if they are deleted.
4370
+ fs_.RemoveFile (" out.bis" );
4371
+ command_runner.commands_ran_ .clear ();
4372
+ state.Reset ();
4373
+
4374
+ fs_.Create (" out.dynout" , " out.bis\n " );
4375
+ EXPECT_TRUE (builder.AddTarget (" out" , &err));
4376
+ EXPECT_TRUE (builder.Build (&err));
4377
+ ASSERT_EQ (" " , err);
4378
+ ASSERT_EQ (1u , command_runner.commands_ran_ .size ());
4379
+
4380
+ builder.command_runner_ .release ();
4381
+ deps_log.Close ();
4382
+ }
4383
+
4384
+ // Create a new state to make sure outputs are reset
4385
+ {
4386
+ FakeCommandRunner command_runner (&fs_);
4387
+ State state;
4388
+ DepsLog deps_log;
4389
+ ASSERT_TRUE (deps_log.OpenForWrite (" ninja_deps" , &err));
4390
+ ASSERT_EQ (" " , err);
4391
+ deps_log.Load (" ninja_deps" , &state, &err);
4392
+ ASSERT_EQ (" " , err);
4393
+ Builder builder (&state, config_, &build_log, &deps_log, &fs_, &status_, 0 );
4394
+ builder.command_runner_ .reset (&command_runner);
4395
+
4396
+ ASSERT_NO_FATAL_FAILURE (
4397
+ AssertParse (&state,
4398
+ " rule cp-plus-bis\n "
4399
+ " command = cp $in $out && cp $in $out.bis\n "
4400
+ " dynout = $out.dynout\n "
4401
+ " build out: cp-plus-bis in\n " ));
4402
+
4403
+ // all clean, no rebuild.
4404
+ command_runner.commands_ran_ .clear ();
4405
+ state.Reset ();
4406
+ EXPECT_TRUE (builder.AddTarget (" out" , &err));
4407
+ EXPECT_EQ (" " , err);
4408
+ EXPECT_TRUE (builder.AlreadyUpToDate ());
4409
+
4410
+ // Test dynamic output are rebuilt if they are deleted
4411
+ // after having been rebuilt in order to make sure
4412
+ // when dynamic output information was already exist they
4413
+ // keep being valid for the next build.
4414
+ fs_.RemoveFile (" out.bis" );
4415
+ command_runner.commands_ran_ .clear ();
4416
+ state.Reset ();
4417
+
4418
+ // Recreate the dynout file because it is not created by the edge
4419
+ fs_.Create (" out.dynout" , " out.bis\n " );
4420
+ EXPECT_TRUE (builder.AddTarget (" out" , &err));
4421
+ EXPECT_TRUE (builder.Build (&err));
4422
+ ASSERT_EQ (" " , err);
4423
+ ASSERT_EQ (1u , command_runner.commands_ran_ .size ());
4424
+
4425
+ builder.command_runner_ .release ();
4426
+ deps_log.Close ();
4427
+ }
4428
+
4429
+ RealDiskInterface disk_interface;
4430
+ disk_interface.RemoveFile (" ninja_deps" );
4431
+ }
4432
+
4433
+ TEST_F (BuildTest, RebuildMissingDynamicOutputsWithRestat) {
4434
+ string err;
4435
+
4436
+ FakeCommandRunner command_runner (&fs_);
4437
+ BuildLog build_log;
4438
+ State state;
4439
+ DepsLog deps_log;
4440
+ ASSERT_TRUE (deps_log.OpenForWrite (" ninja_deps" , &err));
4441
+ ASSERT_EQ (" " , err);
4442
+ Builder builder (&state, config_, &build_log, &deps_log, &fs_, &status_, 0 );
4443
+ builder.command_runner_ .reset (&command_runner);
4444
+
4445
+ ASSERT_NO_FATAL_FAILURE (
4446
+ AssertParse (&state,
4447
+ " rule cp-plus-bis\n "
4448
+ " command = cp $in $out && cp $in $out.bis\n "
4449
+ " dynout = $out.dynout\n "
4450
+ " restat = 1\n "
4451
+ " build out: cp-plus-bis in\n " ));
4452
+
4453
+ fs_.Tick ();
4454
+ fs_.Create (" in" , " " );
4455
+ fs_.Tick ();
4456
+ fs_.Create (" out.dynout" , " out.bis\n " );
4457
+ fs_.Tick ();
4458
+
4459
+ EXPECT_TRUE (builder.AddTarget (" out" , &err));
4460
+ EXPECT_TRUE (builder.Build (&err));
4461
+ ASSERT_EQ (" " , err);
4462
+ ASSERT_EQ (1u , command_runner.commands_ran_ .size ());
4463
+ ASSERT_GT (fs_.Stat (" out" , &err), 0 );
4464
+ ASSERT_GT (fs_.Stat (" out.bis" , &err), 0 );
4465
+ // Make sure the dynout file has been removed after its
4466
+ // information has been extracted in the deps log.
4467
+ ASSERT_EQ (fs_.Stat (" out.dynout" , &err), 0 );
4468
+
4469
+ // all clean, no rebuild.
4470
+ command_runner.commands_ran_ .clear ();
4471
+ state.Reset ();
4472
+ EXPECT_TRUE (builder.AddTarget (" out" , &err));
4473
+ EXPECT_EQ (" " , err);
4474
+ EXPECT_TRUE (builder.AlreadyUpToDate ());
4475
+
4476
+ fs_.RemoveFile (" out.bis" );
4477
+ command_runner.commands_ran_ .clear ();
4478
+ state.Reset ();
4479
+
4480
+ // Recreate the dynout file because it is not created by the edge
4481
+ fs_.Create (" out.dynout" , " out.bis\n " );
4482
+ EXPECT_TRUE (builder.AddTarget (" out" , &err));
4483
+ EXPECT_TRUE (builder.Build (&err));
4484
+ ASSERT_EQ (" " , err);
4485
+ ASSERT_EQ (1u , command_runner.commands_ran_ .size ());
4486
+
4487
+ // Make sure the dynout file has been removed after its
4488
+ // information has been extracted in the deps log.
4489
+ ASSERT_EQ (fs_.Stat (" out.dynout" , &err), 0 );
4490
+
4491
+ builder.command_runner_ .release ();
4492
+
4493
+ deps_log.Close ();
4494
+ RealDiskInterface disk_interface;
4495
+ disk_interface.RemoveFile (" ninja_deps" );
4496
+ }
0 commit comments