hi all:
i am looking into the “main function” of llvm/tools/clang/tools/driver/driver.cpp,
i only add several llvm::outs() in the source code, and re-compile the source code again,
then i use the clang to compile my input file(t.c) like this:
xchen422@dimsum:~$ clang t.c
the output is :
xchen422@dimsum:~$ clang t.c
clang main function start point 1
clang main function start point 3
clang main function start point 4
clang main function start point 1
clang main function start point 2
clang main function start point 5
clang main function start point 6
xchen422@dimsum:~$
It seems that the main() function is called twice, also it seems that there are
some magic in this function(line 468):
Res = TheDriver.ExecuteCompilation(*C, FailingCommands);
i could not understand, could someone give me a brief explanation.
PS:
1). I add llvm::outs() in line 379, line 418, line 422, line 466, line 470 and line 512.
2). t.c file only contains an empty main() function.
3). i paste the main() function below.
int main(int argc_, const char **argv_) {
379 llvm::outs() << “clang main function start point 1” << ‘\n’;
380
381
382 llvm::sys::PrintStackTraceOnErrorSignal();
383 llvm::PrettyStackTraceProgram X(argc_, argv_);
384
385 if (llvm::sys::Process::FixupStandardFileDescriptors())
386 return 1;
387
388 SmallVector<const char *, 256> argv;
389 llvm::SpecificBumpPtrAllocator ArgAllocator;
390 std::error_code EC = llvm::sys::Process::GetArgumentVector(
391 argv, llvm::makeArrayRef(argv_, argc_), ArgAllocator);
392 if (EC) {
393 llvm::errs() << “error: couldn’t get arguments: " << EC.message() << ‘\n’;
394 return 1;
395 }
396
397 std::setstd::string SavedStrings;
398 StringSetSaver Saver(SavedStrings);
399
400 // Determines whether we want nullptr markers in argv to indicate response
401 // files end-of-lines. We only use this for the /LINK driver argument.
402 bool MarkEOLs = true;
403 if (argv.size() > 1 && StringRef(argv[1]).startswith(”-cc1"))
404 MarkEOLs = false;
405 llvm:
:ExpandResponseFiles(Saver, llvm:
:TokenizeGNUCommandLine, argv,
406 MarkEOLs);
407
408 // Handle -cc1 integrated tools, even if -cc1 was expanded from a response
409 // file.
410 auto FirstArg = std::find_if(argv.begin() + 1, argv.end(),
411 [](const char *A) { return A != nullptr; });
412 if (FirstArg != argv.end() && StringRef(*FirstArg).startswith("-cc1")) {
413 // If -cc1 came from a response file, remove the EOL sentinels.
414 if (MarkEOLs) {
415 auto newEnd = std::remove(argv.begin(), argv.end(), nullptr);
416 argv.resize(newEnd - argv.begin());
417 }
418 llvm::outs() << “clang main function start point 2” << ‘\n’;
419 return ExecuteCC1Tool(argv, argv[1] + 4);
420 }
421
422 llvm::outs() << “clang main function start point 3” << ‘\n’;
423 bool CanonicalPrefixes = true;
424 for (int i = 1, size = argv.size(); i < size; ++i) {
425 // Skip end-of-line response file markers
426 if (argv[i] == nullptr)
427 continue;
428 if (StringRef(argv[i]) == “-no-canonical-prefixes”) {
429 CanonicalPrefixes = false;
430 break;
431 }
432 }
433
434 // Handle CCC_OVERRIDE_OPTIONS, used for editing a command line behind the
435 // scenes.
436 if (const char *OverrideStr = ::getenv(“CCC_OVERRIDE_OPTIONS”)) {
437 // FIXME: Driver shouldn’t take extra initial argument.
438 ApplyQAOverride(argv, OverrideStr, SavedStrings);
439 }
440
441 std::string Path = GetExecutablePath(argv[0], CanonicalPrefixes);
442
443 IntrusiveRefCntPtr DiagOpts =
444 CreateAndPopulateDiagOpts(argv);
445
446 TextDiagnosticPrinter *DiagClient
447 = new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
448 FixupDiagPrefixExeName(DiagClient, Path);
449
450 IntrusiveRefCntPtr DiagID(new DiagnosticIDs());
451
452 DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient);
453 ProcessWarningOptions(Diags, *DiagOpts, /ReportDiags=/false);
454
455 Driver TheDriver(Path, llvm::sys::getDefaultTargetTriple(), Diags);
456 SetInstallDir(argv, TheDriver);
457
458 llvm::InitializeAllTargets();
459 ParseProgName(argv, SavedStrings);
460
461 SetBackdoorDriverOutputsFromEnvVars(TheDriver);
462
463 std::unique_ptr C(TheDriver.BuildCompilation(argv));
464 int Res = 0;
465 SmallVector<std::pair<int, const Command *>, 4> FailingCommands;
466 llvm::outs() << “clang main function start point 4” << ‘\n’;
467 if (C.get())
468 Res = TheDriver.ExecuteCompilation(*C, FailingCommands);
469
470 llvm::outs() << “clang main function start point 5” << ‘\n’;
471 // Force a crash to test the diagnostics.
472 if (::getenv(“FORCE_CLANG_DIAGNOSTICS_CRASH”)) {
473 Diags.Report(diag::err_drv_force_crash) << “FORCE_CLANG_DIAGNOSTICS_CRASH”;
474 const Command *FailingCommand = nullptr;
475 FailingCommands.push_back(std::make_pair(-1, FailingCommand));
476 }
477
478 for (const auto &P : FailingCommands) {
479 int CommandRes = P.first;
480 const Command *FailingCommand = P.second;
481 if (!Res)
482 Res = CommandRes;
483
484 // If result status is < 0, then the driver command signalled an error.
485 // If result status is 70, then the driver command reported a fatal error.
486 // On Windows, abort will return an exit code of 3. In these cases,
487 // generate additional diagnostic information if possible.
488 bool DiagnoseCrash = CommandRes < 0 || CommandRes == 70;
489 #ifdef LLVM_ON_WIN32
490 DiagnoseCrash |= CommandRes == 3;
491 #endif
492 if (DiagnoseCrash) {
493 TheDriver.generateCompilationDiagnostics(*C, FailingCommand);
494 break;
495 }
496 }
497
498 // If any timers were active but haven’t been destroyed yet, print their
499 // results now. This happens in -disable-free mode.
500 llvm::TimerGroup::printAll(llvm::errs());
501
502 llvm::llvm_shutdown();
503
504 #ifdef LLVM_ON_WIN32
505 // Exit status should not be negative on Win32, unless abnormal termination.
506 // Once abnormal termiation was caught, negative status should not be
507 // propagated.
508 if (Res < 0)
509 Res = 1;
510 #endif
511
512 llvm::outs() << “clang main function start point 6” << ‘\n’;
513 // If we have multiple failing commands, we return the result of the first
514 // failing command.
515 return Res;
516 }