summaryrefslogtreecommitdiff
path: root/clang/tools/driver
diff options
context:
space:
mode:
authorZancanaro; Carlo <czan8762@plang3.cs.usyd.edu.au>2012-09-24 09:58:17 +1000
committerZancanaro; Carlo <czan8762@plang3.cs.usyd.edu.au>2012-09-24 09:58:17 +1000
commit222e2a7620e6520ffaf4fc4e69d79c18da31542e (patch)
tree7bfbc05bfa3b41c8f9d2e56d53a0bc3e310df239 /clang/tools/driver
parent3d206f03985b50beacae843d880bccdc91a9f424 (diff)
Add the clang library to the repo (with some of my changes, too).
Diffstat (limited to 'clang/tools/driver')
-rw-r--r--clang/tools/driver/CMakeLists.txt63
-rw-r--r--clang/tools/driver/Info.plist.in18
-rw-r--r--clang/tools/driver/Makefile69
-rw-r--r--clang/tools/driver/cc1_main.cpp189
-rw-r--r--clang/tools/driver/cc1as_main.cpp451
-rw-r--r--clang/tools/driver/clang_symlink.cmake27
-rw-r--r--clang/tools/driver/driver.cpp490
7 files changed, 1307 insertions, 0 deletions
diff --git a/clang/tools/driver/CMakeLists.txt b/clang/tools/driver/CMakeLists.txt
new file mode 100644
index 0000000..ae49ac1
--- /dev/null
+++ b/clang/tools/driver/CMakeLists.txt
@@ -0,0 +1,63 @@
+set( LLVM_USED_LIBS
+ clangFrontendTool
+ clangAST
+ clangAnalysis
+ clangBasic
+ clangCodeGen
+ clangDriver
+ clangEdit
+ clangFrontend
+ clangLex
+ clangParse
+ clangEdit
+ clangARCMigrate
+ clangRewrite
+ clangSema
+ clangSerialization
+ clangStaticAnalyzerFrontend
+ clangStaticAnalyzerCheckers
+ clangStaticAnalyzerCore
+ )
+
+set( LLVM_LINK_COMPONENTS
+ ${LLVM_TARGETS_TO_BUILD}
+ asmparser
+ bitreader
+ bitwriter
+ codegen
+ instrumentation
+ ipo
+ linker
+ selectiondag
+ )
+
+add_clang_executable(clang
+ driver.cpp
+ cc1_main.cpp
+ cc1as_main.cpp
+ )
+
+set_target_properties(clang PROPERTIES VERSION ${CLANG_EXECUTABLE_VERSION})
+
+if(UNIX)
+ set(CLANGXX_LINK_OR_COPY create_symlink)
+# Create a relative symlink
+ set(clang_binary "clang${CMAKE_EXECUTABLE_SUFFIX}")
+else()
+ set(CLANGXX_LINK_OR_COPY copy)
+ set(clang_binary "${LLVM_BINARY_DIR}/bin/${CMAKE_CFG_INTDIR}/clang${CMAKE_EXECUTABLE_SUFFIX}")
+endif()
+
+# Create the clang++ symlink in the build directory.
+set(clang_pp "${LLVM_BINARY_DIR}/bin/${CMAKE_CFG_INTDIR}/clang++${CMAKE_EXECUTABLE_SUFFIX}")
+add_custom_command(TARGET clang POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E ${CLANGXX_LINK_OR_COPY} "${clang_binary}" "${clang_pp}")
+
+set_property(DIRECTORY APPEND
+ PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${clang_pp})
+
+install(TARGETS clang
+ RUNTIME DESTINATION bin)
+
+# Create the clang++ symlink at installation time.
+install(SCRIPT clang_symlink.cmake -DCMAKE_INSTALL_PREFIX=\"${CMAKE_INSTALL_PREFIX}\")
diff --git a/clang/tools/driver/Info.plist.in b/clang/tools/driver/Info.plist.in
new file mode 100644
index 0000000..c938fb0
--- /dev/null
+++ b/clang/tools/driver/Info.plist.in
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleIdentifier</key>
+ <string>@TOOL_INFO_UTI@</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>@TOOL_INFO_NAME</string>
+ <key>CFBundleShortVersionString</key>
+ <string>@TOOL_INFO_VERSION@</string>
+ <key>CFBundleVersion</key>
+ <string>@TOOL_INFO_BUILD_VERSION@</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+</dict>
+</plist>
diff --git a/clang/tools/driver/Makefile b/clang/tools/driver/Makefile
new file mode 100644
index 0000000..270d4fd
--- /dev/null
+++ b/clang/tools/driver/Makefile
@@ -0,0 +1,69 @@
+##===- tools/driver/Makefile -------------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+CLANG_LEVEL := ../..
+
+TOOLNAME = clang
+TOOLALIAS = clang++
+
+# We don't currently expect production Clang builds to be interested in
+# plugins. This is important for startup performance.
+ifdef CLANG_IS_PRODUCTION
+TOOL_NO_EXPORTS := 1
+endif
+
+ifdef CLANG_ORDER_FILE
+TOOL_ORDER_FILE := $(CLANG_ORDER_FILE)
+endif
+
+# Include tool version information on OS X.
+TOOL_INFO_PLIST := Info.plist
+
+# Include this here so we can get the configuration of the targets that have
+# been configured for construction. We have to do this early so we can set up
+# LINK_COMPONENTS before including Makefile.rules
+include $(CLANG_LEVEL)/../../Makefile.config
+
+LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader bitwriter codegen \
+ instrumentation ipo linker selectiondag
+USEDLIBS = clangFrontendTool.a clangFrontend.a clangDriver.a \
+ clangSerialization.a clangCodeGen.a clangParse.a clangSema.a \
+ clangStaticAnalyzerFrontend.a clangStaticAnalyzerCheckers.a \
+ clangStaticAnalyzerCore.a \
+ clangAnalysis.a clangARCMigrate.a clangRewrite.a \
+ clangEdit.a clangAST.a clangLex.a clangBasic.a
+
+include $(CLANG_LEVEL)/Makefile
+
+# Set the tool version information values.
+ifeq ($(HOST_OS),Darwin)
+ifdef CLANG_VENDOR
+TOOL_INFO_NAME := $(CLANG_VENDOR) clang
+else
+TOOL_INFO_NAME := clang
+endif
+
+ifdef CLANG_VENDOR_UTI
+TOOL_INFO_UTI := $(CLANG_VENDOR_UTI)
+else
+TOOL_INFO_UTI := org.llvm.clang
+endif
+
+TOOL_INFO_VERSION := $(word 3,$(shell grep "CLANG_VERSION " \
+ $(PROJ_OBJ_DIR)/$(CLANG_LEVEL)/include/clang/Basic/Version.inc))
+ifdef LLVM_SUBMIT_VERSION
+TOOL_INFO_BUILD_VERSION := $(LLVM_SUBMIT_VERSION).$(LLVM_SUBMIT_SUBVERSION)
+else
+TOOL_INFO_BUILD_VERSION :=
+endif
+endif
+
+# Translate make variable to define when building a "production" clang.
+ifdef CLANG_IS_PRODUCTION
+CPP.Defines += -DCLANG_IS_PRODUCTION
+endif
diff --git a/clang/tools/driver/cc1_main.cpp b/clang/tools/driver/cc1_main.cpp
new file mode 100644
index 0000000..a211090
--- /dev/null
+++ b/clang/tools/driver/cc1_main.cpp
@@ -0,0 +1,189 @@
+//===-- cc1_main.cpp - Clang CC1 Compiler Frontend ------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This is the entry point to the clang -cc1 functionality, which implements the
+// core compiler functionality along with a number of additional tools for
+// demonstration and testing purposes.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Driver/Arg.h"
+#include "clang/Driver/ArgList.h"
+#include "clang/Driver/CC1Options.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/OptTable.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Frontend/TextDiagnosticBuffer.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/FrontendTool/Utils.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/Timer.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/LinkAllPasses.h"
+#include <cstdio>
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Main driver
+//===----------------------------------------------------------------------===//
+
+static void LLVMErrorHandler(void *UserData, const std::string &Message) {
+ DiagnosticsEngine &Diags = *static_cast<DiagnosticsEngine*>(UserData);
+
+ Diags.Report(diag::err_fe_error_backend) << Message;
+
+ // We cannot recover from llvm errors.
+ exit(1);
+}
+
+// FIXME: Define the need for this testing away.
+static int cc1_test(DiagnosticsEngine &Diags,
+ const char **ArgBegin, const char **ArgEnd) {
+ using namespace clang::driver;
+
+ llvm::errs() << "cc1 argv:";
+ for (const char **i = ArgBegin; i != ArgEnd; ++i)
+ llvm::errs() << " \"" << *i << '"';
+ llvm::errs() << "\n";
+
+ // Parse the arguments.
+ OptTable *Opts = createCC1OptTable();
+ unsigned MissingArgIndex, MissingArgCount;
+ InputArgList *Args = Opts->ParseArgs(ArgBegin, ArgEnd,
+ MissingArgIndex, MissingArgCount);
+
+ // Check for missing argument error.
+ if (MissingArgCount)
+ Diags.Report(clang::diag::err_drv_missing_argument)
+ << Args->getArgString(MissingArgIndex) << MissingArgCount;
+
+ // Dump the parsed arguments.
+ llvm::errs() << "cc1 parsed options:\n";
+ for (ArgList::const_iterator it = Args->begin(), ie = Args->end();
+ it != ie; ++it)
+ (*it)->dump();
+
+ // Create a compiler invocation.
+ llvm::errs() << "cc1 creating invocation.\n";
+ CompilerInvocation Invocation;
+ if (!CompilerInvocation::CreateFromArgs(Invocation, ArgBegin, ArgEnd, Diags))
+ return 1;
+
+ // Convert the invocation back to argument strings.
+ std::vector<std::string> InvocationArgs;
+ Invocation.toArgs(InvocationArgs);
+
+ // Dump the converted arguments.
+ SmallVector<const char*, 32> Invocation2Args;
+ llvm::errs() << "invocation argv :";
+ for (unsigned i = 0, e = InvocationArgs.size(); i != e; ++i) {
+ Invocation2Args.push_back(InvocationArgs[i].c_str());
+ llvm::errs() << " \"" << InvocationArgs[i] << '"';
+ }
+ llvm::errs() << "\n";
+
+ // Convert those arguments to another invocation, and check that we got the
+ // same thing.
+ CompilerInvocation Invocation2;
+ if (!CompilerInvocation::CreateFromArgs(Invocation2, Invocation2Args.begin(),
+ Invocation2Args.end(), Diags))
+ return 1;
+
+ // FIXME: Implement CompilerInvocation comparison.
+ if (true) {
+ //llvm::errs() << "warning: Invocations differ!\n";
+
+ std::vector<std::string> Invocation2Args;
+ Invocation2.toArgs(Invocation2Args);
+ llvm::errs() << "invocation2 argv:";
+ for (unsigned i = 0, e = Invocation2Args.size(); i != e; ++i)
+ llvm::errs() << " \"" << Invocation2Args[i] << '"';
+ llvm::errs() << "\n";
+ }
+
+ return 0;
+}
+
+int cc1_main(const char **ArgBegin, const char **ArgEnd,
+ const char *Argv0, void *MainAddr) {
+ OwningPtr<CompilerInstance> Clang(new CompilerInstance());
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+
+ // Run clang -cc1 test.
+ if (ArgBegin != ArgEnd && StringRef(ArgBegin[0]) == "-cc1test") {
+ DiagnosticsEngine Diags(DiagID, new TextDiagnosticPrinter(llvm::errs(),
+ DiagnosticOptions()));
+ return cc1_test(Diags, ArgBegin + 1, ArgEnd);
+ }
+
+ // Initialize targets first, so that --version shows registered targets.
+ llvm::InitializeAllTargets();
+ llvm::InitializeAllTargetMCs();
+ llvm::InitializeAllAsmPrinters();
+ llvm::InitializeAllAsmParsers();
+
+ // Buffer diagnostics from argument parsing so that we can output them using a
+ // well formed diagnostic object.
+ TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer;
+ DiagnosticsEngine Diags(DiagID, DiagsBuffer);
+ bool Success;
+ Success = CompilerInvocation::CreateFromArgs(Clang->getInvocation(),
+ ArgBegin, ArgEnd, Diags);
+
+ // Infer the builtin include path if unspecified.
+ if (Clang->getHeaderSearchOpts().UseBuiltinIncludes &&
+ Clang->getHeaderSearchOpts().ResourceDir.empty())
+ Clang->getHeaderSearchOpts().ResourceDir =
+ CompilerInvocation::GetResourcesPath(Argv0, MainAddr);
+
+ // Create the actual diagnostics engine.
+ Clang->createDiagnostics(ArgEnd - ArgBegin, const_cast<char**>(ArgBegin));
+ if (!Clang->hasDiagnostics())
+ return 1;
+
+ // Set an error handler, so that any LLVM backend diagnostics go through our
+ // error handler.
+ llvm::install_fatal_error_handler(LLVMErrorHandler,
+ static_cast<void*>(&Clang->getDiagnostics()));
+
+ DiagsBuffer->FlushDiagnostics(Clang->getDiagnostics());
+ if (!Success)
+ return 1;
+
+ // Execute the frontend actions.
+ Success = ExecuteCompilerInvocation(Clang.get());
+
+ // If any timers were active but haven't been destroyed yet, print their
+ // results now. This happens in -disable-free mode.
+ llvm::TimerGroup::printAll(llvm::errs());
+
+ // Our error handler depends on the Diagnostics object, which we're
+ // potentially about to delete. Uninstall the handler now so that any
+ // later errors use the default handling behavior instead.
+ llvm::remove_fatal_error_handler();
+
+ // When running with -disable-free, don't do any destruction or shutdown.
+ if (Clang->getFrontendOpts().DisableFree) {
+ if (llvm::AreStatisticsEnabled() || Clang->getFrontendOpts().ShowStats)
+ llvm::PrintStatistics();
+ Clang.take();
+ return !Success;
+ }
+
+ // Managed static deconstruction. Useful for making things like
+ // -time-passes usable.
+ llvm::llvm_shutdown();
+
+ return !Success;
+}
diff --git a/clang/tools/driver/cc1as_main.cpp b/clang/tools/driver/cc1as_main.cpp
new file mode 100644
index 0000000..508d6da
--- /dev/null
+++ b/clang/tools/driver/cc1as_main.cpp
@@ -0,0 +1,451 @@
+//===-- cc1as_main.cpp - Clang Assembler ---------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This is the entry point to the clang -cc1as functionality, which implements
+// the direct interface to the LLVM MC based assembler.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Driver/Arg.h"
+#include "clang/Driver/ArgList.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/CC1AsOptions.h"
+#include "clang/Driver/OptTable.h"
+#include "clang/Driver/Options.h"
+#include "clang/Frontend/DiagnosticOptions.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/MC/MCParser/MCAsmParser.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCCodeEmitter.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCObjectFileInfo.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/MC/MCAsmBackend.h"
+#include "llvm/MC/MCTargetAsmParser.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FormattedStream.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/Timer.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/system_error.h"
+#include "llvm/Target/TargetData.h"
+using namespace clang;
+using namespace clang::driver;
+using namespace llvm;
+
+namespace {
+
+/// \brief Helper class for representing a single invocation of the assembler.
+struct AssemblerInvocation {
+ /// @name Target Options
+ /// @{
+
+ /// The name of the target triple to assemble for.
+ std::string Triple;
+
+ /// If given, the name of the target CPU to determine which instructions
+ /// are legal.
+ std::string CPU;
+
+ /// The list of target specific features to enable or disable -- this should
+ /// be a list of strings starting with '+' or '-'.
+ std::vector<std::string> Features;
+
+ /// @}
+ /// @name Language Options
+ /// @{
+
+ std::vector<std::string> IncludePaths;
+ unsigned NoInitialTextSection : 1;
+ unsigned SaveTemporaryLabels : 1;
+ unsigned GenDwarfForAssembly : 1;
+ std::string DwarfDebugFlags;
+
+ /// @}
+ /// @name Frontend Options
+ /// @{
+
+ std::string InputFile;
+ std::vector<std::string> LLVMArgs;
+ std::string OutputPath;
+ enum FileType {
+ FT_Asm, ///< Assembly (.s) output, transliterate mode.
+ FT_Null, ///< No output, for timing purposes.
+ FT_Obj ///< Object file output.
+ };
+ FileType OutputType;
+ unsigned ShowHelp : 1;
+ unsigned ShowVersion : 1;
+
+ /// @}
+ /// @name Transliterate Options
+ /// @{
+
+ unsigned OutputAsmVariant;
+ unsigned ShowEncoding : 1;
+ unsigned ShowInst : 1;
+
+ /// @}
+ /// @name Assembler Options
+ /// @{
+
+ unsigned RelaxAll : 1;
+ unsigned NoExecStack : 1;
+
+ /// @}
+
+public:
+ AssemblerInvocation() {
+ Triple = "";
+ NoInitialTextSection = 0;
+ InputFile = "-";
+ OutputPath = "-";
+ OutputType = FT_Asm;
+ OutputAsmVariant = 0;
+ ShowInst = 0;
+ ShowEncoding = 0;
+ RelaxAll = 0;
+ NoExecStack = 0;
+ }
+
+ static bool CreateFromArgs(AssemblerInvocation &Res, const char **ArgBegin,
+ const char **ArgEnd, DiagnosticsEngine &Diags);
+};
+
+}
+
+bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
+ const char **ArgBegin,
+ const char **ArgEnd,
+ DiagnosticsEngine &Diags) {
+ using namespace clang::driver::cc1asoptions;
+ bool Success = true;
+
+ // Parse the arguments.
+ OwningPtr<OptTable> OptTbl(createCC1AsOptTable());
+ unsigned MissingArgIndex, MissingArgCount;
+ OwningPtr<InputArgList> Args(
+ OptTbl->ParseArgs(ArgBegin, ArgEnd,MissingArgIndex, MissingArgCount));
+
+ // Check for missing argument error.
+ if (MissingArgCount) {
+ Diags.Report(diag::err_drv_missing_argument)
+ << Args->getArgString(MissingArgIndex) << MissingArgCount;
+ Success = false;
+ }
+
+ // Issue errors on unknown arguments.
+ for (arg_iterator it = Args->filtered_begin(cc1asoptions::OPT_UNKNOWN),
+ ie = Args->filtered_end(); it != ie; ++it) {
+ Diags.Report(diag::err_drv_unknown_argument) << (*it) ->getAsString(*Args);
+ Success = false;
+ }
+
+ // Construct the invocation.
+
+ // Target Options
+ Opts.Triple = llvm::Triple::normalize(Args->getLastArgValue(OPT_triple));
+ Opts.CPU = Args->getLastArgValue(OPT_target_cpu);
+ Opts.Features = Args->getAllArgValues(OPT_target_feature);
+
+ // Use the default target triple if unspecified.
+ if (Opts.Triple.empty())
+ Opts.Triple = llvm::sys::getDefaultTargetTriple();
+
+ // Language Options
+ Opts.IncludePaths = Args->getAllArgValues(OPT_I);
+ Opts.NoInitialTextSection = Args->hasArg(OPT_n);
+ Opts.SaveTemporaryLabels = Args->hasArg(OPT_L);
+ Opts.GenDwarfForAssembly = Args->hasArg(OPT_g);
+ Opts.DwarfDebugFlags = Args->getLastArgValue(OPT_dwarf_debug_flags);
+
+ // Frontend Options
+ if (Args->hasArg(OPT_INPUT)) {
+ bool First = true;
+ for (arg_iterator it = Args->filtered_begin(OPT_INPUT),
+ ie = Args->filtered_end(); it != ie; ++it, First=false) {
+ const Arg *A = it;
+ if (First)
+ Opts.InputFile = A->getValue(*Args);
+ else {
+ Diags.Report(diag::err_drv_unknown_argument) << A->getAsString(*Args);
+ Success = false;
+ }
+ }
+ }
+ Opts.LLVMArgs = Args->getAllArgValues(OPT_mllvm);
+ if (Args->hasArg(OPT_fatal_warnings))
+ Opts.LLVMArgs.push_back("-fatal-assembler-warnings");
+ Opts.OutputPath = Args->getLastArgValue(OPT_o);
+ if (Arg *A = Args->getLastArg(OPT_filetype)) {
+ StringRef Name = A->getValue(*Args);
+ unsigned OutputType = StringSwitch<unsigned>(Name)
+ .Case("asm", FT_Asm)
+ .Case("null", FT_Null)
+ .Case("obj", FT_Obj)
+ .Default(~0U);
+ if (OutputType == ~0U) {
+ Diags.Report(diag::err_drv_invalid_value)
+ << A->getAsString(*Args) << Name;
+ Success = false;
+ } else
+ Opts.OutputType = FileType(OutputType);
+ }
+ Opts.ShowHelp = Args->hasArg(OPT_help);
+ Opts.ShowVersion = Args->hasArg(OPT_version);
+
+ // Transliterate Options
+ Opts.OutputAsmVariant = Args->getLastArgIntValue(OPT_output_asm_variant,
+ 0, Diags);
+ Opts.ShowEncoding = Args->hasArg(OPT_show_encoding);
+ Opts.ShowInst = Args->hasArg(OPT_show_inst);
+
+ // Assemble Options
+ Opts.RelaxAll = Args->hasArg(OPT_relax_all);
+ Opts.NoExecStack = Args->hasArg(OPT_no_exec_stack);
+
+ return Success;
+}
+
+static formatted_raw_ostream *GetOutputStream(AssemblerInvocation &Opts,
+ DiagnosticsEngine &Diags,
+ bool Binary) {
+ if (Opts.OutputPath.empty())
+ Opts.OutputPath = "-";
+
+ // Make sure that the Out file gets unlinked from the disk if we get a
+ // SIGINT.
+ if (Opts.OutputPath != "-")
+ sys::RemoveFileOnSignal(sys::Path(Opts.OutputPath));
+
+ std::string Error;
+ raw_fd_ostream *Out =
+ new raw_fd_ostream(Opts.OutputPath.c_str(), Error,
+ (Binary ? raw_fd_ostream::F_Binary : 0));
+ if (!Error.empty()) {
+ Diags.Report(diag::err_fe_unable_to_open_output)
+ << Opts.OutputPath << Error;
+ return 0;
+ }
+
+ return new formatted_raw_ostream(*Out, formatted_raw_ostream::DELETE_STREAM);
+}
+
+static bool ExecuteAssembler(AssemblerInvocation &Opts,
+ DiagnosticsEngine &Diags) {
+ // Get the target specific parser.
+ std::string Error;
+ const Target *TheTarget(TargetRegistry::lookupTarget(Opts.Triple, Error));
+ if (!TheTarget) {
+ Diags.Report(diag::err_target_unknown_triple) << Opts.Triple;
+ return false;
+ }
+
+ OwningPtr<MemoryBuffer> BufferPtr;
+ if (error_code ec = MemoryBuffer::getFileOrSTDIN(Opts.InputFile, BufferPtr)) {
+ Error = ec.message();
+ Diags.Report(diag::err_fe_error_reading) << Opts.InputFile;
+ return false;
+ }
+ MemoryBuffer *Buffer = BufferPtr.take();
+
+ SourceMgr SrcMgr;
+
+ // Tell SrcMgr about this buffer, which is what the parser will pick up.
+ SrcMgr.AddNewSourceBuffer(Buffer, SMLoc());
+
+ // Record the location of the include directories so that the lexer can find
+ // it later.
+ SrcMgr.setIncludeDirs(Opts.IncludePaths);
+
+ OwningPtr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(Opts.Triple));
+ assert(MAI && "Unable to create target asm info!");
+
+ OwningPtr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(Opts.Triple));
+ assert(MRI && "Unable to create target register info!");
+
+ bool IsBinary = Opts.OutputType == AssemblerInvocation::FT_Obj;
+ formatted_raw_ostream *Out = GetOutputStream(Opts, Diags, IsBinary);
+ if (!Out)
+ return false;
+
+ // FIXME: This is not pretty. MCContext has a ptr to MCObjectFileInfo and
+ // MCObjectFileInfo needs a MCContext reference in order to initialize itself.
+ OwningPtr<MCObjectFileInfo> MOFI(new MCObjectFileInfo());
+ MCContext Ctx(*MAI, *MRI, MOFI.get(), &SrcMgr);
+ // FIXME: Assembler behavior can change with -static.
+ MOFI->InitMCObjectFileInfo(Opts.Triple,
+ Reloc::Default, CodeModel::Default, Ctx);
+ if (Opts.SaveTemporaryLabels)
+ Ctx.setAllowTemporaryLabels(false);
+ if (Opts.GenDwarfForAssembly)
+ Ctx.setGenDwarfForAssembly(true);
+ if (!Opts.DwarfDebugFlags.empty())
+ Ctx.setDwarfDebugFlags(StringRef(Opts.DwarfDebugFlags));
+
+ // Build up the feature string from the target feature list.
+ std::string FS;
+ if (!Opts.Features.empty()) {
+ FS = Opts.Features[0];
+ for (unsigned i = 1, e = Opts.Features.size(); i != e; ++i)
+ FS += "," + Opts.Features[i];
+ }
+
+ OwningPtr<MCStreamer> Str;
+
+ OwningPtr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo());
+ OwningPtr<MCSubtargetInfo>
+ STI(TheTarget->createMCSubtargetInfo(Opts.Triple, Opts.CPU, FS));
+
+ // FIXME: There is a bit of code duplication with addPassesToEmitFile.
+ if (Opts.OutputType == AssemblerInvocation::FT_Asm) {
+ MCInstPrinter *IP =
+ TheTarget->createMCInstPrinter(Opts.OutputAsmVariant, *MAI, *MCII, *MRI,
+ *STI);
+ MCCodeEmitter *CE = 0;
+ MCAsmBackend *MAB = 0;
+ if (Opts.ShowEncoding) {
+ CE = TheTarget->createMCCodeEmitter(*MCII, *STI, Ctx);
+ MAB = TheTarget->createMCAsmBackend(Opts.Triple);
+ }
+ Str.reset(TheTarget->createAsmStreamer(Ctx, *Out, /*asmverbose*/true,
+ /*useLoc*/ true,
+ /*useCFI*/ true,
+ /*useDwarfDirectory*/ true,
+ IP, CE, MAB,
+ Opts.ShowInst));
+ } else if (Opts.OutputType == AssemblerInvocation::FT_Null) {
+ Str.reset(createNullStreamer(Ctx));
+ } else {
+ assert(Opts.OutputType == AssemblerInvocation::FT_Obj &&
+ "Invalid file type!");
+ MCCodeEmitter *CE = TheTarget->createMCCodeEmitter(*MCII, *STI, Ctx);
+ MCAsmBackend *MAB = TheTarget->createMCAsmBackend(Opts.Triple);
+ Str.reset(TheTarget->createMCObjectStreamer(Opts.Triple, Ctx, *MAB, *Out,
+ CE, Opts.RelaxAll,
+ Opts.NoExecStack));
+ Str.get()->InitSections();
+ }
+
+ OwningPtr<MCAsmParser> Parser(createMCAsmParser(SrcMgr, Ctx,
+ *Str.get(), *MAI));
+ OwningPtr<MCTargetAsmParser> TAP(TheTarget->createMCAsmParser(*STI, *Parser));
+ if (!TAP) {
+ Diags.Report(diag::err_target_unknown_triple) << Opts.Triple;
+ return false;
+ }
+
+ Parser->setTargetParser(*TAP.get());
+
+ bool Success = !Parser->Run(Opts.NoInitialTextSection);
+
+ // Close the output.
+ delete Out;
+
+ // Delete output on errors.
+ if (!Success && Opts.OutputPath != "-")
+ sys::Path(Opts.OutputPath).eraseFromDisk();
+
+ return Success;
+}
+
+static void LLVMErrorHandler(void *UserData, const std::string &Message) {
+ DiagnosticsEngine &Diags = *static_cast<DiagnosticsEngine*>(UserData);
+
+ Diags.Report(diag::err_fe_error_backend) << Message;
+
+ // We cannot recover from llvm errors.
+ exit(1);
+}
+
+int cc1as_main(const char **ArgBegin, const char **ArgEnd,
+ const char *Argv0, void *MainAddr) {
+ // Print a stack trace if we signal out.
+ sys::PrintStackTraceOnErrorSignal();
+ PrettyStackTraceProgram X(ArgEnd - ArgBegin, ArgBegin);
+ llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
+
+ // Initialize targets and assembly printers/parsers.
+ InitializeAllTargetInfos();
+ InitializeAllTargetMCs();
+ InitializeAllAsmParsers();
+
+ // Construct our diagnostic client.
+ TextDiagnosticPrinter *DiagClient
+ = new TextDiagnosticPrinter(errs(), DiagnosticOptions());
+ DiagClient->setPrefix("clang -cc1as");
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ DiagnosticsEngine Diags(DiagID, DiagClient);
+
+ // Set an error handler, so that any LLVM backend diagnostics go through our
+ // error handler.
+ ScopedFatalErrorHandler FatalErrorHandler
+ (LLVMErrorHandler, static_cast<void*>(&Diags));
+
+ // Parse the arguments.
+ AssemblerInvocation Asm;
+ if (!AssemblerInvocation::CreateFromArgs(Asm, ArgBegin, ArgEnd, Diags))
+ return 1;
+
+ // Honor -help.
+ if (Asm.ShowHelp) {
+ OwningPtr<driver::OptTable> Opts(driver::createCC1AsOptTable());
+ Opts->PrintHelp(llvm::outs(), "clang -cc1as", "Clang Integrated Assembler");
+ return 0;
+ }
+
+ // Honor -version.
+ //
+ // FIXME: Use a better -version message?
+ if (Asm.ShowVersion) {
+ llvm::cl::PrintVersionMessage();
+ return 0;
+ }
+
+ // Honor -mllvm.
+ //
+ // FIXME: Remove this, one day.
+ if (!Asm.LLVMArgs.empty()) {
+ unsigned NumArgs = Asm.LLVMArgs.size();
+ const char **Args = new const char*[NumArgs + 2];
+ Args[0] = "clang (LLVM option parsing)";
+ for (unsigned i = 0; i != NumArgs; ++i)
+ Args[i + 1] = Asm.LLVMArgs[i].c_str();
+ Args[NumArgs + 1] = 0;
+ llvm::cl::ParseCommandLineOptions(NumArgs + 1, Args);
+ }
+
+ // Execute the invocation, unless there were parsing errors.
+ bool Success = false;
+ if (!Diags.hasErrorOccurred())
+ Success = ExecuteAssembler(Asm, Diags);
+
+ // If any timers were active but haven't been destroyed yet, print their
+ // results now.
+ TimerGroup::printAll(errs());
+
+ return !Success;
+}
diff --git a/clang/tools/driver/clang_symlink.cmake b/clang/tools/driver/clang_symlink.cmake
new file mode 100644
index 0000000..c7341cb
--- /dev/null
+++ b/clang/tools/driver/clang_symlink.cmake
@@ -0,0 +1,27 @@
+# We need to execute this script at installation time because the
+# DESTDIR environment variable may be unset at configuration time.
+# See PR8397.
+
+if(UNIX)
+ set(CLANGXX_LINK_OR_COPY create_symlink)
+ set(CLANGXX_DESTDIR $ENV{DESTDIR})
+else()
+ set(CLANGXX_LINK_OR_COPY copy)
+endif()
+
+# CMAKE_EXECUTABLE_SUFFIX is undefined on cmake scripts. See PR9286.
+if( WIN32 )
+ set(EXECUTABLE_SUFFIX ".exe")
+else()
+ set(EXECUTABLE_SUFFIX "")
+endif()
+
+set(bindir "${CLANGXX_DESTDIR}${CMAKE_INSTALL_PREFIX}/bin/")
+set(clang "clang${EXECUTABLE_SUFFIX}")
+set(clangxx "clang++${EXECUTABLE_SUFFIX}")
+
+message("Creating clang++ executable based on ${clang}")
+
+execute_process(
+ COMMAND "${CMAKE_COMMAND}" -E ${CLANGXX_LINK_OR_COPY} "${clang}" "${clangxx}"
+ WORKING_DIRECTORY "${bindir}")
diff --git a/clang/tools/driver/driver.cpp b/clang/tools/driver/driver.cpp
new file mode 100644
index 0000000..8c05fff
--- /dev/null
+++ b/clang/tools/driver/driver.cpp
@@ -0,0 +1,490 @@
+//===-- driver.cpp - Clang GCC-Compatible Driver --------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This is the entry point to the clang driver; it is a thin wrapper
+// for functionality in the Driver clang library.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Driver/ArgList.h"
+#include "clang/Driver/CC1Options.h"
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/Option.h"
+#include "clang/Driver/OptTable.h"
+#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Frontend/DiagnosticOptions.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Frontend/Utils.h"
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Regex.h"
+#include "llvm/Support/Timer.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Program.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/system_error.h"
+#include <cctype>
+using namespace clang;
+using namespace clang::driver;
+
+llvm::sys::Path GetExecutablePath(const char *Argv0, bool CanonicalPrefixes) {
+ if (!CanonicalPrefixes)
+ return llvm::sys::Path(Argv0);
+
+ // This just needs to be some symbol in the binary; C++ doesn't
+ // allow taking the address of ::main however.
+ void *P = (void*) (intptr_t) GetExecutablePath;
+ return llvm::sys::Path::GetMainExecutable(Argv0, P);
+}
+
+static const char *SaveStringInSet(std::set<std::string> &SavedStrings,
+ StringRef S) {
+ return SavedStrings.insert(S).first->c_str();
+}
+
+/// ApplyQAOverride - Apply a list of edits to the input argument lists.
+///
+/// The input string is a space separate list of edits to perform,
+/// they are applied in order to the input argument lists. Edits
+/// should be one of the following forms:
+///
+/// '#': Silence information about the changes to the command line arguments.
+///
+/// '^': Add FOO as a new argument at the beginning of the command line.
+///
+/// '+': Add FOO as a new argument at the end of the command line.
+///
+/// 's/XXX/YYY/': Substitute the regular expression XXX with YYY in the command
+/// line.
+///
+/// 'xOPTION': Removes all instances of the literal argument OPTION.
+///
+/// 'XOPTION': Removes all instances of the literal argument OPTION,
+/// and the following argument.
+///
+/// 'Ox': Removes all flags matching 'O' or 'O[sz0-9]' and adds 'Ox'
+/// at the end of the command line.
+///
+/// \param OS - The stream to write edit information to.
+/// \param Args - The vector of command line arguments.
+/// \param Edit - The override command to perform.
+/// \param SavedStrings - Set to use for storing string representations.
+static void ApplyOneQAOverride(raw_ostream &OS,
+ SmallVectorImpl<const char*> &Args,
+ StringRef Edit,
+ std::set<std::string> &SavedStrings) {
+ // This does not need to be efficient.
+
+ if (Edit[0] == '^') {
+ const char *Str =
+ SaveStringInSet(SavedStrings, Edit.substr(1));
+ OS << "### Adding argument " << Str << " at beginning\n";
+ Args.insert(Args.begin() + 1, Str);
+ } else if (Edit[0] == '+') {
+ const char *Str =
+ SaveStringInSet(SavedStrings, Edit.substr(1));
+ OS << "### Adding argument " << Str << " at end\n";
+ Args.push_back(Str);
+ } else if (Edit[0] == 's' && Edit[1] == '/' && Edit.endswith("/") &&
+ Edit.slice(2, Edit.size()-1).find('/') != StringRef::npos) {
+ StringRef MatchPattern = Edit.substr(2).split('/').first;
+ StringRef ReplPattern = Edit.substr(2).split('/').second;
+ ReplPattern = ReplPattern.slice(0, ReplPattern.size()-1);
+
+ for (unsigned i = 1, e = Args.size(); i != e; ++i) {
+ std::string Repl = llvm::Regex(MatchPattern).sub(ReplPattern, Args[i]);
+
+ if (Repl != Args[i]) {
+ OS << "### Replacing '" << Args[i] << "' with '" << Repl << "'\n";
+ Args[i] = SaveStringInSet(SavedStrings, Repl);
+ }
+ }
+ } else if (Edit[0] == 'x' || Edit[0] == 'X') {
+ std::string Option = Edit.substr(1, std::string::npos);
+ for (unsigned i = 1; i < Args.size();) {
+ if (Option == Args[i]) {
+ OS << "### Deleting argument " << Args[i] << '\n';
+ Args.erase(Args.begin() + i);
+ if (Edit[0] == 'X') {
+ if (i < Args.size()) {
+ OS << "### Deleting argument " << Args[i] << '\n';
+ Args.erase(Args.begin() + i);
+ } else
+ OS << "### Invalid X edit, end of command line!\n";
+ }
+ } else
+ ++i;
+ }
+ } else if (Edit[0] == 'O') {
+ for (unsigned i = 1; i < Args.size();) {
+ const char *A = Args[i];
+ if (A[0] == '-' && A[1] == 'O' &&
+ (A[2] == '\0' ||
+ (A[3] == '\0' && (A[2] == 's' || A[2] == 'z' ||
+ ('0' <= A[2] && A[2] <= '9'))))) {
+ OS << "### Deleting argument " << Args[i] << '\n';
+ Args.erase(Args.begin() + i);
+ } else
+ ++i;
+ }
+ OS << "### Adding argument " << Edit << " at end\n";
+ Args.push_back(SaveStringInSet(SavedStrings, '-' + Edit.str()));
+ } else {
+ OS << "### Unrecognized edit: " << Edit << "\n";
+ }
+}
+
+/// ApplyQAOverride - Apply a comma separate list of edits to the
+/// input argument lists. See ApplyOneQAOverride.
+static void ApplyQAOverride(SmallVectorImpl<const char*> &Args,
+ const char *OverrideStr,
+ std::set<std::string> &SavedStrings) {
+ raw_ostream *OS = &llvm::errs();
+
+ if (OverrideStr[0] == '#') {
+ ++OverrideStr;
+ OS = &llvm::nulls();
+ }
+
+ *OS << "### QA_OVERRIDE_GCC3_OPTIONS: " << OverrideStr << "\n";
+
+ // This does not need to be efficient.
+
+ const char *S = OverrideStr;
+ while (*S) {
+ const char *End = ::strchr(S, ' ');
+ if (!End)
+ End = S + strlen(S);
+ if (End != S)
+ ApplyOneQAOverride(*OS, Args, std::string(S, End), SavedStrings);
+ S = End;
+ if (*S != '\0')
+ ++S;
+ }
+}
+
+extern int cc1_main(const char **ArgBegin, const char **ArgEnd,
+ const char *Argv0, void *MainAddr);
+extern int cc1as_main(const char **ArgBegin, const char **ArgEnd,
+ const char *Argv0, void *MainAddr);
+
+static void ExpandArgsFromBuf(const char *Arg,
+ SmallVectorImpl<const char*> &ArgVector,
+ std::set<std::string> &SavedStrings) {
+ const char *FName = Arg + 1;
+ OwningPtr<llvm::MemoryBuffer> MemBuf;
+ if (llvm::MemoryBuffer::getFile(FName, MemBuf)) {
+ ArgVector.push_back(SaveStringInSet(SavedStrings, Arg));
+ return;
+ }
+
+ const char *Buf = MemBuf->getBufferStart();
+ char InQuote = ' ';
+ std::string CurArg;
+
+ for (const char *P = Buf; ; ++P) {
+ if (*P == '\0' || (isspace(*P) && InQuote == ' ')) {
+ if (!CurArg.empty()) {
+
+ if (CurArg[0] != '@') {
+ ArgVector.push_back(SaveStringInSet(SavedStrings, CurArg));
+ } else {
+ ExpandArgsFromBuf(CurArg.c_str(), ArgVector, SavedStrings);
+ }
+
+ CurArg = "";
+ }
+ if (*P == '\0')
+ break;
+ else
+ continue;
+ }
+
+ if (isspace(*P)) {
+ if (InQuote != ' ')
+ CurArg.push_back(*P);
+ continue;
+ }
+
+ if (*P == '"' || *P == '\'') {
+ if (InQuote == *P)
+ InQuote = ' ';
+ else if (InQuote == ' ')
+ InQuote = *P;
+ else
+ CurArg.push_back(*P);
+ continue;
+ }
+
+ if (*P == '\\') {
+ ++P;
+ if (*P != '\0')
+ CurArg.push_back(*P);
+ continue;
+ }
+ CurArg.push_back(*P);
+ }
+}
+
+static void ExpandArgv(int argc, const char **argv,
+ SmallVectorImpl<const char*> &ArgVector,
+ std::set<std::string> &SavedStrings) {
+ for (int i = 0; i < argc; ++i) {
+ const char *Arg = argv[i];
+ if (Arg[0] != '@') {
+ ArgVector.push_back(SaveStringInSet(SavedStrings, std::string(Arg)));
+ continue;
+ }
+
+ ExpandArgsFromBuf(Arg, ArgVector, SavedStrings);
+ }
+}
+
+static void ParseProgName(SmallVectorImpl<const char *> &ArgVector,
+ std::set<std::string> &SavedStrings,
+ Driver &TheDriver)
+{
+ // Try to infer frontend type and default target from the program name.
+
+ // suffixes[] contains the list of known driver suffixes.
+ // Suffixes are compared against the program name in order.
+ // If there is a match, the frontend type is updated as necessary (CPP/C++).
+ // If there is no match, a second round is done after stripping the last
+ // hyphen and everything following it. This allows using something like
+ // "clang++-2.9".
+
+ // If there is a match in either the first or second round,
+ // the function tries to identify a target as prefix. E.g.
+ // "x86_64-linux-clang" as interpreted as suffix "clang" with
+ // target prefix "x86_64-linux". If such a target prefix is found,
+ // is gets added via -target as implicit first argument.
+ static const struct {
+ const char *Suffix;
+ bool IsCXX;
+ bool IsCPP;
+ } suffixes [] = {
+ { "clang", false, false },
+ { "clang++", true, false },
+ { "clang-c++", true, false },
+ { "clang-cc", false, false },
+ { "clang-cpp", false, true },
+ { "clang-g++", true, false },
+ { "clang-gcc", false, false },
+ { "cc", false, false },
+ { "cpp", false, true },
+ { "++", true, false },
+ };
+ std::string ProgName(llvm::sys::path::stem(ArgVector[0]));
+ StringRef ProgNameRef(ProgName);
+ StringRef Prefix;
+
+ for (int Components = 2; Components; --Components) {
+ bool FoundMatch = false;
+ size_t i;
+
+ for (i = 0; i < sizeof(suffixes) / sizeof(suffixes[0]); ++i) {
+ if (ProgNameRef.endswith(suffixes[i].Suffix)) {
+ FoundMatch = true;
+ if (suffixes[i].IsCXX)
+ TheDriver.CCCIsCXX = true;
+ if (suffixes[i].IsCPP)
+ TheDriver.CCCIsCPP = true;
+ break;
+ }
+ }
+
+ if (FoundMatch) {
+ StringRef::size_type LastComponent = ProgNameRef.rfind('-',
+ ProgNameRef.size() - strlen(suffixes[i].Suffix));
+ if (LastComponent != StringRef::npos)
+ Prefix = ProgNameRef.slice(0, LastComponent);
+ break;
+ }
+
+ StringRef::size_type LastComponent = ProgNameRef.rfind('-');
+ if (LastComponent == StringRef::npos)
+ break;
+ ProgNameRef = ProgNameRef.slice(0, LastComponent);
+ }
+
+ if (Prefix.empty())
+ return;
+
+ std::string IgnoredError;
+ if (llvm::TargetRegistry::lookupTarget(Prefix, IgnoredError)) {
+ SmallVectorImpl<const char *>::iterator it = ArgVector.begin();
+ if (it != ArgVector.end())
+ ++it;
+ ArgVector.insert(it, SaveStringInSet(SavedStrings, Prefix));
+ ArgVector.insert(it,
+ SaveStringInSet(SavedStrings, std::string("-target")));
+ }
+}
+
+int main(int argc_, const char **argv_) {
+ llvm::sys::PrintStackTraceOnErrorSignal();
+ llvm::PrettyStackTraceProgram X(argc_, argv_);
+
+ std::set<std::string> SavedStrings;
+ SmallVector<const char*, 256> argv;
+
+ ExpandArgv(argc_, argv_, argv, SavedStrings);
+
+ // Handle -cc1 integrated tools.
+ if (argv.size() > 1 && StringRef(argv[1]).startswith("-cc1")) {
+ StringRef Tool = argv[1] + 4;
+
+ if (Tool == "")
+ return cc1_main(argv.data()+2, argv.data()+argv.size(), argv[0],
+ (void*) (intptr_t) GetExecutablePath);
+ if (Tool == "as")
+ return cc1as_main(argv.data()+2, argv.data()+argv.size(), argv[0],
+ (void*) (intptr_t) GetExecutablePath);
+
+ // Reject unknown tools.
+ llvm::errs() << "error: unknown integrated tool '" << Tool << "'\n";
+ return 1;
+ }
+
+ bool CanonicalPrefixes = true;
+ for (int i = 1, size = argv.size(); i < size; ++i) {
+ if (StringRef(argv[i]) == "-no-canonical-prefixes") {
+ CanonicalPrefixes = false;
+ break;
+ }
+ }
+
+ llvm::sys::Path Path = GetExecutablePath(argv[0], CanonicalPrefixes);
+
+ DiagnosticOptions DiagOpts;
+ {
+ // Note that ParseDiagnosticArgs() uses the cc1 option table.
+ OwningPtr<OptTable> CC1Opts(createCC1OptTable());
+ unsigned MissingArgIndex, MissingArgCount;
+ OwningPtr<InputArgList> Args(CC1Opts->ParseArgs(argv.begin()+1, argv.end(),
+ MissingArgIndex, MissingArgCount));
+ // We ignore MissingArgCount and the return value of ParseDiagnosticArgs.
+ // Any errors that would be diagnosed here will also be diagnosed later,
+ // when the DiagnosticsEngine actually exists.
+ (void) ParseDiagnosticArgs(DiagOpts, *Args);
+ }
+ // Now we can create the DiagnosticsEngine with a properly-filled-out
+ // DiagnosticOptions instance.
+ TextDiagnosticPrinter *DiagClient
+ = new TextDiagnosticPrinter(llvm::errs(), DiagOpts);
+ DiagClient->setPrefix(llvm::sys::path::stem(Path.str()));
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+
+ DiagnosticsEngine Diags(DiagID, DiagClient);
+ ProcessWarningOptions(Diags, DiagOpts);
+
+#ifdef CLANG_IS_PRODUCTION
+ const bool IsProduction = true;
+#else
+ const bool IsProduction = false;
+#endif
+ Driver TheDriver(Path.str(), llvm::sys::getDefaultTargetTriple(),
+ "a.out", IsProduction, Diags);
+
+ // Attempt to find the original path used to invoke the driver, to determine
+ // the installed path. We do this manually, because we want to support that
+ // path being a symlink.
+ {
+ SmallString<128> InstalledPath(argv[0]);
+
+ // Do a PATH lookup, if there are no directory components.
+ if (llvm::sys::path::filename(InstalledPath) == InstalledPath) {
+ llvm::sys::Path Tmp = llvm::sys::Program::FindProgramByName(
+ llvm::sys::path::filename(InstalledPath.str()));
+ if (!Tmp.empty())
+ InstalledPath = Tmp.str();
+ }
+ llvm::sys::fs::make_absolute(InstalledPath);
+ InstalledPath = llvm::sys::path::parent_path(InstalledPath);
+ bool exists;
+ if (!llvm::sys::fs::exists(InstalledPath.str(), exists) && exists)
+ TheDriver.setInstalledDir(InstalledPath);
+ }
+
+ llvm::InitializeAllTargets();
+ ParseProgName(argv, SavedStrings, TheDriver);
+
+ // Handle CC_PRINT_OPTIONS and CC_PRINT_OPTIONS_FILE.
+ TheDriver.CCPrintOptions = !!::getenv("CC_PRINT_OPTIONS");
+ if (TheDriver.CCPrintOptions)
+ TheDriver.CCPrintOptionsFilename = ::getenv("CC_PRINT_OPTIONS_FILE");
+
+ // Handle CC_PRINT_HEADERS and CC_PRINT_HEADERS_FILE.
+ TheDriver.CCPrintHeaders = !!::getenv("CC_PRINT_HEADERS");
+ if (TheDriver.CCPrintHeaders)
+ TheDriver.CCPrintHeadersFilename = ::getenv("CC_PRINT_HEADERS_FILE");
+
+ // Handle CC_LOG_DIAGNOSTICS and CC_LOG_DIAGNOSTICS_FILE.
+ TheDriver.CCLogDiagnostics = !!::getenv("CC_LOG_DIAGNOSTICS");
+ if (TheDriver.CCLogDiagnostics)
+ TheDriver.CCLogDiagnosticsFilename = ::getenv("CC_LOG_DIAGNOSTICS_FILE");
+
+ // Handle QA_OVERRIDE_GCC3_OPTIONS and CCC_ADD_ARGS, used for editing a
+ // command line behind the scenes.
+ if (const char *OverrideStr = ::getenv("QA_OVERRIDE_GCC3_OPTIONS")) {
+ // FIXME: Driver shouldn't take extra initial argument.
+ ApplyQAOverride(argv, OverrideStr, SavedStrings);
+ } else if (const char *Cur = ::getenv("CCC_ADD_ARGS")) {
+ // FIXME: Driver shouldn't take extra initial argument.
+ std::vector<const char*> ExtraArgs;
+
+ for (;;) {
+ const char *Next = strchr(Cur, ',');
+
+ if (Next) {
+ ExtraArgs.push_back(SaveStringInSet(SavedStrings,
+ std::string(Cur, Next)));
+ Cur = Next + 1;
+ } else {
+ if (*Cur != '\0')
+ ExtraArgs.push_back(SaveStringInSet(SavedStrings, Cur));
+ break;
+ }
+ }
+
+ argv.insert(&argv[1], ExtraArgs.begin(), ExtraArgs.end());
+ }
+
+ OwningPtr<Compilation> C(TheDriver.BuildCompilation(argv));
+ int Res = 0;
+ const Command *FailingCommand = 0;
+ if (C.get())
+ Res = TheDriver.ExecuteCompilation(*C, FailingCommand);
+
+ // If result status is < 0, then the driver command signalled an error.
+ // In this case, generate additional diagnostic information if possible.
+ if (Res < 0)
+ TheDriver.generateCompilationDiagnostics(*C, FailingCommand);
+
+ // If any timers were active but haven't been destroyed yet, print their
+ // results now. This happens in -disable-free mode.
+ llvm::TimerGroup::printAll(llvm::errs());
+
+ llvm::llvm_shutdown();
+
+ return Res;
+}