llvm-project/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
Fangrui Song 2d94dd812f Revert D60974 "[clang-ifs] Clang Interface Stubs, first version."
This reverts commit rC363626.

clangIndex depends on clangFrontend. r363626 adds a dependency from
clangFrontend to clangIndex, which creates a circular dependency.

This is disallowed by -DBUILD_SHARED_LIBS=on builds:

    CMake Error: The inter-target dependency graph contains the following strongly connected component (cycle):
      "clangFrontend" of type SHARED_LIBRARY
        depends on "clangIndex" (weak)
      "clangIndex" of type SHARED_LIBRARY
        depends on "clangFrontend" (weak)
    At least one of these targets is not a STATIC_LIBRARY.  Cyclic dependencies are allowed only among static libraries.

Note, the dependency on clangIndex cannot be removed because
libclangFrontend.so is linked with -Wl,-z,defs: a shared object must
have its full direct dependencies specified on the linker command line.

In -DBUILD_SHARED_LIBS=off builds, this appears to work when linking
`bin/clang-9`. However, it can cause trouble to downstream clang library
users. The llvm build system links libraries this way:

    clang main_program_object_file ... lib/libclangIndex.a ...  lib/libclangFrontend.a -o exe

libclangIndex.a etc are not wrapped in --start-group.

If the downstream application depends on libclangFrontend.a but not any
other clang libraries that depend on libclangIndex.a, this can cause undefined
reference errors when the linker is ld.bfd or gold.

The proper fix is to not include clangIndex files in clangFrontend.

llvm-svn: 363649
2019-06-18 05:52:39 +00:00

294 lines
12 KiB
C++

//===--- ExecuteCompilerInvocation.cpp ------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file holds ExecuteCompilerInvocation(). It is split into its own file to
// minimize the impact of pulling in essentially everything else in Clang.
//
//===----------------------------------------------------------------------===//
#include "clang/ARCMigrate/ARCMTActions.h"
#include "clang/CodeGen/CodeGenAction.h"
#include "clang/Config/config.h"
#include "clang/Driver/Options.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/FrontendPluginRegistry.h"
#include "clang/Frontend/Utils.h"
#include "clang/FrontendTool/Utils.h"
#include "clang/Rewrite/Frontend/FrontendActions.h"
#include "clang/StaticAnalyzer/Frontend/FrontendActions.h"
#include "llvm/Option/OptTable.h"
#include "llvm/Option/Option.h"
#include "llvm/Support/BuryPointer.h"
#include "llvm/Support/DynamicLibrary.h"
#include "llvm/Support/ErrorHandling.h"
using namespace clang;
using namespace llvm::opt;
namespace clang {
static std::unique_ptr<FrontendAction>
CreateFrontendBaseAction(CompilerInstance &CI) {
using namespace clang::frontend;
StringRef Action("unknown");
(void)Action;
switch (CI.getFrontendOpts().ProgramAction) {
case ASTDeclList: return llvm::make_unique<ASTDeclListAction>();
case ASTDump: return llvm::make_unique<ASTDumpAction>();
case ASTPrint: return llvm::make_unique<ASTPrintAction>();
case ASTView: return llvm::make_unique<ASTViewAction>();
case DumpCompilerOptions:
return llvm::make_unique<DumpCompilerOptionsAction>();
case DumpRawTokens: return llvm::make_unique<DumpRawTokensAction>();
case DumpTokens: return llvm::make_unique<DumpTokensAction>();
case EmitAssembly: return llvm::make_unique<EmitAssemblyAction>();
case EmitBC: return llvm::make_unique<EmitBCAction>();
case EmitHTML: return llvm::make_unique<HTMLPrintAction>();
case EmitLLVM: return llvm::make_unique<EmitLLVMAction>();
case EmitLLVMOnly: return llvm::make_unique<EmitLLVMOnlyAction>();
case EmitCodeGenOnly: return llvm::make_unique<EmitCodeGenOnlyAction>();
case EmitObj: return llvm::make_unique<EmitObjAction>();
case FixIt: return llvm::make_unique<FixItAction>();
case GenerateModule:
return llvm::make_unique<GenerateModuleFromModuleMapAction>();
case GenerateModuleInterface:
return llvm::make_unique<GenerateModuleInterfaceAction>();
case GenerateHeaderModule:
return llvm::make_unique<GenerateHeaderModuleAction>();
case GeneratePCH: return llvm::make_unique<GeneratePCHAction>();
case InitOnly: return llvm::make_unique<InitOnlyAction>();
case ParseSyntaxOnly: return llvm::make_unique<SyntaxOnlyAction>();
case ModuleFileInfo: return llvm::make_unique<DumpModuleInfoAction>();
case VerifyPCH: return llvm::make_unique<VerifyPCHAction>();
case TemplightDump: return llvm::make_unique<TemplightDumpAction>();
case PluginAction: {
for (FrontendPluginRegistry::iterator it =
FrontendPluginRegistry::begin(), ie = FrontendPluginRegistry::end();
it != ie; ++it) {
if (it->getName() == CI.getFrontendOpts().ActionName) {
std::unique_ptr<PluginASTAction> P(it->instantiate());
if ((P->getActionType() != PluginASTAction::ReplaceAction &&
P->getActionType() != PluginASTAction::Cmdline) ||
!P->ParseArgs(CI, CI.getFrontendOpts().PluginArgs[it->getName()]))
return nullptr;
return std::move(P);
}
}
CI.getDiagnostics().Report(diag::err_fe_invalid_plugin_name)
<< CI.getFrontendOpts().ActionName;
return nullptr;
}
case PrintPreamble: return llvm::make_unique<PrintPreambleAction>();
case PrintPreprocessedInput: {
if (CI.getPreprocessorOutputOpts().RewriteIncludes ||
CI.getPreprocessorOutputOpts().RewriteImports)
return llvm::make_unique<RewriteIncludesAction>();
return llvm::make_unique<PrintPreprocessedAction>();
}
case RewriteMacros: return llvm::make_unique<RewriteMacrosAction>();
case RewriteTest: return llvm::make_unique<RewriteTestAction>();
#if CLANG_ENABLE_OBJC_REWRITER
case RewriteObjC: return llvm::make_unique<RewriteObjCAction>();
#else
case RewriteObjC: Action = "RewriteObjC"; break;
#endif
#if CLANG_ENABLE_ARCMT
case MigrateSource:
return llvm::make_unique<arcmt::MigrateSourceAction>();
#else
case MigrateSource: Action = "MigrateSource"; break;
#endif
#if CLANG_ENABLE_STATIC_ANALYZER
case RunAnalysis: return llvm::make_unique<ento::AnalysisAction>();
#else
case RunAnalysis: Action = "RunAnalysis"; break;
#endif
case RunPreprocessorOnly: return llvm::make_unique<PreprocessOnlyAction>();
case PrintDependencyDirectivesSourceMinimizerOutput:
return llvm::make_unique<PrintDependencyDirectivesSourceMinimizerAction>();
}
#if !CLANG_ENABLE_ARCMT || !CLANG_ENABLE_STATIC_ANALYZER \
|| !CLANG_ENABLE_OBJC_REWRITER
CI.getDiagnostics().Report(diag::err_fe_action_not_available) << Action;
return 0;
#else
llvm_unreachable("Invalid program action!");
#endif
}
std::unique_ptr<FrontendAction>
CreateFrontendAction(CompilerInstance &CI) {
// Create the underlying action.
std::unique_ptr<FrontendAction> Act = CreateFrontendBaseAction(CI);
if (!Act)
return nullptr;
const FrontendOptions &FEOpts = CI.getFrontendOpts();
if (FEOpts.FixAndRecompile) {
Act = llvm::make_unique<FixItRecompile>(std::move(Act));
}
#if CLANG_ENABLE_ARCMT
if (CI.getFrontendOpts().ProgramAction != frontend::MigrateSource &&
CI.getFrontendOpts().ProgramAction != frontend::GeneratePCH) {
// Potentially wrap the base FE action in an ARC Migrate Tool action.
switch (FEOpts.ARCMTAction) {
case FrontendOptions::ARCMT_None:
break;
case FrontendOptions::ARCMT_Check:
Act = llvm::make_unique<arcmt::CheckAction>(std::move(Act));
break;
case FrontendOptions::ARCMT_Modify:
Act = llvm::make_unique<arcmt::ModifyAction>(std::move(Act));
break;
case FrontendOptions::ARCMT_Migrate:
Act = llvm::make_unique<arcmt::MigrateAction>(std::move(Act),
FEOpts.MTMigrateDir,
FEOpts.ARCMTMigrateReportOut,
FEOpts.ARCMTMigrateEmitARCErrors);
break;
}
if (FEOpts.ObjCMTAction != FrontendOptions::ObjCMT_None) {
Act = llvm::make_unique<arcmt::ObjCMigrateAction>(std::move(Act),
FEOpts.MTMigrateDir,
FEOpts.ObjCMTAction);
}
}
#endif
// If there are any AST files to merge, create a frontend action
// adaptor to perform the merge.
if (!FEOpts.ASTMergeFiles.empty())
Act = llvm::make_unique<ASTMergeAction>(std::move(Act),
FEOpts.ASTMergeFiles);
return Act;
}
bool ExecuteCompilerInvocation(CompilerInstance *Clang) {
// Honor -help.
if (Clang->getFrontendOpts().ShowHelp) {
std::unique_ptr<OptTable> Opts = driver::createDriverOptTable();
Opts->PrintHelp(llvm::outs(), "clang -cc1 [options] file...",
"LLVM 'Clang' Compiler: http://clang.llvm.org",
/*Include=*/driver::options::CC1Option,
/*Exclude=*/0, /*ShowAllAliases=*/false);
return true;
}
// Honor -version.
//
// FIXME: Use a better -version message?
if (Clang->getFrontendOpts().ShowVersion) {
llvm::cl::PrintVersionMessage();
return true;
}
// Load any requested plugins.
for (unsigned i = 0,
e = Clang->getFrontendOpts().Plugins.size(); i != e; ++i) {
const std::string &Path = Clang->getFrontendOpts().Plugins[i];
std::string Error;
if (llvm::sys::DynamicLibrary::LoadLibraryPermanently(Path.c_str(), &Error))
Clang->getDiagnostics().Report(diag::err_fe_unable_to_load_plugin)
<< Path << Error;
}
// Check if any of the loaded plugins replaces the main AST action
for (FrontendPluginRegistry::iterator it = FrontendPluginRegistry::begin(),
ie = FrontendPluginRegistry::end();
it != ie; ++it) {
std::unique_ptr<PluginASTAction> P(it->instantiate());
if (P->getActionType() == PluginASTAction::ReplaceAction) {
Clang->getFrontendOpts().ProgramAction = clang::frontend::PluginAction;
Clang->getFrontendOpts().ActionName = it->getName();
break;
}
}
// Honor -mllvm.
//
// FIXME: Remove this, one day.
// This should happen AFTER plugins have been loaded!
if (!Clang->getFrontendOpts().LLVMArgs.empty()) {
unsigned NumArgs = Clang->getFrontendOpts().LLVMArgs.size();
auto Args = llvm::make_unique<const char*[]>(NumArgs + 2);
Args[0] = "clang (LLVM option parsing)";
for (unsigned i = 0; i != NumArgs; ++i)
Args[i + 1] = Clang->getFrontendOpts().LLVMArgs[i].c_str();
Args[NumArgs + 1] = nullptr;
llvm::cl::ParseCommandLineOptions(NumArgs + 1, Args.get());
}
#if CLANG_ENABLE_STATIC_ANALYZER
// These should happen AFTER plugins have been loaded!
AnalyzerOptions &AnOpts = *Clang->getAnalyzerOpts();
// Honor -analyzer-checker-help and -analyzer-checker-help-hidden.
if (AnOpts.ShowCheckerHelp || AnOpts.ShowCheckerHelpAlpha ||
AnOpts.ShowCheckerHelpDeveloper) {
ento::printCheckerHelp(llvm::outs(),
Clang->getFrontendOpts().Plugins,
AnOpts,
Clang->getDiagnostics(),
Clang->getLangOpts());
return true;
}
// Honor -analyzer-checker-option-help.
if (AnOpts.ShowCheckerOptionList || AnOpts.ShowCheckerOptionAlphaList ||
AnOpts.ShowCheckerOptionDeveloperList) {
ento::printCheckerConfigList(llvm::outs(),
Clang->getFrontendOpts().Plugins,
*Clang->getAnalyzerOpts(),
Clang->getDiagnostics(),
Clang->getLangOpts());
return true;
}
// Honor -analyzer-list-enabled-checkers.
if (AnOpts.ShowEnabledCheckerList) {
ento::printEnabledCheckerList(llvm::outs(),
Clang->getFrontendOpts().Plugins,
AnOpts,
Clang->getDiagnostics(),
Clang->getLangOpts());
}
// Honor -analyzer-config-help.
if (AnOpts.ShowConfigOptionsList) {
ento::printAnalyzerConfigList(llvm::outs());
return true;
}
#endif
// If there were errors in processing arguments, don't do anything else.
if (Clang->getDiagnostics().hasErrorOccurred())
return false;
// Create and execute the frontend action.
std::unique_ptr<FrontendAction> Act(CreateFrontendAction(*Clang));
if (!Act)
return false;
bool Success = Clang->ExecuteAction(*Act);
if (Clang->getFrontendOpts().DisableFree)
llvm::BuryPointer(std::move(Act));
return Success;
}
} // namespace clang