Skip to content

Commit 23e374c

Browse files
committed
Add support for emitting parseable-output "finished" message and per-primary messages for batched jobs
Inside swift-frontend
1 parent f09ab5c commit 23e374c

File tree

7 files changed

+200
-71
lines changed

7 files changed

+200
-71
lines changed

include/swift/Basic/ParseableOutput.h

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,31 +20,36 @@
2020

2121
#include "swift/Basic/LLVM.h"
2222
#include "swift/Basic/TaskQueue.h"
23-
#include "swift/Frontend/Frontend.h"
2423
#include "swift/Driver/Job.h"
24+
#include "swift/Frontend/Frontend.h"
2525

2626
namespace swift {
2727

28-
2928
namespace parseable_output {
3029

3130
/// Emits a "began" message to the given stream, corresponding to a Driver Job.
3231
void emitBeganMessage(raw_ostream &os, const driver::Job &Cmd, int64_t Pid,
3332
sys::TaskProcessInformation ProcInfo);
3433

35-
/// Emits a "began" message to the given stream, corresponding to a given Frontend
36-
/// Compiler Invocation.
37-
void emitBeganMessage(raw_ostream &os,
38-
const CompilerInvocation &Invocation,
39-
ArrayRef<const char *> Args,
40-
int64_t Pid,
34+
/// Emits a "began" message to the given stream, corresponding to a given
35+
/// Frontend Compiler Invocation.
36+
void emitBeganMessage(raw_ostream &os, const CompilerInvocation &Invocation,
37+
ArrayRef<const char *> Args, int64_t Pid,
4138
sys::TaskProcessInformation ProcInfo);
4239

4340
/// Emits a "finished" message to the given stream.
4441
void emitFinishedMessage(raw_ostream &os, const driver::Job &Cmd, int64_t Pid,
4542
int ExitStatus, StringRef Output,
4643
sys::TaskProcessInformation ProcInfo);
4744

45+
/// Emits a "finished" message to the given stream corresponding to a given
46+
/// Frontend Compiler Invocation.
47+
void emitFinishedMessage(
48+
raw_ostream &os, const CompilerInvocation &Invocation, int64_t Pid,
49+
int ExitStatus,
50+
const llvm::StringMap<std::vector<std::string>> &FileSpecificDiagnostics,
51+
sys::TaskProcessInformation ProcInfo);
52+
4853
/// Emits a "signalled" message to the given stream.
4954
void emitSignalledMessage(raw_ostream &os, const driver::Job &Cmd, int64_t Pid,
5055
StringRef ErrorMsg, StringRef Output,
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
//===- AccumulatingDiagnosticConsumer.h - Collect Text Diagnostics C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2020 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This file defines the AccumulatingDiagnosticConsumer class, which collects
14+
// all emitted diagnostics into an externally-owned collection.
15+
//
16+
//===----------------------------------------------------------------------===//
17+
18+
#ifndef SWIFT_ACCUMULATINGDIAGNOSTICCONSUMER_H
19+
#define SWIFT_ACCUMULATINGDIAGNOSTICCONSUMER_H
20+
21+
#include "swift/AST/DiagnosticConsumer.h"
22+
#include "swift/Basic/DiagnosticOptions.h"
23+
#include "swift/Basic/LLVM.h"
24+
25+
#include <string>
26+
#include <sstream>
27+
28+
namespace swift {
29+
/// Diagnostic consumer that simply collects all emitted diagnostics into the provided
30+
/// collection.
31+
class AccumulatingFileDiagnosticConsumer : public DiagnosticConsumer {
32+
std::vector<std::string> &Diagnostics;
33+
public:
34+
AccumulatingFileDiagnosticConsumer(std::vector<std::string> &DiagBuffer)
35+
: Diagnostics(DiagBuffer) {}
36+
37+
private:
38+
void handleDiagnostic(SourceManager &SM,
39+
const DiagnosticInfo &Info) override {
40+
std::string DiagMsg;
41+
llvm::raw_string_ostream DiagOS(DiagMsg);
42+
DiagnosticEngine::formatDiagnosticText(DiagOS, Info.FormatString,
43+
Info.FormatArgs);
44+
auto LC = SM.getPresumedLineAndColumnForLoc(Info.Loc);
45+
std::ostringstream StrOS;
46+
StrOS << LC.first << ", " << LC.second << ": " << DiagOS.str();
47+
Diagnostics.push_back(StrOS.str());
48+
}
49+
};
50+
}
51+
#endif

include/swift/Frontend/FrontendOptions.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,11 @@ class FrontendOptions {
184184
/// entity.
185185
bool ProfileEntities = false;
186186

187+
/// Emit parseable-output directly from the frontend, instead of relying
188+
/// the driver to emit it. This is used in context where frontend jobs are executed by
189+
/// clients other than the driver.
190+
bool FrontendParseableOutput = false;
191+
187192
/// Indicates whether or not an import statement can pick up a Swift source
188193
/// file (as opposed to a module file).
189194
bool EnableSourceImport = false;

include/swift/Option/FrontendOptions.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ def output_filelist : Separate<["-"], "output-filelist">,
3030
def supplementary_output_file_map : Separate<["-"], "supplementary-output-file-map">,
3131
HelpText<"Specify supplementary outputs in a file rather than on the command line">;
3232

33+
def frontend_parseable_output : Flag<["-"], "frontend-parseable-output">,
34+
HelpText<"Emit textual output in a parseable format">;
3335

3436
def emit_module_doc : Flag<["-"], "emit-module-doc">,
3537
HelpText<"Emit a module documentation file based on documentation "

lib/Basic/ParseableOutput.cpp

Lines changed: 85 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#include "swift/Basic/ParseableOutput.h"
14-
1514
#include "swift/Basic/FileTypes.h"
1615
#include "swift/Basic/JSONSerialization.h"
1716
#include "swift/Basic/TaskQueue.h"
@@ -21,6 +20,8 @@
2120
#include "llvm/Support/Path.h"
2221
#include "llvm/Support/raw_ostream.h"
2322

23+
#include <sstream>
24+
2425
using namespace swift::parseable_output;
2526
using namespace swift::driver;
2627
using namespace swift::sys;
@@ -221,17 +222,9 @@ class DetailedInvocationBasedMessage : public InvocationBasedMessage {
221222
public:
222223
DetailedInvocationBasedMessage(StringRef Kind,
223224
const CompilerInvocation &Invocation,
225+
const InputFile &PrimaryInput,
224226
ArrayRef<const char *> Args)
225227
: InvocationBasedMessage(Kind, Invocation), Args(Args) {
226-
const auto &IO = Invocation.getFrontendOptions().InputsAndOutputs;
227-
// This frontend invocation correpsonds to a BatchJob:
228-
// A container of multiple StandardCompile Jobs.
229-
if (IO.hasMultiplePrimaryInputs()) {
230-
llvm::dbgs() << "Batch JOB.\n";
231-
} else {
232-
llvm::dbgs() << "Single JOB.\n";
233-
}
234-
235228
// Command line and arguments
236229
Executable = Invocation.getFrontendOptions().MainExecutablePath;
237230
CommandLine += Executable;
@@ -240,30 +233,23 @@ class DetailedInvocationBasedMessage : public InvocationBasedMessage {
240233
CommandLine += std::string(" ") + A;
241234
}
242235

243-
// Primary Inputs
244-
IO.forEachPrimaryInput([&](const InputFile &input) -> bool {
245-
Inputs.push_back(CommandInput(input.getFileName()));
246-
return false;
247-
});
236+
// Primary Input only
237+
Inputs.push_back(CommandInput(PrimaryInput.getFileName()));
248238

249-
// Outputs
250-
IO.forEachOutputFilename([&](const StringRef &output) {
251-
Outputs.push_back(OutputPair(file_types::lookupTypeForExtension(
252-
llvm::sys::path::extension(output)),
253-
output.str()));
254-
});
239+
// Output for this Primary
240+
auto OutputFile = PrimaryInput.outputFilename();
241+
Outputs.push_back(OutputPair(file_types::lookupTypeForExtension(
242+
llvm::sys::path::extension(OutputFile)),
243+
OutputFile));
255244

256245
// Supplementary outputs
257-
IO.forEachPrimaryInput([&](const InputFile &input) -> bool {
258-
const auto &primarySpecificFiles = input.getPrimarySpecificPaths();
259-
const auto &supplementaryOutputPaths =
260-
primarySpecificFiles.SupplementaryOutputs;
261-
supplementaryOutputPaths.forEachSetOutput([&](const std::string &output) {
262-
Outputs.push_back(OutputPair(file_types::lookupTypeForExtension(
263-
llvm::sys::path::extension(output)),
264-
output));
265-
});
266-
return false;
246+
const auto &primarySpecificFiles = PrimaryInput.getPrimarySpecificPaths();
247+
const auto &supplementaryOutputPaths =
248+
primarySpecificFiles.SupplementaryOutputs;
249+
supplementaryOutputPaths.forEachSetOutput([&](const std::string &output) {
250+
Outputs.push_back(OutputPair(file_types::lookupTypeForExtension(
251+
llvm::sys::path::extension(output)),
252+
output));
267253
});
268254
}
269255

@@ -290,22 +276,6 @@ class TaskBasedMessage : public CommandBasedMessage {
290276
}
291277
};
292278

293-
class FinishedInvocationBasedMessage : public InvocationBasedMessage {
294-
int64_t Pid;
295-
296-
public:
297-
FinishedInvocationBasedMessage(StringRef Kind,
298-
const CompilerInvocation &Invocation,
299-
int64_t Pid,
300-
StringRef Output,
301-
int ExitStatus)
302-
: InvocationBasedMessage(Kind, Invocation), Pid(Pid) {}
303-
void provideMapping(swift::json::Output &out) override {
304-
InvocationBasedMessage::provideMapping(out);
305-
out.mapRequired("pid", Pid);
306-
}
307-
};
308-
309279
class BeganCommandMessage : public DetailedCommandBasedMessage {
310280
int64_t Pid;
311281
TaskProcessInformation ProcInfo;
@@ -329,10 +299,11 @@ class BeganInvocationMessage : public DetailedInvocationBasedMessage {
329299

330300
public:
331301
BeganInvocationMessage(const CompilerInvocation &Invocation,
302+
const InputFile &PrimaryInput,
332303
ArrayRef<const char *> Args, int64_t Pid,
333304
TaskProcessInformation ProcInfo)
334-
: DetailedInvocationBasedMessage("began", Invocation, Args), Pid(Pid),
335-
ProcInfo(ProcInfo) {}
305+
: DetailedInvocationBasedMessage("began", Invocation, PrimaryInput, Args),
306+
Pid(Pid), ProcInfo(ProcInfo) {}
336307

337308
void provideMapping(swift::json::Output &out) override {
338309
DetailedInvocationBasedMessage::provideMapping(out);
@@ -341,6 +312,27 @@ class BeganInvocationMessage : public DetailedInvocationBasedMessage {
341312
}
342313
};
343314

315+
class FinishedInvocationMessage : public InvocationBasedMessage {
316+
int64_t Pid;
317+
int ExitStatus;
318+
std::string Output;
319+
TaskProcessInformation ProcInfo;
320+
321+
public:
322+
FinishedInvocationMessage(const CompilerInvocation &Invocation, int64_t Pid,
323+
StringRef Output, int ExitStatus,
324+
TaskProcessInformation ProcInfo)
325+
: InvocationBasedMessage("finished", Invocation), Pid(Pid),
326+
ExitStatus(ExitStatus), Output(Output), ProcInfo(ProcInfo) {}
327+
void provideMapping(swift::json::Output &out) override {
328+
InvocationBasedMessage::provideMapping(out);
329+
out.mapOptional("output", Output, std::string());
330+
out.mapRequired("process", ProcInfo);
331+
out.mapRequired("pid", Pid);
332+
out.mapRequired("exit-status", ExitStatus);
333+
}
334+
};
335+
344336
class TaskOutputMessage : public TaskBasedMessage {
345337
std::string Output;
346338
TaskProcessInformation ProcInfo;
@@ -362,7 +354,7 @@ class FinishedCommandMessage : public TaskOutputMessage {
362354

363355
public:
364356
FinishedCommandMessage(const driver::Job &Cmd, int64_t Pid, StringRef Output,
365-
TaskProcessInformation ProcInfo, int ExitStatus)
357+
TaskProcessInformation ProcInfo, int ExitStatus)
366358
: TaskOutputMessage("finished", Cmd, Pid, Output, ProcInfo),
367359
ExitStatus(ExitStatus) {}
368360

@@ -418,27 +410,58 @@ static void emitMessage(raw_ostream &os, Message &msg) {
418410
os << JSONString << '\n';
419411
}
420412

421-
void parseable_output::emitBeganMessage(
422-
raw_ostream &os, const driver::Job &Cmd, int64_t Pid,
423-
TaskProcessInformation ProcInfo) {
413+
void parseable_output::emitBeganMessage(raw_ostream &os, const driver::Job &Cmd,
414+
int64_t Pid,
415+
TaskProcessInformation ProcInfo) {
424416
BeganCommandMessage msg(Cmd, Pid, ProcInfo);
425417
emitMessage(os, msg);
426418
}
427419

428-
void parseable_output::emitBeganMessage(
429-
raw_ostream &os, const CompilerInvocation &Invocation,
430-
ArrayRef<const char *> Args, int64_t Pid, TaskProcessInformation ProcInfo) {
431-
BeganInvocationMessage msg(Invocation, Args, Pid, ProcInfo);
432-
emitMessage(os, msg);
420+
void parseable_output::emitBeganMessage(raw_ostream &os,
421+
const CompilerInvocation &Invocation,
422+
ArrayRef<const char *> Args,
423+
int64_t Pid,
424+
TaskProcessInformation ProcInfo) {
425+
const auto &IO = Invocation.getFrontendOptions().InputsAndOutputs;
426+
IO.forEachPrimaryInput([&](const InputFile &Input) -> bool {
427+
BeganInvocationMessage msg(Invocation, Input, Args, Pid, ProcInfo);
428+
emitMessage(os, msg);
429+
return false;
430+
});
433431
}
434432

435-
void parseable_output::emitFinishedMessage(
436-
raw_ostream &os, const driver::Job &Cmd, int64_t Pid, int ExitStatus,
437-
StringRef Output, TaskProcessInformation ProcInfo) {
433+
void parseable_output::emitFinishedMessage(raw_ostream &os,
434+
const driver::Job &Cmd, int64_t Pid,
435+
int ExitStatus, StringRef Output,
436+
TaskProcessInformation ProcInfo) {
438437
FinishedCommandMessage msg(Cmd, Pid, Output, ProcInfo, ExitStatus);
439438
emitMessage(os, msg);
440439
}
441440

441+
void parseable_output::emitFinishedMessage(
442+
raw_ostream &os, const CompilerInvocation &Invocation, int64_t Pid,
443+
int ExitStatus,
444+
const llvm::StringMap<std::vector<std::string>> &FileSpecificDiagnostics,
445+
TaskProcessInformation ProcInfo) {
446+
const auto &IO = Invocation.getFrontendOptions().InputsAndOutputs;
447+
IO.forEachPrimaryInput([&](const InputFile &Input) -> bool {
448+
assert(FileSpecificDiagnostics.count(Input.getFileName()) != 0 &&
449+
"Expected diagnostic collection for input.");
450+
451+
// Join all diagnostics produced for this file into a single output.
452+
auto PrimaryDiags = FileSpecificDiagnostics.lookup(Input.getFileName());
453+
const char* const Delim = "\n";
454+
std::ostringstream JoinedDiags;
455+
std::copy(PrimaryDiags.begin(), PrimaryDiags.end(),
456+
std::ostream_iterator<std::string>(JoinedDiags, Delim));
457+
FinishedInvocationMessage msg(Invocation, Pid,
458+
JoinedDiags.str(),
459+
ExitStatus, ProcInfo);
460+
emitMessage(os, msg);
461+
return false;
462+
});
463+
}
464+
442465
void parseable_output::emitSignalledMessage(
443466
raw_ostream &os, const driver::Job &Cmd, int64_t Pid, StringRef ErrorMsg,
444467
StringRef Output, Optional<int> Signal, TaskProcessInformation ProcInfo) {
@@ -447,7 +470,7 @@ void parseable_output::emitSignalledMessage(
447470
}
448471

449472
void parseable_output::emitSkippedMessage(raw_ostream &os,
450-
const driver::Job &Cmd) {
473+
const driver::Job &Cmd) {
451474
SkippedMessage msg(Cmd);
452475
emitMessage(os, msg);
453476
}

lib/Frontend/ArgsToFrontendOptionsConverter.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ bool ArgsToFrontendOptionsConverter::convert(
7777
Opts.EnableTesting |= Args.hasArg(OPT_enable_testing);
7878
Opts.EnablePrivateImports |= Args.hasArg(OPT_enable_private_imports);
7979
Opts.EnableLibraryEvolution |= Args.hasArg(OPT_enable_library_evolution);
80+
Opts.FrontendParseableOutput |= Args.hasArg(OPT_frontend_parseable_output);
8081

8182
// FIXME: Remove this flag
8283
Opts.EnableLibraryEvolution |= Args.hasArg(OPT_enable_resilience);

0 commit comments

Comments
 (0)