Skip to content

Commit 4e19445

Browse files
mcprathundeboll
andcommitted
Implement GNU jobserver posix client support
The core principle of a jobserver is simple: before starting a new job (edge in ninja-speak), a token must be acquired from an external entity as approval. Once a job is finished, the token is returned to represent a free job slot. In the case of GNU Make, this external entity is the parent process which has executed Ninja and is managing the load capacity for all subprocesses which it has spawned. Introducing client support for this model allows Ninja to give load capacity management to it's parent process, allowing it to control the number of subprocesses that Ninja spawns at any given time. This functionality is desirable when Ninja is part of a bigger build, such as Yocto/OpenEmbedded, Openwrt/Linux, Buildroot, and Android. Here, multiple compile jobs are executed in parallel in order to maximize cpu utilization, but if each compile job in Ninja uses all available cores, the system is overloaded. This implementation instantiates the client in the NinjaMain class and passes pointers to the Jobserver class into other classes. All tokens are returned whenever the CommandRunner aborts, and the current number of tokens compared to the current number of running subprocesses controls the available load capacity, used to determine how many new tokens to attempt to acquire in order to try to start another job for each loop to find work. Calls to functions are excluded from Windows builds pending Windows-specific support for the jobserver. Co-authored-by: Martin Hundebøll <martin@geanix.com> Co-developed-by: Martin Hundebøll <martin@geanix.com> Signed-off-by: Martin Hundebøll <martin@geanix.com> Signed-off-by: Michael Pratt <mcpratt@pm.me>
1 parent 4b7d399 commit 4e19445

File tree

9 files changed

+374
-44
lines changed

9 files changed

+374
-44
lines changed

CMakeLists.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,10 @@ if(WIN32)
169169
# errors by telling windows.h to not define those two.
170170
add_compile_definitions(NOMINMAX)
171171
else()
172-
target_sources(libninja PRIVATE src/subprocess-posix.cc)
172+
target_sources(libninja PRIVATE
173+
src/jobserver-posix.cc
174+
src/subprocess-posix.cc
175+
)
173176
if(CMAKE_SYSTEM_NAME STREQUAL "OS400" OR CMAKE_SYSTEM_NAME STREQUAL "AIX")
174177
target_sources(libninja PRIVATE src/getopt.c)
175178
# Build getopt.c, which can be compiled as either C or C++, as C++

configure.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,7 @@ def has_re2c() -> bool:
564564
objs += cxx('minidump-win32', variables=cxxvariables)
565565
objs += cc('getopt')
566566
else:
567+
objs += cxx('jobserver-posix')
567568
objs += cxx('subprocess-posix')
568569
if platform.is_aix():
569570
objs += cc('getopt')

src/build.cc

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -162,8 +162,20 @@ Edge* Plan::FindWork() {
162162
if (ready_.empty())
163163
return NULL;
164164

165+
// Only initiate work if the jobserver can acquire a token.
166+
if (builder_ && builder_->jobserver_ &&
167+
builder_->jobserver_->Enabled() &&
168+
!builder_->jobserver_->Acquire()) {
169+
return NULL;
170+
}
171+
165172
Edge* work = ready_.top();
166173
ready_.pop();
174+
175+
// Mark this edge as using a job token to be released when finished.
176+
if (builder_ && builder_->jobserver_)
177+
work->has_job_token_ = builder_->jobserver_->Enabled();
178+
167179
return work;
168180
}
169181

@@ -199,6 +211,13 @@ bool Plan::EdgeFinished(Edge* edge, EdgeResult result, string* err) {
199211
edge->pool()->EdgeFinished(*edge);
200212
edge->pool()->RetrieveReadyEdges(&ready_);
201213

214+
// If jobserver is used, return the token for this job.
215+
if (builder_ && builder_->jobserver_ &&
216+
edge->has_job_token_) {
217+
builder_->jobserver_->Release();
218+
edge->has_job_token_ = false;
219+
}
220+
202221
// The rest of this function only applies to successful commands.
203222
if (result != kEdgeSucceeded)
204223
return true;
@@ -592,14 +611,17 @@ void Plan::Dump() const {
592611
}
593612

594613
struct RealCommandRunner : public CommandRunner {
595-
explicit RealCommandRunner(const BuildConfig& config) : config_(config) {}
614+
explicit RealCommandRunner(const BuildConfig& config, Jobserver* jobserver) :
615+
config_(config), jobserver_(jobserver) {}
616+
596617
size_t CanRunMore() const override;
597618
bool StartCommand(Edge* edge) override;
598619
bool WaitForCommand(Result* result) override;
599620
vector<Edge*> GetActiveEdges() override;
600621
void Abort() override;
601622

602623
const BuildConfig& config_;
624+
Jobserver* jobserver_;
603625
SubprocessSet subprocs_;
604626
map<const Subprocess*, Edge*> subproc_to_edge_;
605627
};
@@ -614,6 +636,7 @@ vector<Edge*> RealCommandRunner::GetActiveEdges() {
614636

615637
void RealCommandRunner::Abort() {
616638
subprocs_.Clear();
639+
jobserver_->Clear();
617640
}
618641

619642
size_t RealCommandRunner::CanRunMore() const {
@@ -628,6 +651,15 @@ size_t RealCommandRunner::CanRunMore() const {
628651
capacity = load_capacity;
629652
}
630653

654+
int job_tokens = jobserver_->Tokens();
655+
656+
// When initialized, behave as if the implicit token is acquired already.
657+
// Otherwise, this happens after a token is released but before it is replaced,
658+
// so the base capacity is represented by job_tokens + 1 when positive.
659+
// Add an extra loop on capacity for each job in order to get an extra token.
660+
if (job_tokens)
661+
capacity = abs(job_tokens) - subproc_number + 2;
662+
631663
if (capacity < 0)
632664
capacity = 0;
633665

@@ -667,10 +699,10 @@ bool RealCommandRunner::WaitForCommand(Result* result) {
667699
return true;
668700
}
669701

670-
Builder::Builder(State* state, const BuildConfig& config, BuildLog* build_log,
671-
DepsLog* deps_log, DiskInterface* disk_interface,
672-
Status* status, int64_t start_time_millis)
673-
: state_(state), config_(config), plan_(this), status_(status),
702+
Builder::Builder(State* state, const BuildConfig& config, Jobserver* jobserver,
703+
BuildLog* build_log, DepsLog* deps_log, DiskInterface* disk_interface,
704+
Status* status, int64_t start_time_millis) : state_(state),
705+
config_(config), jobserver_(jobserver), plan_(this), status_(status),
674706
start_time_millis_(start_time_millis), disk_interface_(disk_interface),
675707
explanations_(g_explaining ? new Explanations() : nullptr),
676708
scan_(state, build_log, deps_log, disk_interface,
@@ -775,7 +807,7 @@ bool Builder::Build(string* err) {
775807
if (config_.dry_run)
776808
command_runner_.reset(new DryRunCommandRunner);
777809
else
778-
command_runner_.reset(new RealCommandRunner(config_));
810+
command_runner_.reset(new RealCommandRunner(config_, jobserver_));
779811
}
780812

781813
// We are about to start the build process.

src/build.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "depfile_parser.h"
2525
#include "exit_status.h"
2626
#include "graph.h"
27+
#include "jobserver.h"
2728
#include "util.h" // int64_t
2829

2930
struct BuildLog;
@@ -187,9 +188,9 @@ struct BuildConfig {
187188

188189
/// Builder wraps the build process: starting commands, updating status.
189190
struct Builder {
190-
Builder(State* state, const BuildConfig& config, BuildLog* build_log,
191-
DepsLog* deps_log, DiskInterface* disk_interface, Status* status,
192-
int64_t start_time_millis);
191+
Builder(State* state, const BuildConfig& config, Jobserver* jobserver,
192+
BuildLog* build_log, DepsLog* deps_log, DiskInterface* disk_interface,
193+
Status* status, int64_t start_time_millis);
193194
~Builder();
194195

195196
/// Clean up after interrupted commands by deleting output files.
@@ -224,6 +225,7 @@ struct Builder {
224225

225226
State* state_;
226227
const BuildConfig& config_;
228+
Jobserver* jobserver_;
227229
Plan plan_;
228230
std::unique_ptr<CommandRunner> command_runner_;
229231
Status* status_;

src/build_test.cc

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -535,12 +535,12 @@ struct FakeCommandRunner : public CommandRunner {
535535

536536
struct BuildTest : public StateTestWithBuiltinRules, public BuildLogUser {
537537
BuildTest() : config_(MakeConfig()), command_runner_(&fs_), status_(config_),
538-
builder_(&state_, config_, NULL, NULL, &fs_, &status_, 0) {
538+
builder_(&state_, config_, NULL, NULL, NULL, &fs_, &status_, 0) {
539539
}
540540

541541
explicit BuildTest(DepsLog* log)
542542
: config_(MakeConfig()), command_runner_(&fs_), status_(config_),
543-
builder_(&state_, config_, NULL, log, &fs_, &status_, 0) {}
543+
builder_(&state_, config_, NULL, NULL, log, &fs_, &status_, 0) {}
544544

545545
virtual void SetUp() {
546546
StateTestWithBuiltinRules::SetUp();
@@ -610,7 +610,7 @@ void BuildTest::RebuildTarget(const string& target, const char* manifest,
610610
pdeps_log = &deps_log;
611611
}
612612

613-
Builder builder(pstate, config_, pbuild_log, pdeps_log, &fs_, &status_, 0);
613+
Builder builder(pstate, config_, NULL, pbuild_log, pdeps_log, &fs_, &status_, 0);
614614
EXPECT_TRUE(builder.AddTarget(target, &err));
615615

616616
command_runner_.commands_ran_.clear();
@@ -2559,7 +2559,7 @@ TEST_F(BuildWithDepsLogTest, Straightforward) {
25592559
ASSERT_TRUE(deps_log.OpenForWrite(deps_log_file_.path(), &err));
25602560
ASSERT_EQ("", err);
25612561

2562-
Builder builder(&state, config_, NULL, &deps_log, &fs_, &status_, 0);
2562+
Builder builder(&state, config_, NULL, NULL, &deps_log, &fs_, &status_, 0);
25632563
builder.command_runner_.reset(&command_runner_);
25642564
EXPECT_TRUE(builder.AddTarget("out", &err));
25652565
ASSERT_EQ("", err);
@@ -2589,7 +2589,7 @@ TEST_F(BuildWithDepsLogTest, Straightforward) {
25892589
ASSERT_TRUE(deps_log.Load(deps_log_file_.path(), &state, &err));
25902590
ASSERT_TRUE(deps_log.OpenForWrite(deps_log_file_.path(), &err));
25912591

2592-
Builder builder(&state, config_, NULL, &deps_log, &fs_, &status_, 0);
2592+
Builder builder(&state, config_, NULL, NULL, &deps_log, &fs_, &status_, 0);
25932593
builder.command_runner_.reset(&command_runner_);
25942594
command_runner_.commands_ran_.clear();
25952595
EXPECT_TRUE(builder.AddTarget("out", &err));
@@ -2630,7 +2630,7 @@ TEST_F(BuildWithDepsLogTest, ObsoleteDeps) {
26302630
ASSERT_TRUE(deps_log.OpenForWrite(deps_log_file_.path(), &err));
26312631
ASSERT_EQ("", err);
26322632

2633-
Builder builder(&state, config_, NULL, &deps_log, &fs_, &status_, 0);
2633+
Builder builder(&state, config_, NULL, NULL, &deps_log, &fs_, &status_, 0);
26342634
builder.command_runner_.reset(&command_runner_);
26352635
EXPECT_TRUE(builder.AddTarget("out", &err));
26362636
ASSERT_EQ("", err);
@@ -2659,7 +2659,7 @@ TEST_F(BuildWithDepsLogTest, ObsoleteDeps) {
26592659
ASSERT_TRUE(deps_log.Load(deps_log_file_.path(), &state, &err));
26602660
ASSERT_TRUE(deps_log.OpenForWrite(deps_log_file_.path(), &err));
26612661

2662-
Builder builder(&state, config_, NULL, &deps_log, &fs_, &status_, 0);
2662+
Builder builder(&state, config_, NULL, NULL, &deps_log, &fs_, &status_, 0);
26632663
builder.command_runner_.reset(&command_runner_);
26642664
command_runner_.commands_ran_.clear();
26652665
EXPECT_TRUE(builder.AddTarget("out", &err));
@@ -2695,7 +2695,7 @@ TEST_F(BuildWithDepsLogTest, DepsIgnoredInDryRun) {
26952695

26962696
// The deps log is NULL in dry runs.
26972697
config_.dry_run = true;
2698-
Builder builder(&state, config_, NULL, NULL, &fs_, &status_, 0);
2698+
Builder builder(&state, config_, NULL, NULL, NULL, &fs_, &status_, 0);
26992699
builder.command_runner_.reset(&command_runner_);
27002700
command_runner_.commands_ran_.clear();
27012701

@@ -2730,7 +2730,7 @@ TEST_F(BuildWithDepsLogTest, TestInputMtimeRaceCondition) {
27302730

27312731
BuildLog::LogEntry* log_entry = NULL;
27322732
{
2733-
Builder builder(&state, config_, &build_log, &deps_log, &fs_, &status_, 0);
2733+
Builder builder(&state, config_, NULL, &build_log, &deps_log, &fs_, &status_, 0);
27342734
builder.command_runner_.reset(&command_runner_);
27352735
command_runner_.commands_ran_.clear();
27362736

@@ -2750,7 +2750,7 @@ TEST_F(BuildWithDepsLogTest, TestInputMtimeRaceCondition) {
27502750
}
27512751

27522752
{
2753-
Builder builder(&state, config_, &build_log, &deps_log, &fs_, &status_, 0);
2753+
Builder builder(&state, config_, NULL, &build_log, &deps_log, &fs_, &status_, 0);
27542754
builder.command_runner_.reset(&command_runner_);
27552755
command_runner_.commands_ran_.clear();
27562756

@@ -2772,7 +2772,7 @@ TEST_F(BuildWithDepsLogTest, TestInputMtimeRaceCondition) {
27722772
}
27732773

27742774
{
2775-
Builder builder(&state, config_, &build_log, &deps_log, &fs_, &status_, 0);
2775+
Builder builder(&state, config_, NULL, &build_log, &deps_log, &fs_, &status_, 0);
27762776
builder.command_runner_.reset(&command_runner_);
27772777
command_runner_.commands_ran_.clear();
27782778

@@ -2811,7 +2811,7 @@ TEST_F(BuildWithDepsLogTest, TestInputMtimeRaceConditionWithDepFile) {
28112811
ASSERT_TRUE(deps_log.OpenForWrite(deps_log_file_.path(), &err));
28122812

28132813
{
2814-
Builder builder(&state, config_, &build_log, &deps_log, &fs_, &status_, 0);
2814+
Builder builder(&state, config_, NULL, &build_log, &deps_log, &fs_, &status_, 0);
28152815
builder.command_runner_.reset(&command_runner_);
28162816

28172817
// Run the build, out gets built, dep file is created
@@ -2832,7 +2832,7 @@ TEST_F(BuildWithDepsLogTest, TestInputMtimeRaceConditionWithDepFile) {
28322832
{
28332833
// Trigger the build again - "out" will rebuild since its newest input mtime (header.h)
28342834
// is newer than the recorded mtime of out in the build log
2835-
Builder builder(&state, config_, &build_log, &deps_log, &fs_, &status_, 0);
2835+
Builder builder(&state, config_, NULL, &build_log, &deps_log, &fs_, &status_, 0);
28362836
builder.command_runner_.reset(&command_runner_);
28372837
command_runner_.commands_ran_.clear();
28382838

@@ -2848,7 +2848,7 @@ TEST_F(BuildWithDepsLogTest, TestInputMtimeRaceConditionWithDepFile) {
28482848
{
28492849
// Trigger the build again - "out" won't rebuild since the file wasn't updated during
28502850
// the previous build
2851-
Builder builder(&state, config_, &build_log, &deps_log, &fs_, &status_, 0);
2851+
Builder builder(&state, config_, NULL, &build_log, &deps_log, &fs_, &status_, 0);
28522852
builder.command_runner_.reset(&command_runner_);
28532853
command_runner_.commands_ran_.clear();
28542854

@@ -2867,7 +2867,7 @@ TEST_F(BuildWithDepsLogTest, TestInputMtimeRaceConditionWithDepFile) {
28672867
{
28682868
// Rebuild. This time, long-cc will cause header.h to be updated while the build is
28692869
// in progress
2870-
Builder builder(&state, config_, &build_log, &deps_log, &fs_, &status_, 0);
2870+
Builder builder(&state, config_, NULL, &build_log, &deps_log, &fs_, &status_, 0);
28712871
builder.command_runner_.reset(&command_runner_);
28722872
command_runner_.commands_ran_.clear();
28732873

@@ -2883,7 +2883,7 @@ TEST_F(BuildWithDepsLogTest, TestInputMtimeRaceConditionWithDepFile) {
28832883
{
28842884
// Rebuild. Because header.h is now in the deplog for out, it should be detectable as
28852885
// a change-while-in-progress and should cause a rebuild of out.
2886-
Builder builder(&state, config_, &build_log, &deps_log, &fs_, &status_, 0);
2886+
Builder builder(&state, config_, NULL, &build_log, &deps_log, &fs_, &status_, 0);
28872887
builder.command_runner_.reset(&command_runner_);
28882888
command_runner_.commands_ran_.clear();
28892889

@@ -2899,7 +2899,7 @@ TEST_F(BuildWithDepsLogTest, TestInputMtimeRaceConditionWithDepFile) {
28992899
{
29002900
// This time, the header.h file was not updated during the build, so the target should
29012901
// not be considered dirty.
2902-
Builder builder(&state, config_, &build_log, &deps_log, &fs_, &status_, 0);
2902+
Builder builder(&state, config_, NULL, &build_log, &deps_log, &fs_, &status_, 0);
29032903
builder.command_runner_.reset(&command_runner_);
29042904
command_runner_.commands_ran_.clear();
29052905

@@ -2957,7 +2957,7 @@ TEST_F(BuildWithDepsLogTest, RestatDepfileDependencyDepsLog) {
29572957
ASSERT_TRUE(deps_log.OpenForWrite(deps_log_file_.path(), &err));
29582958
ASSERT_EQ("", err);
29592959

2960-
Builder builder(&state, config_, NULL, &deps_log, &fs_, &status_, 0);
2960+
Builder builder(&state, config_, NULL, NULL, &deps_log, &fs_, &status_, 0);
29612961
builder.command_runner_.reset(&command_runner_);
29622962
EXPECT_TRUE(builder.AddTarget("out", &err));
29632963
ASSERT_EQ("", err);
@@ -2983,7 +2983,7 @@ TEST_F(BuildWithDepsLogTest, RestatDepfileDependencyDepsLog) {
29832983
ASSERT_TRUE(deps_log.Load(deps_log_file_.path(), &state, &err));
29842984
ASSERT_TRUE(deps_log.OpenForWrite(deps_log_file_.path(), &err));
29852985

2986-
Builder builder(&state, config_, NULL, &deps_log, &fs_, &status_, 0);
2986+
Builder builder(&state, config_, NULL, NULL, &deps_log, &fs_, &status_, 0);
29872987
builder.command_runner_.reset(&command_runner_);
29882988
command_runner_.commands_ran_.clear();
29892989
EXPECT_TRUE(builder.AddTarget("out", &err));
@@ -3016,7 +3016,7 @@ TEST_F(BuildWithDepsLogTest, DepFileOKDepsLog) {
30163016
ASSERT_TRUE(deps_log.OpenForWrite(deps_log_file_.path(), &err));
30173017
ASSERT_EQ("", err);
30183018

3019-
Builder builder(&state, config_, NULL, &deps_log, &fs_, &status_, 0);
3019+
Builder builder(&state, config_, NULL, NULL, &deps_log, &fs_, &status_, 0);
30203020
builder.command_runner_.reset(&command_runner_);
30213021
EXPECT_TRUE(builder.AddTarget("fo o.o", &err));
30223022
ASSERT_EQ("", err);
@@ -3037,7 +3037,7 @@ TEST_F(BuildWithDepsLogTest, DepFileOKDepsLog) {
30373037
ASSERT_TRUE(deps_log.OpenForWrite(deps_log_file_.path(), &err));
30383038
ASSERT_EQ("", err);
30393039

3040-
Builder builder(&state, config_, NULL, &deps_log, &fs_, &status_, 0);
3040+
Builder builder(&state, config_, NULL, NULL, &deps_log, &fs_, &status_, 0);
30413041
builder.command_runner_.reset(&command_runner_);
30423042

30433043
Edge* edge = state.edges_.back();
@@ -3087,7 +3087,7 @@ TEST_F(BuildWithDepsLogTest, DiscoveredDepDuringBuildChanged) {
30873087
ASSERT_TRUE(deps_log.OpenForWrite(deps_log_file_.path(), &err));
30883088
ASSERT_EQ("", err);
30893089

3090-
Builder builder(&state, config_, &build_log, &deps_log, &fs_, &status_, 0);
3090+
Builder builder(&state, config_, NULL, &build_log, &deps_log, &fs_, &status_, 0);
30913091
builder.command_runner_.reset(&command_runner_);
30923092
EXPECT_TRUE(builder.AddTarget("out2", &err));
30933093
EXPECT_FALSE(builder.AlreadyUpToDate());
@@ -3111,7 +3111,7 @@ TEST_F(BuildWithDepsLogTest, DiscoveredDepDuringBuildChanged) {
31113111
ASSERT_TRUE(deps_log.OpenForWrite(deps_log_file_.path(), &err));
31123112
ASSERT_EQ("", err);
31133113

3114-
Builder builder(&state, config_, &build_log, &deps_log, &fs_, &status_, 0);
3114+
Builder builder(&state, config_, NULL, &build_log, &deps_log, &fs_, &status_, 0);
31153115
builder.command_runner_.reset(&command_runner_);
31163116
EXPECT_TRUE(builder.AddTarget("out2", &err));
31173117
EXPECT_FALSE(builder.AlreadyUpToDate());
@@ -3134,7 +3134,7 @@ TEST_F(BuildWithDepsLogTest, DiscoveredDepDuringBuildChanged) {
31343134
ASSERT_TRUE(deps_log.OpenForWrite(deps_log_file_.path(), &err));
31353135
ASSERT_EQ("", err);
31363136

3137-
Builder builder(&state, config_, &build_log, &deps_log, &fs_, &status_, 0);
3137+
Builder builder(&state, config_, NULL, &build_log, &deps_log, &fs_, &status_, 0);
31383138
builder.command_runner_.reset(&command_runner_);
31393139
EXPECT_TRUE(builder.AddTarget("out2", &err));
31403140
EXPECT_TRUE(builder.AlreadyUpToDate());
@@ -3162,7 +3162,7 @@ TEST_F(BuildWithDepsLogTest, DepFileDepsLogCanonicalize) {
31623162
ASSERT_TRUE(deps_log.OpenForWrite(deps_log_file_.path(), &err));
31633163
ASSERT_EQ("", err);
31643164

3165-
Builder builder(&state, config_, NULL, &deps_log, &fs_, &status_, 0);
3165+
Builder builder(&state, config_, NULL, NULL, &deps_log, &fs_, &status_, 0);
31663166
builder.command_runner_.reset(&command_runner_);
31673167
EXPECT_TRUE(builder.AddTarget("a/b/c/d/e/fo o.o", &err));
31683168
ASSERT_EQ("", err);
@@ -3185,7 +3185,7 @@ TEST_F(BuildWithDepsLogTest, DepFileDepsLogCanonicalize) {
31853185
ASSERT_TRUE(deps_log.OpenForWrite(deps_log_file_.path(), &err));
31863186
ASSERT_EQ("", err);
31873187

3188-
Builder builder(&state, config_, NULL, &deps_log, &fs_, &status_, 0);
3188+
Builder builder(&state, config_, NULL, NULL, &deps_log, &fs_, &status_, 0);
31893189
builder.command_runner_.reset(&command_runner_);
31903190

31913191
state.GetNode("bar.h", 0)->MarkDirty(); // Mark bar.h as missing.
@@ -4264,7 +4264,7 @@ TEST_F(BuildWithDepsLogTest, ValidationThroughDepfile) {
42644264
ASSERT_TRUE(deps_log.OpenForWrite(deps_log_file_.path(), &err));
42654265
ASSERT_EQ("", err);
42664266

4267-
Builder builder(&state, config_, NULL, &deps_log, &fs_, &status_, 0);
4267+
Builder builder(&state, config_, NULL, NULL, &deps_log, &fs_, &status_, 0);
42684268
builder.command_runner_.reset(&command_runner_);
42694269

42704270
EXPECT_TRUE(builder.AddTarget("out2", &err));
@@ -4300,7 +4300,7 @@ TEST_F(BuildWithDepsLogTest, ValidationThroughDepfile) {
43004300
ASSERT_TRUE(deps_log.OpenForWrite(deps_log_file_.path(), &err));
43014301
ASSERT_EQ("", err);
43024302

4303-
Builder builder(&state, config_, NULL, &deps_log, &fs_, &status_, 0);
4303+
Builder builder(&state, config_, NULL, NULL, &deps_log, &fs_, &status_, 0);
43044304
builder.command_runner_.reset(&command_runner_);
43054305

43064306
EXPECT_TRUE(builder.AddTarget("out2", &err));

0 commit comments

Comments
 (0)