| author | |
| committer | |
| log | a77a17e2c2dc8c2add8a3ed47708c90799425c70 |
| tree | a1fcec35c29f5324b215ba477bc53ce1e3a3ed00 |
| parent | 00d8f4a1bb634ec5b0569e6ff6c2679ade2bd6b0 |
| signature | Commit is signed but in an unrecognized format. |
closes #4906 files changed, 1360 insertions(+), 0 deletions(-)
CMakeLists.txt+3| ... | ... | @@ -431,6 +431,9 @@ set(BLAKE_SOURCES |
| 431 | 431 | set(ZIG_CPP_SOURCES |
| 432 | 432 | "${CMAKE_SOURCE_DIR}/src/zig_llvm.cpp" |
| 433 | 433 | "${CMAKE_SOURCE_DIR}/src/zig_clang.cpp" |
| 434 | "${CMAKE_SOURCE_DIR}/src/zig_clang_driver.cpp" | |
| 435 | "${CMAKE_SOURCE_DIR}/src/zig_clang_cc1_main.cpp" | |
| 436 | "${CMAKE_SOURCE_DIR}/src/zig_clang_cc1as_main.cpp" | |
| 434 | 437 | "${CMAKE_SOURCE_DIR}/src/windows_sdk.cpp" |
| 435 | 438 | ) |
| 436 | 439 |
cmake/Findclang.cmake+22| ... | ... | @@ -11,17 +11,28 @@ if(MSVC) |
| 11 | 11 | find_package(CLANG REQUIRED CONFIG) |
| 12 | 12 | |
| 13 | 13 | set(CLANG_LIBRARIES |
| 14 | clangFrontendTool | |
| 15 | clangCodeGen | |
| 14 | 16 | clangFrontend |
| 15 | 17 | clangDriver |
| 16 | 18 | clangSerialization |
| 17 | 19 | clangSema |
| 20 | clangStaticAnalyzerFrontend | |
| 21 | clangStaticAnalyzerCheckers | |
| 22 | clangStaticAnalyzerCore | |
| 18 | 23 | clangAnalysis |
| 24 | clangASTMatchers | |
| 19 | 25 | clangAST |
| 20 | 26 | clangParse |
| 21 | 27 | clangSema |
| 22 | 28 | clangBasic |
| 23 | 29 | clangEdit |
| 24 | 30 | clangLex |
| 31 | clangARCMigrate | |
| 32 | clangRewriteFrontend | |
| 33 | clangRewrite | |
| 34 | clangCrossTU | |
| 35 | clangIndex | |
| 25 | 36 | ) |
| 26 | 37 | |
| 27 | 38 | else() |
| ... | ... | @@ -50,17 +61,28 @@ else() |
| 50 | 61 | endif() |
| 51 | 62 | endmacro(FIND_AND_ADD_CLANG_LIB) |
| 52 | 63 | |
| 64 | FIND_AND_ADD_CLANG_LIB(clangFrontendTool) | |
| 65 | FIND_AND_ADD_CLANG_LIB(clangCodeGen) | |
| 53 | 66 | FIND_AND_ADD_CLANG_LIB(clangFrontend) |
| 54 | 67 | FIND_AND_ADD_CLANG_LIB(clangDriver) |
| 55 | 68 | FIND_AND_ADD_CLANG_LIB(clangSerialization) |
| 56 | 69 | FIND_AND_ADD_CLANG_LIB(clangSema) |
| 70 | FIND_AND_ADD_CLANG_LIB(clangStaticAnalyzerFrontend) | |
| 71 | FIND_AND_ADD_CLANG_LIB(clangStaticAnalyzerCheckers) | |
| 72 | FIND_AND_ADD_CLANG_LIB(clangStaticAnalyzerCore) | |
| 57 | 73 | FIND_AND_ADD_CLANG_LIB(clangAnalysis) |
| 74 | FIND_AND_ADD_CLANG_LIB(clangASTMatchers) | |
| 58 | 75 | FIND_AND_ADD_CLANG_LIB(clangAST) |
| 59 | 76 | FIND_AND_ADD_CLANG_LIB(clangParse) |
| 60 | 77 | FIND_AND_ADD_CLANG_LIB(clangSema) |
| 61 | 78 | FIND_AND_ADD_CLANG_LIB(clangBasic) |
| 62 | 79 | FIND_AND_ADD_CLANG_LIB(clangEdit) |
| 63 | 80 | FIND_AND_ADD_CLANG_LIB(clangLex) |
| 81 | FIND_AND_ADD_CLANG_LIB(clangARCMigrate) | |
| 82 | FIND_AND_ADD_CLANG_LIB(clangRewriteFrontend) | |
| 83 | FIND_AND_ADD_CLANG_LIB(clangRewrite) | |
| 84 | FIND_AND_ADD_CLANG_LIB(clangCrossTU) | |
| 85 | FIND_AND_ADD_CLANG_LIB(clangIndex) | |
| 64 | 86 | endif() |
| 65 | 87 | |
| 66 | 88 | include(FindPackageHandleStandardArgs) |
src/main.cpp+13| ... | ... | @@ -32,6 +32,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) { |
| 32 | 32 | " build-lib [source] create library from source or object files\n" |
| 33 | 33 | " build-obj [source] create object from source or assembly\n" |
| 34 | 34 | " builtin show the source code of that @import(\"builtin\")\n" |
| 35 | " cc C compiler\n" | |
| 35 | 36 | " fmt parse files and render in canonical zig format\n" |
| 36 | 37 | " help show this usage information\n" |
| 37 | 38 | " id print the base64-encoded compiler id\n" |
| ... | ... | @@ -240,6 +241,8 @@ static bool get_cache_opt(CacheOpt opt, bool default_value) { |
| 240 | 241 | zig_unreachable(); |
| 241 | 242 | } |
| 242 | 243 | |
| 244 | extern "C" int ZigClang_main(int argc, char **argv); | |
| 245 | ||
| 243 | 246 | int main(int argc, char **argv) { |
| 244 | 247 | char *arg0 = argv[0]; |
| 245 | 248 | Error err; |
| ... | ... | @@ -257,6 +260,16 @@ int main(int argc, char **argv) { |
| 257 | 260 | return 0; |
| 258 | 261 | } |
| 259 | 262 | |
| 263 | if (argc >= 2 && (strcmp(argv[1], "cc") == 0)) { | |
| 264 | return ZigClang_main(argc - 1, argv + 1); | |
| 265 | } | |
| 266 | if (argc >= 2 && strcmp(argv[1], "-cc1") == 0) { | |
| 267 | return ZigClang_main(argc, argv); | |
| 268 | } | |
| 269 | if (argc >= 2 && strcmp(argv[1], "-cc1as") == 0) { | |
| 270 | return ZigClang_main(argc, argv); | |
| 271 | } | |
| 272 | ||
| 260 | 273 | // Must be before all os.hpp function calls. |
| 261 | 274 | os_init(); |
| 262 | 275 |
src/zig_clang_cc1_main.cpp created+237| ... | ... | @@ -0,0 +1,237 @@ |
| 1 | //===-- cc1_main.cpp - Clang CC1 Compiler Frontend ------------------------===// | |
| 2 | // | |
| 3 | // The LLVM Compiler Infrastructure | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 7 | // | |
| 8 | //===----------------------------------------------------------------------===// | |
| 9 | // | |
| 10 | // This is the entry point to the clang -cc1 functionality, which implements the | |
| 11 | // core compiler functionality along with a number of additional tools for | |
| 12 | // demonstration and testing purposes. | |
| 13 | // | |
| 14 | //===----------------------------------------------------------------------===// | |
| 15 | ||
| 16 | #include "llvm/Option/Arg.h" | |
| 17 | #include "clang/CodeGen/ObjectFilePCHContainerOperations.h" | |
| 18 | #include "clang/Config/config.h" | |
| 19 | #include "clang/Basic/Stack.h" | |
| 20 | #include "clang/Driver/DriverDiagnostic.h" | |
| 21 | #include "clang/Driver/Options.h" | |
| 22 | #include "clang/Frontend/CompilerInstance.h" | |
| 23 | #include "clang/Frontend/CompilerInvocation.h" | |
| 24 | #include "clang/Frontend/FrontendDiagnostic.h" | |
| 25 | #include "clang/Frontend/TextDiagnosticBuffer.h" | |
| 26 | #include "clang/Frontend/TextDiagnosticPrinter.h" | |
| 27 | #include "clang/Frontend/Utils.h" | |
| 28 | #include "clang/FrontendTool/Utils.h" | |
| 29 | #include "llvm/ADT/Statistic.h" | |
| 30 | #include "llvm/Config/llvm-config.h" | |
| 31 | #include "llvm/LinkAllPasses.h" | |
| 32 | #include "llvm/Option/ArgList.h" | |
| 33 | #include "llvm/Option/OptTable.h" | |
| 34 | #include "llvm/Support/Compiler.h" | |
| 35 | #include "llvm/Support/ErrorHandling.h" | |
| 36 | #include "llvm/Support/ManagedStatic.h" | |
| 37 | #include "llvm/Support/Signals.h" | |
| 38 | #include "llvm/Support/TargetSelect.h" | |
| 39 | #include "llvm/Support/Timer.h" | |
| 40 | #include "llvm/Support/raw_ostream.h" | |
| 41 | #include <cstdio> | |
| 42 | ||
| 43 | #ifdef CLANG_HAVE_RLIMITS | |
| 44 | #include <sys/resource.h> | |
| 45 | #endif | |
| 46 | ||
| 47 | using namespace clang; | |
| 48 | using namespace llvm::opt; | |
| 49 | ||
| 50 | //===----------------------------------------------------------------------===// | |
| 51 | // Main driver | |
| 52 | //===----------------------------------------------------------------------===// | |
| 53 | ||
| 54 | static void LLVMErrorHandler(void *UserData, const std::string &Message, | |
| 55 | bool GenCrashDiag) { | |
| 56 | DiagnosticsEngine &Diags = *static_cast<DiagnosticsEngine*>(UserData); | |
| 57 | ||
| 58 | Diags.Report(diag::err_fe_error_backend) << Message; | |
| 59 | ||
| 60 | // Run the interrupt handlers to make sure any special cleanups get done, in | |
| 61 | // particular that we remove files registered with RemoveFileOnSignal. | |
| 62 | llvm::sys::RunInterruptHandlers(); | |
| 63 | ||
| 64 | // We cannot recover from llvm errors. When reporting a fatal error, exit | |
| 65 | // with status 70 to generate crash diagnostics. For BSD systems this is | |
| 66 | // defined as an internal software error. Otherwise, exit with status 1. | |
| 67 | exit(GenCrashDiag ? 70 : 1); | |
| 68 | } | |
| 69 | ||
| 70 | #ifdef LINK_POLLY_INTO_TOOLS | |
| 71 | namespace polly { | |
| 72 | void initializePollyPasses(llvm::PassRegistry &Registry); | |
| 73 | } | |
| 74 | #endif | |
| 75 | ||
| 76 | #ifdef CLANG_HAVE_RLIMITS | |
| 77 | #if defined(__linux__) && defined(__PIE__) | |
| 78 | static size_t getCurrentStackAllocation() { | |
| 79 | // If we can't compute the current stack usage, allow for 512K of command | |
| 80 | // line arguments and environment. | |
| 81 | size_t Usage = 512 * 1024; | |
| 82 | if (FILE *StatFile = fopen("/proc/self/stat", "r")) { | |
| 83 | // We assume that the stack extends from its current address to the end of | |
| 84 | // the environment space. In reality, there is another string literal (the | |
| 85 | // program name) after the environment, but this is close enough (we only | |
| 86 | // need to be within 100K or so). | |
| 87 | unsigned long StackPtr, EnvEnd; | |
| 88 | // Disable silly GCC -Wformat warning that complains about length | |
| 89 | // modifiers on ignored format specifiers. We want to retain these | |
| 90 | // for documentation purposes even though they have no effect. | |
| 91 | #if defined(__GNUC__) && !defined(__clang__) | |
| 92 | #pragma GCC diagnostic push | |
| 93 | #pragma GCC diagnostic ignored "-Wformat" | |
| 94 | #endif | |
| 95 | if (fscanf(StatFile, | |
| 96 | "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*lu %*lu %*lu %*lu %*lu " | |
| 97 | "%*lu %*ld %*ld %*ld %*ld %*ld %*ld %*llu %*lu %*ld %*lu %*lu " | |
| 98 | "%*lu %*lu %lu %*lu %*lu %*lu %*lu %*lu %*llu %*lu %*lu %*d %*d " | |
| 99 | "%*u %*u %*llu %*lu %*ld %*lu %*lu %*lu %*lu %*lu %*lu %lu %*d", | |
| 100 | &StackPtr, &EnvEnd) == 2) { | |
| 101 | #if defined(__GNUC__) && !defined(__clang__) | |
| 102 | #pragma GCC diagnostic pop | |
| 103 | #endif | |
| 104 | Usage = StackPtr < EnvEnd ? EnvEnd - StackPtr : StackPtr - EnvEnd; | |
| 105 | } | |
| 106 | fclose(StatFile); | |
| 107 | } | |
| 108 | return Usage; | |
| 109 | } | |
| 110 | ||
| 111 | #include <alloca.h> | |
| 112 | ||
| 113 | LLVM_ATTRIBUTE_NOINLINE | |
| 114 | static void ensureStackAddressSpace() { | |
| 115 | // Linux kernels prior to 4.1 will sometimes locate the heap of a PIE binary | |
| 116 | // relatively close to the stack (they are only guaranteed to be 128MiB | |
| 117 | // apart). This results in crashes if we happen to heap-allocate more than | |
| 118 | // 128MiB before we reach our stack high-water mark. | |
| 119 | // | |
| 120 | // To avoid these crashes, ensure that we have sufficient virtual memory | |
| 121 | // pages allocated before we start running. | |
| 122 | size_t Curr = getCurrentStackAllocation(); | |
| 123 | const int kTargetStack = DesiredStackSize - 256 * 1024; | |
| 124 | if (Curr < kTargetStack) { | |
| 125 | volatile char *volatile Alloc = | |
| 126 | static_cast<volatile char *>(alloca(kTargetStack - Curr)); | |
| 127 | Alloc[0] = 0; | |
| 128 | Alloc[kTargetStack - Curr - 1] = 0; | |
| 129 | } | |
| 130 | } | |
| 131 | #else | |
| 132 | static void ensureStackAddressSpace() {} | |
| 133 | #endif | |
| 134 | ||
| 135 | /// Attempt to ensure that we have at least 8MiB of usable stack space. | |
| 136 | static void ensureSufficientStack() { | |
| 137 | struct rlimit rlim; | |
| 138 | if (getrlimit(RLIMIT_STACK, &rlim) != 0) | |
| 139 | return; | |
| 140 | ||
| 141 | // Increase the soft stack limit to our desired level, if necessary and | |
| 142 | // possible. | |
| 143 | if (rlim.rlim_cur != RLIM_INFINITY && | |
| 144 | rlim.rlim_cur < rlim_t(DesiredStackSize)) { | |
| 145 | // Try to allocate sufficient stack. | |
| 146 | if (rlim.rlim_max == RLIM_INFINITY || | |
| 147 | rlim.rlim_max >= rlim_t(DesiredStackSize)) | |
| 148 | rlim.rlim_cur = DesiredStackSize; | |
| 149 | else if (rlim.rlim_cur == rlim.rlim_max) | |
| 150 | return; | |
| 151 | else | |
| 152 | rlim.rlim_cur = rlim.rlim_max; | |
| 153 | ||
| 154 | if (setrlimit(RLIMIT_STACK, &rlim) != 0 || | |
| 155 | rlim.rlim_cur != DesiredStackSize) | |
| 156 | return; | |
| 157 | } | |
| 158 | ||
| 159 | // We should now have a stack of size at least DesiredStackSize. Ensure | |
| 160 | // that we can actually use that much, if necessary. | |
| 161 | ensureStackAddressSpace(); | |
| 162 | } | |
| 163 | #else | |
| 164 | static void ensureSufficientStack() {} | |
| 165 | #endif | |
| 166 | ||
| 167 | int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) { | |
| 168 | ensureSufficientStack(); | |
| 169 | ||
| 170 | std::unique_ptr<CompilerInstance> Clang(new CompilerInstance()); | |
| 171 | IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); | |
| 172 | ||
| 173 | // Register the support for object-file-wrapped Clang modules. | |
| 174 | auto PCHOps = Clang->getPCHContainerOperations(); | |
| 175 | PCHOps->registerWriter(llvm::make_unique<ObjectFilePCHContainerWriter>()); | |
| 176 | PCHOps->registerReader(llvm::make_unique<ObjectFilePCHContainerReader>()); | |
| 177 | ||
| 178 | // Initialize targets first, so that --version shows registered targets. | |
| 179 | llvm::InitializeAllTargets(); | |
| 180 | llvm::InitializeAllTargetMCs(); | |
| 181 | llvm::InitializeAllAsmPrinters(); | |
| 182 | llvm::InitializeAllAsmParsers(); | |
| 183 | ||
| 184 | #ifdef LINK_POLLY_INTO_TOOLS | |
| 185 | llvm::PassRegistry &Registry = *llvm::PassRegistry::getPassRegistry(); | |
| 186 | polly::initializePollyPasses(Registry); | |
| 187 | #endif | |
| 188 | ||
| 189 | // Buffer diagnostics from argument parsing so that we can output them using a | |
| 190 | // well formed diagnostic object. | |
| 191 | IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); | |
| 192 | TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer; | |
| 193 | DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagsBuffer); | |
| 194 | bool Success = CompilerInvocation::CreateFromArgs( | |
| 195 | Clang->getInvocation(), Argv.begin(), Argv.end(), Diags); | |
| 196 | ||
| 197 | // Infer the builtin include path if unspecified. | |
| 198 | if (Clang->getHeaderSearchOpts().UseBuiltinIncludes && | |
| 199 | Clang->getHeaderSearchOpts().ResourceDir.empty()) | |
| 200 | Clang->getHeaderSearchOpts().ResourceDir = | |
| 201 | CompilerInvocation::GetResourcesPath(Argv0, MainAddr); | |
| 202 | ||
| 203 | // Create the actual diagnostics engine. | |
| 204 | Clang->createDiagnostics(); | |
| 205 | if (!Clang->hasDiagnostics()) | |
| 206 | return 1; | |
| 207 | ||
| 208 | // Set an error handler, so that any LLVM backend diagnostics go through our | |
| 209 | // error handler. | |
| 210 | llvm::install_fatal_error_handler(LLVMErrorHandler, | |
| 211 | static_cast<void*>(&Clang->getDiagnostics())); | |
| 212 | ||
| 213 | DiagsBuffer->FlushDiagnostics(Clang->getDiagnostics()); | |
| 214 | if (!Success) | |
| 215 | return 1; | |
| 216 | ||
| 217 | // Execute the frontend actions. | |
| 218 | Success = ExecuteCompilerInvocation(Clang.get()); | |
| 219 | ||
| 220 | // If any timers were active but haven't been destroyed yet, print their | |
| 221 | // results now. This happens in -disable-free mode. | |
| 222 | llvm::TimerGroup::printAll(llvm::errs()); | |
| 223 | ||
| 224 | // Our error handler depends on the Diagnostics object, which we're | |
| 225 | // potentially about to delete. Uninstall the handler now so that any | |
| 226 | // later errors use the default handling behavior instead. | |
| 227 | llvm::remove_fatal_error_handler(); | |
| 228 | ||
| 229 | // When running with -disable-free, don't do any destruction or shutdown. | |
| 230 | if (Clang->getFrontendOpts().DisableFree) { | |
| 231 | BuryPointer(std::move(Clang)); | |
| 232 | return !Success; | |
| 233 | } | |
| 234 | ||
| 235 | return !Success; | |
| 236 | } | |
| 237 |
src/zig_clang_cc1as_main.cpp created+573| ... | ... | @@ -0,0 +1,573 @@ |
| 1 | //===-- cc1as_main.cpp - Clang Assembler ---------------------------------===// | |
| 2 | // | |
| 3 | // The LLVM Compiler Infrastructure | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 7 | // | |
| 8 | //===----------------------------------------------------------------------===// | |
| 9 | // | |
| 10 | // This is the entry point to the clang -cc1as functionality, which implements | |
| 11 | // the direct interface to the LLVM MC based assembler. | |
| 12 | // | |
| 13 | //===----------------------------------------------------------------------===// | |
| 14 | ||
| 15 | #include "clang/Basic/Diagnostic.h" | |
| 16 | #include "clang/Basic/DiagnosticOptions.h" | |
| 17 | #include "clang/Driver/DriverDiagnostic.h" | |
| 18 | #include "clang/Driver/Options.h" | |
| 19 | #include "clang/Frontend/FrontendDiagnostic.h" | |
| 20 | #include "clang/Frontend/TextDiagnosticPrinter.h" | |
| 21 | #include "clang/Frontend/Utils.h" | |
| 22 | #include "llvm/ADT/STLExtras.h" | |
| 23 | #include "llvm/ADT/StringSwitch.h" | |
| 24 | #include "llvm/ADT/Triple.h" | |
| 25 | #include "llvm/IR/DataLayout.h" | |
| 26 | #include "llvm/MC/MCAsmBackend.h" | |
| 27 | #include "llvm/MC/MCAsmInfo.h" | |
| 28 | #include "llvm/MC/MCCodeEmitter.h" | |
| 29 | #include "llvm/MC/MCContext.h" | |
| 30 | #include "llvm/MC/MCInstrInfo.h" | |
| 31 | #include "llvm/MC/MCObjectFileInfo.h" | |
| 32 | #include "llvm/MC/MCObjectWriter.h" | |
| 33 | #include "llvm/MC/MCParser/MCAsmParser.h" | |
| 34 | #include "llvm/MC/MCParser/MCTargetAsmParser.h" | |
| 35 | #include "llvm/MC/MCRegisterInfo.h" | |
| 36 | #include "llvm/MC/MCStreamer.h" | |
| 37 | #include "llvm/MC/MCSubtargetInfo.h" | |
| 38 | #include "llvm/MC/MCTargetOptions.h" | |
| 39 | #include "llvm/Option/Arg.h" | |
| 40 | #include "llvm/Option/ArgList.h" | |
| 41 | #include "llvm/Option/OptTable.h" | |
| 42 | #include "llvm/Support/CommandLine.h" | |
| 43 | #include "llvm/Support/ErrorHandling.h" | |
| 44 | #include "llvm/Support/FileSystem.h" | |
| 45 | #include "llvm/Support/FormattedStream.h" | |
| 46 | #include "llvm/Support/Host.h" | |
| 47 | #include "llvm/Support/MemoryBuffer.h" | |
| 48 | #include "llvm/Support/Path.h" | |
| 49 | #include "llvm/Support/Signals.h" | |
| 50 | #include "llvm/Support/SourceMgr.h" | |
| 51 | #include "llvm/Support/TargetRegistry.h" | |
| 52 | #include "llvm/Support/TargetSelect.h" | |
| 53 | #include "llvm/Support/Timer.h" | |
| 54 | #include "llvm/Support/raw_ostream.h" | |
| 55 | #include <memory> | |
| 56 | #include <system_error> | |
| 57 | using namespace clang; | |
| 58 | using namespace clang::driver; | |
| 59 | using namespace clang::driver::options; | |
| 60 | using namespace llvm; | |
| 61 | using namespace llvm::opt; | |
| 62 | ||
| 63 | namespace { | |
| 64 | ||
| 65 | /// Helper class for representing a single invocation of the assembler. | |
| 66 | struct AssemblerInvocation { | |
| 67 | /// @name Target Options | |
| 68 | /// @{ | |
| 69 | ||
| 70 | /// The name of the target triple to assemble for. | |
| 71 | std::string Triple; | |
| 72 | ||
| 73 | /// If given, the name of the target CPU to determine which instructions | |
| 74 | /// are legal. | |
| 75 | std::string CPU; | |
| 76 | ||
| 77 | /// The list of target specific features to enable or disable -- this should | |
| 78 | /// be a list of strings starting with '+' or '-'. | |
| 79 | std::vector<std::string> Features; | |
| 80 | ||
| 81 | /// The list of symbol definitions. | |
| 82 | std::vector<std::string> SymbolDefs; | |
| 83 | ||
| 84 | /// @} | |
| 85 | /// @name Language Options | |
| 86 | /// @{ | |
| 87 | ||
| 88 | std::vector<std::string> IncludePaths; | |
| 89 | unsigned NoInitialTextSection : 1; | |
| 90 | unsigned SaveTemporaryLabels : 1; | |
| 91 | unsigned GenDwarfForAssembly : 1; | |
| 92 | unsigned RelaxELFRelocations : 1; | |
| 93 | unsigned DwarfVersion; | |
| 94 | std::string DwarfDebugFlags; | |
| 95 | std::string DwarfDebugProducer; | |
| 96 | std::string DebugCompilationDir; | |
| 97 | std::map<const std::string, const std::string> DebugPrefixMap; | |
| 98 | llvm::DebugCompressionType CompressDebugSections = | |
| 99 | llvm::DebugCompressionType::None; | |
| 100 | std::string MainFileName; | |
| 101 | std::string SplitDwarfFile; | |
| 102 | ||
| 103 | /// @} | |
| 104 | /// @name Frontend Options | |
| 105 | /// @{ | |
| 106 | ||
| 107 | std::string InputFile; | |
| 108 | std::vector<std::string> LLVMArgs; | |
| 109 | std::string OutputPath; | |
| 110 | enum FileType { | |
| 111 | FT_Asm, ///< Assembly (.s) output, transliterate mode. | |
| 112 | FT_Null, ///< No output, for timing purposes. | |
| 113 | FT_Obj ///< Object file output. | |
| 114 | }; | |
| 115 | FileType OutputType; | |
| 116 | unsigned ShowHelp : 1; | |
| 117 | unsigned ShowVersion : 1; | |
| 118 | ||
| 119 | /// @} | |
| 120 | /// @name Transliterate Options | |
| 121 | /// @{ | |
| 122 | ||
| 123 | unsigned OutputAsmVariant; | |
| 124 | unsigned ShowEncoding : 1; | |
| 125 | unsigned ShowInst : 1; | |
| 126 | ||
| 127 | /// @} | |
| 128 | /// @name Assembler Options | |
| 129 | /// @{ | |
| 130 | ||
| 131 | unsigned RelaxAll : 1; | |
| 132 | unsigned NoExecStack : 1; | |
| 133 | unsigned FatalWarnings : 1; | |
| 134 | unsigned IncrementalLinkerCompatible : 1; | |
| 135 | ||
| 136 | /// The name of the relocation model to use. | |
| 137 | std::string RelocationModel; | |
| 138 | ||
| 139 | /// @} | |
| 140 | ||
| 141 | public: | |
| 142 | AssemblerInvocation() { | |
| 143 | Triple = ""; | |
| 144 | NoInitialTextSection = 0; | |
| 145 | InputFile = "-"; | |
| 146 | OutputPath = "-"; | |
| 147 | OutputType = FT_Asm; | |
| 148 | OutputAsmVariant = 0; | |
| 149 | ShowInst = 0; | |
| 150 | ShowEncoding = 0; | |
| 151 | RelaxAll = 0; | |
| 152 | NoExecStack = 0; | |
| 153 | FatalWarnings = 0; | |
| 154 | IncrementalLinkerCompatible = 0; | |
| 155 | DwarfVersion = 0; | |
| 156 | } | |
| 157 | ||
| 158 | static bool CreateFromArgs(AssemblerInvocation &Res, | |
| 159 | ArrayRef<const char *> Argv, | |
| 160 | DiagnosticsEngine &Diags); | |
| 161 | }; | |
| 162 | ||
| 163 | } | |
| 164 | ||
| 165 | bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts, | |
| 166 | ArrayRef<const char *> Argv, | |
| 167 | DiagnosticsEngine &Diags) { | |
| 168 | bool Success = true; | |
| 169 | ||
| 170 | // Parse the arguments. | |
| 171 | std::unique_ptr<OptTable> OptTbl(createDriverOptTable()); | |
| 172 | ||
| 173 | const unsigned IncludedFlagsBitmask = options::CC1AsOption; | |
| 174 | unsigned MissingArgIndex, MissingArgCount; | |
| 175 | InputArgList Args = OptTbl->ParseArgs(Argv, MissingArgIndex, MissingArgCount, | |
| 176 | IncludedFlagsBitmask); | |
| 177 | ||
| 178 | // Check for missing argument error. | |
| 179 | if (MissingArgCount) { | |
| 180 | Diags.Report(diag::err_drv_missing_argument) | |
| 181 | << Args.getArgString(MissingArgIndex) << MissingArgCount; | |
| 182 | Success = false; | |
| 183 | } | |
| 184 | ||
| 185 | // Issue errors on unknown arguments. | |
| 186 | for (const Arg *A : Args.filtered(OPT_UNKNOWN)) { | |
| 187 | auto ArgString = A->getAsString(Args); | |
| 188 | std::string Nearest; | |
| 189 | if (OptTbl->findNearest(ArgString, Nearest, IncludedFlagsBitmask) > 1) | |
| 190 | Diags.Report(diag::err_drv_unknown_argument) << ArgString; | |
| 191 | else | |
| 192 | Diags.Report(diag::err_drv_unknown_argument_with_suggestion) | |
| 193 | << ArgString << Nearest; | |
| 194 | Success = false; | |
| 195 | } | |
| 196 | ||
| 197 | // Construct the invocation. | |
| 198 | ||
| 199 | // Target Options | |
| 200 | Opts.Triple = llvm::Triple::normalize(Args.getLastArgValue(OPT_triple)); | |
| 201 | Opts.CPU = Args.getLastArgValue(OPT_target_cpu); | |
| 202 | Opts.Features = Args.getAllArgValues(OPT_target_feature); | |
| 203 | ||
| 204 | // Use the default target triple if unspecified. | |
| 205 | if (Opts.Triple.empty()) | |
| 206 | Opts.Triple = llvm::sys::getDefaultTargetTriple(); | |
| 207 | ||
| 208 | // Language Options | |
| 209 | Opts.IncludePaths = Args.getAllArgValues(OPT_I); | |
| 210 | Opts.NoInitialTextSection = Args.hasArg(OPT_n); | |
| 211 | Opts.SaveTemporaryLabels = Args.hasArg(OPT_msave_temp_labels); | |
| 212 | // Any DebugInfoKind implies GenDwarfForAssembly. | |
| 213 | Opts.GenDwarfForAssembly = Args.hasArg(OPT_debug_info_kind_EQ); | |
| 214 | ||
| 215 | if (const Arg *A = Args.getLastArg(OPT_compress_debug_sections, | |
| 216 | OPT_compress_debug_sections_EQ)) { | |
| 217 | if (A->getOption().getID() == OPT_compress_debug_sections) { | |
| 218 | // TODO: be more clever about the compression type auto-detection | |
| 219 | Opts.CompressDebugSections = llvm::DebugCompressionType::GNU; | |
| 220 | } else { | |
| 221 | Opts.CompressDebugSections = | |
| 222 | llvm::StringSwitch<llvm::DebugCompressionType>(A->getValue()) | |
| 223 | .Case("none", llvm::DebugCompressionType::None) | |
| 224 | .Case("zlib", llvm::DebugCompressionType::Z) | |
| 225 | .Case("zlib-gnu", llvm::DebugCompressionType::GNU) | |
| 226 | .Default(llvm::DebugCompressionType::None); | |
| 227 | } | |
| 228 | } | |
| 229 | ||
| 230 | Opts.RelaxELFRelocations = Args.hasArg(OPT_mrelax_relocations); | |
| 231 | Opts.DwarfVersion = getLastArgIntValue(Args, OPT_dwarf_version_EQ, 2, Diags); | |
| 232 | Opts.DwarfDebugFlags = Args.getLastArgValue(OPT_dwarf_debug_flags); | |
| 233 | Opts.DwarfDebugProducer = Args.getLastArgValue(OPT_dwarf_debug_producer); | |
| 234 | Opts.DebugCompilationDir = Args.getLastArgValue(OPT_fdebug_compilation_dir); | |
| 235 | Opts.MainFileName = Args.getLastArgValue(OPT_main_file_name); | |
| 236 | ||
| 237 | for (const auto &Arg : Args.getAllArgValues(OPT_fdebug_prefix_map_EQ)) | |
| 238 | Opts.DebugPrefixMap.insert(StringRef(Arg).split('=')); | |
| 239 | ||
| 240 | // Frontend Options | |
| 241 | if (Args.hasArg(OPT_INPUT)) { | |
| 242 | bool First = true; | |
| 243 | for (const Arg *A : Args.filtered(OPT_INPUT)) { | |
| 244 | if (First) { | |
| 245 | Opts.InputFile = A->getValue(); | |
| 246 | First = false; | |
| 247 | } else { | |
| 248 | Diags.Report(diag::err_drv_unknown_argument) << A->getAsString(Args); | |
| 249 | Success = false; | |
| 250 | } | |
| 251 | } | |
| 252 | } | |
| 253 | Opts.LLVMArgs = Args.getAllArgValues(OPT_mllvm); | |
| 254 | Opts.OutputPath = Args.getLastArgValue(OPT_o); | |
| 255 | Opts.SplitDwarfFile = Args.getLastArgValue(OPT_split_dwarf_file); | |
| 256 | if (Arg *A = Args.getLastArg(OPT_filetype)) { | |
| 257 | StringRef Name = A->getValue(); | |
| 258 | unsigned OutputType = StringSwitch<unsigned>(Name) | |
| 259 | .Case("asm", FT_Asm) | |
| 260 | .Case("null", FT_Null) | |
| 261 | .Case("obj", FT_Obj) | |
| 262 | .Default(~0U); | |
| 263 | if (OutputType == ~0U) { | |
| 264 | Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name; | |
| 265 | Success = false; | |
| 266 | } else | |
| 267 | Opts.OutputType = FileType(OutputType); | |
| 268 | } | |
| 269 | Opts.ShowHelp = Args.hasArg(OPT_help); | |
| 270 | Opts.ShowVersion = Args.hasArg(OPT_version); | |
| 271 | ||
| 272 | // Transliterate Options | |
| 273 | Opts.OutputAsmVariant = | |
| 274 | getLastArgIntValue(Args, OPT_output_asm_variant, 0, Diags); | |
| 275 | Opts.ShowEncoding = Args.hasArg(OPT_show_encoding); | |
| 276 | Opts.ShowInst = Args.hasArg(OPT_show_inst); | |
| 277 | ||
| 278 | // Assemble Options | |
| 279 | Opts.RelaxAll = Args.hasArg(OPT_mrelax_all); | |
| 280 | Opts.NoExecStack = Args.hasArg(OPT_mno_exec_stack); | |
| 281 | Opts.FatalWarnings = Args.hasArg(OPT_massembler_fatal_warnings); | |
| 282 | Opts.RelocationModel = Args.getLastArgValue(OPT_mrelocation_model, "pic"); | |
| 283 | Opts.IncrementalLinkerCompatible = | |
| 284 | Args.hasArg(OPT_mincremental_linker_compatible); | |
| 285 | Opts.SymbolDefs = Args.getAllArgValues(OPT_defsym); | |
| 286 | ||
| 287 | return Success; | |
| 288 | } | |
| 289 | ||
| 290 | static std::unique_ptr<raw_fd_ostream> | |
| 291 | getOutputStream(StringRef Path, DiagnosticsEngine &Diags, bool Binary) { | |
| 292 | // Make sure that the Out file gets unlinked from the disk if we get a | |
| 293 | // SIGINT. | |
| 294 | if (Path != "-") | |
| 295 | sys::RemoveFileOnSignal(Path); | |
| 296 | ||
| 297 | std::error_code EC; | |
| 298 | auto Out = llvm::make_unique<raw_fd_ostream>( | |
| 299 | Path, EC, (Binary ? sys::fs::F_None : sys::fs::F_Text)); | |
| 300 | if (EC) { | |
| 301 | Diags.Report(diag::err_fe_unable_to_open_output) << Path << EC.message(); | |
| 302 | return nullptr; | |
| 303 | } | |
| 304 | ||
| 305 | return Out; | |
| 306 | } | |
| 307 | ||
| 308 | static bool ExecuteAssembler(AssemblerInvocation &Opts, | |
| 309 | DiagnosticsEngine &Diags) { | |
| 310 | // Get the target specific parser. | |
| 311 | std::string Error; | |
| 312 | const Target *TheTarget = TargetRegistry::lookupTarget(Opts.Triple, Error); | |
| 313 | if (!TheTarget) | |
| 314 | return Diags.Report(diag::err_target_unknown_triple) << Opts.Triple; | |
| 315 | ||
| 316 | ErrorOr<std::unique_ptr<MemoryBuffer>> Buffer = | |
| 317 | MemoryBuffer::getFileOrSTDIN(Opts.InputFile); | |
| 318 | ||
| 319 | if (std::error_code EC = Buffer.getError()) { | |
| 320 | Error = EC.message(); | |
| 321 | return Diags.Report(diag::err_fe_error_reading) << Opts.InputFile; | |
| 322 | } | |
| 323 | ||
| 324 | SourceMgr SrcMgr; | |
| 325 | ||
| 326 | // Tell SrcMgr about this buffer, which is what the parser will pick up. | |
| 327 | SrcMgr.AddNewSourceBuffer(std::move(*Buffer), SMLoc()); | |
| 328 | ||
| 329 | // Record the location of the include directories so that the lexer can find | |
| 330 | // it later. | |
| 331 | SrcMgr.setIncludeDirs(Opts.IncludePaths); | |
| 332 | ||
| 333 | std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(Opts.Triple)); | |
| 334 | assert(MRI && "Unable to create target register info!"); | |
| 335 | ||
| 336 | std::unique_ptr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, Opts.Triple)); | |
| 337 | assert(MAI && "Unable to create target asm info!"); | |
| 338 | ||
| 339 | // Ensure MCAsmInfo initialization occurs before any use, otherwise sections | |
| 340 | // may be created with a combination of default and explicit settings. | |
| 341 | MAI->setCompressDebugSections(Opts.CompressDebugSections); | |
| 342 | ||
| 343 | MAI->setRelaxELFRelocations(Opts.RelaxELFRelocations); | |
| 344 | ||
| 345 | bool IsBinary = Opts.OutputType == AssemblerInvocation::FT_Obj; | |
| 346 | if (Opts.OutputPath.empty()) | |
| 347 | Opts.OutputPath = "-"; | |
| 348 | std::unique_ptr<raw_fd_ostream> FDOS = | |
| 349 | getOutputStream(Opts.OutputPath, Diags, IsBinary); | |
| 350 | if (!FDOS) | |
| 351 | return true; | |
| 352 | std::unique_ptr<raw_fd_ostream> DwoOS; | |
| 353 | if (!Opts.SplitDwarfFile.empty()) | |
| 354 | DwoOS = getOutputStream(Opts.SplitDwarfFile, Diags, IsBinary); | |
| 355 | ||
| 356 | // FIXME: This is not pretty. MCContext has a ptr to MCObjectFileInfo and | |
| 357 | // MCObjectFileInfo needs a MCContext reference in order to initialize itself. | |
| 358 | std::unique_ptr<MCObjectFileInfo> MOFI(new MCObjectFileInfo()); | |
| 359 | ||
| 360 | MCContext Ctx(MAI.get(), MRI.get(), MOFI.get(), &SrcMgr); | |
| 361 | ||
| 362 | bool PIC = false; | |
| 363 | if (Opts.RelocationModel == "static") { | |
| 364 | PIC = false; | |
| 365 | } else if (Opts.RelocationModel == "pic") { | |
| 366 | PIC = true; | |
| 367 | } else { | |
| 368 | assert(Opts.RelocationModel == "dynamic-no-pic" && | |
| 369 | "Invalid PIC model!"); | |
| 370 | PIC = false; | |
| 371 | } | |
| 372 | ||
| 373 | MOFI->InitMCObjectFileInfo(Triple(Opts.Triple), PIC, Ctx); | |
| 374 | if (Opts.SaveTemporaryLabels) | |
| 375 | Ctx.setAllowTemporaryLabels(false); | |
| 376 | if (Opts.GenDwarfForAssembly) | |
| 377 | Ctx.setGenDwarfForAssembly(true); | |
| 378 | if (!Opts.DwarfDebugFlags.empty()) | |
| 379 | Ctx.setDwarfDebugFlags(StringRef(Opts.DwarfDebugFlags)); | |
| 380 | if (!Opts.DwarfDebugProducer.empty()) | |
| 381 | Ctx.setDwarfDebugProducer(StringRef(Opts.DwarfDebugProducer)); | |
| 382 | if (!Opts.DebugCompilationDir.empty()) | |
| 383 | Ctx.setCompilationDir(Opts.DebugCompilationDir); | |
| 384 | if (!Opts.DebugPrefixMap.empty()) | |
| 385 | for (const auto &KV : Opts.DebugPrefixMap) | |
| 386 | Ctx.addDebugPrefixMapEntry(KV.first, KV.second); | |
| 387 | if (!Opts.MainFileName.empty()) | |
| 388 | Ctx.setMainFileName(StringRef(Opts.MainFileName)); | |
| 389 | Ctx.setDwarfVersion(Opts.DwarfVersion); | |
| 390 | ||
| 391 | // Build up the feature string from the target feature list. | |
| 392 | std::string FS; | |
| 393 | if (!Opts.Features.empty()) { | |
| 394 | FS = Opts.Features[0]; | |
| 395 | for (unsigned i = 1, e = Opts.Features.size(); i != e; ++i) | |
| 396 | FS += "," + Opts.Features[i]; | |
| 397 | } | |
| 398 | ||
| 399 | std::unique_ptr<MCStreamer> Str; | |
| 400 | ||
| 401 | std::unique_ptr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo()); | |
| 402 | std::unique_ptr<MCSubtargetInfo> STI( | |
| 403 | TheTarget->createMCSubtargetInfo(Opts.Triple, Opts.CPU, FS)); | |
| 404 | ||
| 405 | raw_pwrite_stream *Out = FDOS.get(); | |
| 406 | std::unique_ptr<buffer_ostream> BOS; | |
| 407 | ||
| 408 | // FIXME: There is a bit of code duplication with addPassesToEmitFile. | |
| 409 | if (Opts.OutputType == AssemblerInvocation::FT_Asm) { | |
| 410 | MCInstPrinter *IP = TheTarget->createMCInstPrinter( | |
| 411 | llvm::Triple(Opts.Triple), Opts.OutputAsmVariant, *MAI, *MCII, *MRI); | |
| 412 | ||
| 413 | std::unique_ptr<MCCodeEmitter> CE; | |
| 414 | if (Opts.ShowEncoding) | |
| 415 | CE.reset(TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx)); | |
| 416 | MCTargetOptions MCOptions; | |
| 417 | std::unique_ptr<MCAsmBackend> MAB( | |
| 418 | TheTarget->createMCAsmBackend(*STI, *MRI, MCOptions)); | |
| 419 | ||
| 420 | auto FOut = llvm::make_unique<formatted_raw_ostream>(*Out); | |
| 421 | Str.reset(TheTarget->createAsmStreamer( | |
| 422 | Ctx, std::move(FOut), /*asmverbose*/ true, | |
| 423 | /*useDwarfDirectory*/ true, IP, std::move(CE), std::move(MAB), | |
| 424 | Opts.ShowInst)); | |
| 425 | } else if (Opts.OutputType == AssemblerInvocation::FT_Null) { | |
| 426 | Str.reset(createNullStreamer(Ctx)); | |
| 427 | } else { | |
| 428 | assert(Opts.OutputType == AssemblerInvocation::FT_Obj && | |
| 429 | "Invalid file type!"); | |
| 430 | if (!FDOS->supportsSeeking()) { | |
| 431 | BOS = make_unique<buffer_ostream>(*FDOS); | |
| 432 | Out = BOS.get(); | |
| 433 | } | |
| 434 | ||
| 435 | std::unique_ptr<MCCodeEmitter> CE( | |
| 436 | TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx)); | |
| 437 | MCTargetOptions MCOptions; | |
| 438 | std::unique_ptr<MCAsmBackend> MAB( | |
| 439 | TheTarget->createMCAsmBackend(*STI, *MRI, MCOptions)); | |
| 440 | std::unique_ptr<MCObjectWriter> OW = | |
| 441 | DwoOS ? MAB->createDwoObjectWriter(*Out, *DwoOS) | |
| 442 | : MAB->createObjectWriter(*Out); | |
| 443 | ||
| 444 | Triple T(Opts.Triple); | |
| 445 | Str.reset(TheTarget->createMCObjectStreamer( | |
| 446 | T, Ctx, std::move(MAB), std::move(OW), std::move(CE), *STI, | |
| 447 | Opts.RelaxAll, Opts.IncrementalLinkerCompatible, | |
| 448 | /*DWARFMustBeAtTheEnd*/ true)); | |
| 449 | Str.get()->InitSections(Opts.NoExecStack); | |
| 450 | } | |
| 451 | ||
| 452 | // Assembly to object compilation should leverage assembly info. | |
| 453 | Str->setUseAssemblerInfoForParsing(true); | |
| 454 | ||
| 455 | bool Failed = false; | |
| 456 | ||
| 457 | std::unique_ptr<MCAsmParser> Parser( | |
| 458 | createMCAsmParser(SrcMgr, Ctx, *Str.get(), *MAI)); | |
| 459 | ||
| 460 | // FIXME: init MCTargetOptions from sanitizer flags here. | |
| 461 | MCTargetOptions Options; | |
| 462 | std::unique_ptr<MCTargetAsmParser> TAP( | |
| 463 | TheTarget->createMCAsmParser(*STI, *Parser, *MCII, Options)); | |
| 464 | if (!TAP) | |
| 465 | Failed = Diags.Report(diag::err_target_unknown_triple) << Opts.Triple; | |
| 466 | ||
| 467 | // Set values for symbols, if any. | |
| 468 | for (auto &S : Opts.SymbolDefs) { | |
| 469 | auto Pair = StringRef(S).split('='); | |
| 470 | auto Sym = Pair.first; | |
| 471 | auto Val = Pair.second; | |
| 472 | int64_t Value; | |
| 473 | // We have already error checked this in the driver. | |
| 474 | Val.getAsInteger(0, Value); | |
| 475 | Ctx.setSymbolValue(Parser->getStreamer(), Sym, Value); | |
| 476 | } | |
| 477 | ||
| 478 | if (!Failed) { | |
| 479 | Parser->setTargetParser(*TAP.get()); | |
| 480 | Failed = Parser->Run(Opts.NoInitialTextSection); | |
| 481 | } | |
| 482 | ||
| 483 | // Close Streamer first. | |
| 484 | // It might have a reference to the output stream. | |
| 485 | Str.reset(); | |
| 486 | // Close the output stream early. | |
| 487 | BOS.reset(); | |
| 488 | FDOS.reset(); | |
| 489 | ||
| 490 | // Delete output file if there were errors. | |
| 491 | if (Failed) { | |
| 492 | if (Opts.OutputPath != "-") | |
| 493 | sys::fs::remove(Opts.OutputPath); | |
| 494 | if (!Opts.SplitDwarfFile.empty() && Opts.SplitDwarfFile != "-") | |
| 495 | sys::fs::remove(Opts.SplitDwarfFile); | |
| 496 | } | |
| 497 | ||
| 498 | return Failed; | |
| 499 | } | |
| 500 | ||
| 501 | static void LLVMErrorHandler(void *UserData, const std::string &Message, | |
| 502 | bool GenCrashDiag) { | |
| 503 | DiagnosticsEngine &Diags = *static_cast<DiagnosticsEngine*>(UserData); | |
| 504 | ||
| 505 | Diags.Report(diag::err_fe_error_backend) << Message; | |
| 506 | ||
| 507 | // We cannot recover from llvm errors. | |
| 508 | exit(1); | |
| 509 | } | |
| 510 | ||
| 511 | int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) { | |
| 512 | // Initialize targets and assembly printers/parsers. | |
| 513 | InitializeAllTargetInfos(); | |
| 514 | InitializeAllTargetMCs(); | |
| 515 | InitializeAllAsmParsers(); | |
| 516 | ||
| 517 | // Construct our diagnostic client. | |
| 518 | IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); | |
| 519 | TextDiagnosticPrinter *DiagClient | |
| 520 | = new TextDiagnosticPrinter(errs(), &*DiagOpts); | |
| 521 | DiagClient->setPrefix("clang -cc1as"); | |
| 522 | IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); | |
| 523 | DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient); | |
| 524 | ||
| 525 | // Set an error handler, so that any LLVM backend diagnostics go through our | |
| 526 | // error handler. | |
| 527 | ScopedFatalErrorHandler FatalErrorHandler | |
| 528 | (LLVMErrorHandler, static_cast<void*>(&Diags)); | |
| 529 | ||
| 530 | // Parse the arguments. | |
| 531 | AssemblerInvocation Asm; | |
| 532 | if (!AssemblerInvocation::CreateFromArgs(Asm, Argv, Diags)) | |
| 533 | return 1; | |
| 534 | ||
| 535 | if (Asm.ShowHelp) { | |
| 536 | std::unique_ptr<OptTable> Opts(driver::createDriverOptTable()); | |
| 537 | Opts->PrintHelp(llvm::outs(), "clang -cc1as", "Clang Integrated Assembler", | |
| 538 | /*Include=*/driver::options::CC1AsOption, /*Exclude=*/0, | |
| 539 | /*ShowAllAliases=*/false); | |
| 540 | return 0; | |
| 541 | } | |
| 542 | ||
| 543 | // Honor -version. | |
| 544 | // | |
| 545 | // FIXME: Use a better -version message? | |
| 546 | if (Asm.ShowVersion) { | |
| 547 | llvm::cl::PrintVersionMessage(); | |
| 548 | return 0; | |
| 549 | } | |
| 550 | ||
| 551 | // Honor -mllvm. | |
| 552 | // | |
| 553 | // FIXME: Remove this, one day. | |
| 554 | if (!Asm.LLVMArgs.empty()) { | |
| 555 | unsigned NumArgs = Asm.LLVMArgs.size(); | |
| 556 | auto Args = llvm::make_unique<const char*[]>(NumArgs + 2); | |
| 557 | Args[0] = "clang (LLVM option parsing)"; | |
| 558 | for (unsigned i = 0; i != NumArgs; ++i) | |
| 559 | Args[i + 1] = Asm.LLVMArgs[i].c_str(); | |
| 560 | Args[NumArgs + 1] = nullptr; | |
| 561 | llvm::cl::ParseCommandLineOptions(NumArgs + 1, Args.get()); | |
| 562 | } | |
| 563 | ||
| 564 | // Execute the invocation, unless there were parsing errors. | |
| 565 | bool Failed = Diags.hasErrorOccurred() || ExecuteAssembler(Asm, Diags); | |
| 566 | ||
| 567 | // If any timers were active but haven't been destroyed yet, print their | |
| 568 | // results now. | |
| 569 | TimerGroup::printAll(errs()); | |
| 570 | ||
| 571 | return !!Failed; | |
| 572 | } | |
| 573 |
src/zig_clang_driver.cpp created+512| ... | ... | @@ -0,0 +1,512 @@ |
| 1 | //===-- driver.cpp - Clang GCC-Compatible Driver --------------------------===// | |
| 2 | // | |
| 3 | // The LLVM Compiler Infrastructure | |
| 4 | // | |
| 5 | // This file is distributed under the University of Illinois Open Source | |
| 6 | // License. See LICENSE.TXT for details. | |
| 7 | // | |
| 8 | //===----------------------------------------------------------------------===// | |
| 9 | // | |
| 10 | // This is the entry point to the clang driver; it is a thin wrapper | |
| 11 | // for functionality in the Driver clang library. | |
| 12 | // | |
| 13 | //===----------------------------------------------------------------------===// | |
| 14 | ||
| 15 | #include "clang/Driver/Driver.h" | |
| 16 | #include "clang/Basic/DiagnosticOptions.h" | |
| 17 | #include "clang/Driver/Compilation.h" | |
| 18 | #include "clang/Driver/DriverDiagnostic.h" | |
| 19 | #include "clang/Driver/Options.h" | |
| 20 | #include "clang/Driver/ToolChain.h" | |
| 21 | #include "clang/Frontend/ChainedDiagnosticConsumer.h" | |
| 22 | #include "clang/Frontend/CompilerInvocation.h" | |
| 23 | #include "clang/Frontend/SerializedDiagnosticPrinter.h" | |
| 24 | #include "clang/Frontend/TextDiagnosticPrinter.h" | |
| 25 | #include "clang/Frontend/Utils.h" | |
| 26 | #include "llvm/ADT/ArrayRef.h" | |
| 27 | #include "llvm/ADT/SmallString.h" | |
| 28 | #include "llvm/ADT/SmallVector.h" | |
| 29 | #include "llvm/Option/ArgList.h" | |
| 30 | #include "llvm/Option/OptTable.h" | |
| 31 | #include "llvm/Option/Option.h" | |
| 32 | #include "llvm/Support/CommandLine.h" | |
| 33 | #include "llvm/Support/ErrorHandling.h" | |
| 34 | #include "llvm/Support/FileSystem.h" | |
| 35 | #include "llvm/Support/Host.h" | |
| 36 | #include "llvm/Support/InitLLVM.h" | |
| 37 | #include "llvm/Support/Path.h" | |
| 38 | #include "llvm/Support/Process.h" | |
| 39 | #include "llvm/Support/Program.h" | |
| 40 | #include "llvm/Support/Regex.h" | |
| 41 | #include "llvm/Support/Signals.h" | |
| 42 | #include "llvm/Support/StringSaver.h" | |
| 43 | #include "llvm/Support/TargetSelect.h" | |
| 44 | #include "llvm/Support/Timer.h" | |
| 45 | #include "llvm/Support/raw_ostream.h" | |
| 46 | #include <memory> | |
| 47 | #include <set> | |
| 48 | #include <system_error> | |
| 49 | using namespace clang; | |
| 50 | using namespace clang::driver; | |
| 51 | using namespace llvm::opt; | |
| 52 | ||
| 53 | std::string GetExecutablePath(const char *Argv0, bool CanonicalPrefixes) { | |
| 54 | if (!CanonicalPrefixes) { | |
| 55 | SmallString<128> ExecutablePath(Argv0); | |
| 56 | // Do a PATH lookup if Argv0 isn't a valid path. | |
| 57 | if (!llvm::sys::fs::exists(ExecutablePath)) | |
| 58 | if (llvm::ErrorOr<std::string> P = | |
| 59 | llvm::sys::findProgramByName(ExecutablePath)) | |
| 60 | ExecutablePath = *P; | |
| 61 | return ExecutablePath.str(); | |
| 62 | } | |
| 63 | ||
| 64 | // This just needs to be some symbol in the binary; C++ doesn't | |
| 65 | // allow taking the address of ::main however. | |
| 66 | void *P = (void*) (intptr_t) GetExecutablePath; | |
| 67 | return llvm::sys::fs::getMainExecutable(Argv0, P); | |
| 68 | } | |
| 69 | ||
| 70 | static const char *GetStableCStr(std::set<std::string> &SavedStrings, | |
| 71 | StringRef S) { | |
| 72 | return SavedStrings.insert(S).first->c_str(); | |
| 73 | } | |
| 74 | ||
| 75 | /// ApplyQAOverride - Apply a list of edits to the input argument lists. | |
| 76 | /// | |
| 77 | /// The input string is a space separate list of edits to perform, | |
| 78 | /// they are applied in order to the input argument lists. Edits | |
| 79 | /// should be one of the following forms: | |
| 80 | /// | |
| 81 | /// '#': Silence information about the changes to the command line arguments. | |
| 82 | /// | |
| 83 | /// '^': Add FOO as a new argument at the beginning of the command line. | |
| 84 | /// | |
| 85 | /// '+': Add FOO as a new argument at the end of the command line. | |
| 86 | /// | |
| 87 | /// 's/XXX/YYY/': Substitute the regular expression XXX with YYY in the command | |
| 88 | /// line. | |
| 89 | /// | |
| 90 | /// 'xOPTION': Removes all instances of the literal argument OPTION. | |
| 91 | /// | |
| 92 | /// 'XOPTION': Removes all instances of the literal argument OPTION, | |
| 93 | /// and the following argument. | |
| 94 | /// | |
| 95 | /// 'Ox': Removes all flags matching 'O' or 'O[sz0-9]' and adds 'Ox' | |
| 96 | /// at the end of the command line. | |
| 97 | /// | |
| 98 | /// \param OS - The stream to write edit information to. | |
| 99 | /// \param Args - The vector of command line arguments. | |
| 100 | /// \param Edit - The override command to perform. | |
| 101 | /// \param SavedStrings - Set to use for storing string representations. | |
| 102 | static void ApplyOneQAOverride(raw_ostream &OS, | |
| 103 | SmallVectorImpl<const char*> &Args, | |
| 104 | StringRef Edit, | |
| 105 | std::set<std::string> &SavedStrings) { | |
| 106 | // This does not need to be efficient. | |
| 107 | ||
| 108 | if (Edit[0] == '^') { | |
| 109 | const char *Str = | |
| 110 | GetStableCStr(SavedStrings, Edit.substr(1)); | |
| 111 | OS << "### Adding argument " << Str << " at beginning\n"; | |
| 112 | Args.insert(Args.begin() + 1, Str); | |
| 113 | } else if (Edit[0] == '+') { | |
| 114 | const char *Str = | |
| 115 | GetStableCStr(SavedStrings, Edit.substr(1)); | |
| 116 | OS << "### Adding argument " << Str << " at end\n"; | |
| 117 | Args.push_back(Str); | |
| 118 | } else if (Edit[0] == 's' && Edit[1] == '/' && Edit.endswith("/") && | |
| 119 | Edit.slice(2, Edit.size()-1).find('/') != StringRef::npos) { | |
| 120 | StringRef MatchPattern = Edit.substr(2).split('/').first; | |
| 121 | StringRef ReplPattern = Edit.substr(2).split('/').second; | |
| 122 | ReplPattern = ReplPattern.slice(0, ReplPattern.size()-1); | |
| 123 | ||
| 124 | for (unsigned i = 1, e = Args.size(); i != e; ++i) { | |
| 125 | // Ignore end-of-line response file markers | |
| 126 | if (Args[i] == nullptr) | |
| 127 | continue; | |
| 128 | std::string Repl = llvm::Regex(MatchPattern).sub(ReplPattern, Args[i]); | |
| 129 | ||
| 130 | if (Repl != Args[i]) { | |
| 131 | OS << "### Replacing '" << Args[i] << "' with '" << Repl << "'\n"; | |
| 132 | Args[i] = GetStableCStr(SavedStrings, Repl); | |
| 133 | } | |
| 134 | } | |
| 135 | } else if (Edit[0] == 'x' || Edit[0] == 'X') { | |
| 136 | auto Option = Edit.substr(1); | |
| 137 | for (unsigned i = 1; i < Args.size();) { | |
| 138 | if (Option == Args[i]) { | |
| 139 | OS << "### Deleting argument " << Args[i] << '\n'; | |
| 140 | Args.erase(Args.begin() + i); | |
| 141 | if (Edit[0] == 'X') { | |
| 142 | if (i < Args.size()) { | |
| 143 | OS << "### Deleting argument " << Args[i] << '\n'; | |
| 144 | Args.erase(Args.begin() + i); | |
| 145 | } else | |
| 146 | OS << "### Invalid X edit, end of command line!\n"; | |
| 147 | } | |
| 148 | } else | |
| 149 | ++i; | |
| 150 | } | |
| 151 | } else if (Edit[0] == 'O') { | |
| 152 | for (unsigned i = 1; i < Args.size();) { | |
| 153 | const char *A = Args[i]; | |
| 154 | // Ignore end-of-line response file markers | |
| 155 | if (A == nullptr) | |
| 156 | continue; | |
| 157 | if (A[0] == '-' && A[1] == 'O' && | |
| 158 | (A[2] == '\0' || | |
| 159 | (A[3] == '\0' && (A[2] == 's' || A[2] == 'z' || | |
| 160 | ('0' <= A[2] && A[2] <= '9'))))) { | |
| 161 | OS << "### Deleting argument " << Args[i] << '\n'; | |
| 162 | Args.erase(Args.begin() + i); | |
| 163 | } else | |
| 164 | ++i; | |
| 165 | } | |
| 166 | OS << "### Adding argument " << Edit << " at end\n"; | |
| 167 | Args.push_back(GetStableCStr(SavedStrings, '-' + Edit.str())); | |
| 168 | } else { | |
| 169 | OS << "### Unrecognized edit: " << Edit << "\n"; | |
| 170 | } | |
| 171 | } | |
| 172 | ||
| 173 | /// ApplyQAOverride - Apply a comma separate list of edits to the | |
| 174 | /// input argument lists. See ApplyOneQAOverride. | |
| 175 | static void ApplyQAOverride(SmallVectorImpl<const char*> &Args, | |
| 176 | const char *OverrideStr, | |
| 177 | std::set<std::string> &SavedStrings) { | |
| 178 | raw_ostream *OS = &llvm::errs(); | |
| 179 | ||
| 180 | if (OverrideStr[0] == '#') { | |
| 181 | ++OverrideStr; | |
| 182 | OS = &llvm::nulls(); | |
| 183 | } | |
| 184 | ||
| 185 | *OS << "### CCC_OVERRIDE_OPTIONS: " << OverrideStr << "\n"; | |
| 186 | ||
| 187 | // This does not need to be efficient. | |
| 188 | ||
| 189 | const char *S = OverrideStr; | |
| 190 | while (*S) { | |
| 191 | const char *End = ::strchr(S, ' '); | |
| 192 | if (!End) | |
| 193 | End = S + strlen(S); | |
| 194 | if (End != S) | |
| 195 | ApplyOneQAOverride(*OS, Args, std::string(S, End), SavedStrings); | |
| 196 | S = End; | |
| 197 | if (*S != '\0') | |
| 198 | ++S; | |
| 199 | } | |
| 200 | } | |
| 201 | ||
| 202 | extern int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, | |
| 203 | void *MainAddr); | |
| 204 | extern int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0, | |
| 205 | void *MainAddr); | |
| 206 | ||
| 207 | static void insertTargetAndModeArgs(const ParsedClangName &NameParts, | |
| 208 | SmallVectorImpl<const char *> &ArgVector, | |
| 209 | std::set<std::string> &SavedStrings) { | |
| 210 | // Put target and mode arguments at the start of argument list so that | |
| 211 | // arguments specified in command line could override them. Avoid putting | |
| 212 | // them at index 0, as an option like '-cc1' must remain the first. | |
| 213 | int InsertionPoint = 0; | |
| 214 | if (ArgVector.size() > 0) | |
| 215 | ++InsertionPoint; | |
| 216 | ||
| 217 | if (NameParts.DriverMode) { | |
| 218 | // Add the mode flag to the arguments. | |
| 219 | ArgVector.insert(ArgVector.begin() + InsertionPoint, | |
| 220 | GetStableCStr(SavedStrings, NameParts.DriverMode)); | |
| 221 | } | |
| 222 | ||
| 223 | if (NameParts.TargetIsValid) { | |
| 224 | const char *arr[] = {"-target", GetStableCStr(SavedStrings, | |
| 225 | NameParts.TargetPrefix)}; | |
| 226 | ArgVector.insert(ArgVector.begin() + InsertionPoint, | |
| 227 | std::begin(arr), std::end(arr)); | |
| 228 | } | |
| 229 | } | |
| 230 | ||
| 231 | static void getCLEnvVarOptions(std::string &EnvValue, llvm::StringSaver &Saver, | |
| 232 | SmallVectorImpl<const char *> &Opts) { | |
| 233 | llvm::cl::TokenizeWindowsCommandLine(EnvValue, Saver, Opts); | |
| 234 | // The first instance of '#' should be replaced with '=' in each option. | |
| 235 | for (const char *Opt : Opts) | |
| 236 | if (char *NumberSignPtr = const_cast<char *>(::strchr(Opt, '#'))) | |
| 237 | *NumberSignPtr = '='; | |
| 238 | } | |
| 239 | ||
| 240 | static void SetBackdoorDriverOutputsFromEnvVars(Driver &TheDriver) { | |
| 241 | // Handle CC_PRINT_OPTIONS and CC_PRINT_OPTIONS_FILE. | |
| 242 | TheDriver.CCPrintOptions = !!::getenv("CC_PRINT_OPTIONS"); | |
| 243 | if (TheDriver.CCPrintOptions) | |
| 244 | TheDriver.CCPrintOptionsFilename = ::getenv("CC_PRINT_OPTIONS_FILE"); | |
| 245 | ||
| 246 | // Handle CC_PRINT_HEADERS and CC_PRINT_HEADERS_FILE. | |
| 247 | TheDriver.CCPrintHeaders = !!::getenv("CC_PRINT_HEADERS"); | |
| 248 | if (TheDriver.CCPrintHeaders) | |
| 249 | TheDriver.CCPrintHeadersFilename = ::getenv("CC_PRINT_HEADERS_FILE"); | |
| 250 | ||
| 251 | // Handle CC_LOG_DIAGNOSTICS and CC_LOG_DIAGNOSTICS_FILE. | |
| 252 | TheDriver.CCLogDiagnostics = !!::getenv("CC_LOG_DIAGNOSTICS"); | |
| 253 | if (TheDriver.CCLogDiagnostics) | |
| 254 | TheDriver.CCLogDiagnosticsFilename = ::getenv("CC_LOG_DIAGNOSTICS_FILE"); | |
| 255 | } | |
| 256 | ||
| 257 | static void FixupDiagPrefixExeName(TextDiagnosticPrinter *DiagClient, | |
| 258 | const std::string &Path) { | |
| 259 | // If the clang binary happens to be named cl.exe for compatibility reasons, | |
| 260 | // use clang-cl.exe as the prefix to avoid confusion between clang and MSVC. | |
| 261 | StringRef ExeBasename(llvm::sys::path::filename(Path)); | |
| 262 | if (ExeBasename.equals_lower("cl.exe")) | |
| 263 | ExeBasename = "clang-cl.exe"; | |
| 264 | DiagClient->setPrefix(ExeBasename); | |
| 265 | } | |
| 266 | ||
| 267 | // This lets us create the DiagnosticsEngine with a properly-filled-out | |
| 268 | // DiagnosticOptions instance. | |
| 269 | static DiagnosticOptions * | |
| 270 | CreateAndPopulateDiagOpts(ArrayRef<const char *> argv) { | |
| 271 | auto *DiagOpts = new DiagnosticOptions; | |
| 272 | std::unique_ptr<OptTable> Opts(createDriverOptTable()); | |
| 273 | unsigned MissingArgIndex, MissingArgCount; | |
| 274 | InputArgList Args = | |
| 275 | Opts->ParseArgs(argv.slice(1), MissingArgIndex, MissingArgCount); | |
| 276 | // We ignore MissingArgCount and the return value of ParseDiagnosticArgs. | |
| 277 | // Any errors that would be diagnosed here will also be diagnosed later, | |
| 278 | // when the DiagnosticsEngine actually exists. | |
| 279 | (void)ParseDiagnosticArgs(*DiagOpts, Args); | |
| 280 | return DiagOpts; | |
| 281 | } | |
| 282 | ||
| 283 | static void SetInstallDir(SmallVectorImpl<const char *> &argv, | |
| 284 | Driver &TheDriver, bool CanonicalPrefixes) { | |
| 285 | // Attempt to find the original path used to invoke the driver, to determine | |
| 286 | // the installed path. We do this manually, because we want to support that | |
| 287 | // path being a symlink. | |
| 288 | SmallString<128> InstalledPath(argv[0]); | |
| 289 | ||
| 290 | // Do a PATH lookup, if there are no directory components. | |
| 291 | if (llvm::sys::path::filename(InstalledPath) == InstalledPath) | |
| 292 | if (llvm::ErrorOr<std::string> Tmp = llvm::sys::findProgramByName( | |
| 293 | llvm::sys::path::filename(InstalledPath.str()))) | |
| 294 | InstalledPath = *Tmp; | |
| 295 | ||
| 296 | // FIXME: We don't actually canonicalize this, we just make it absolute. | |
| 297 | if (CanonicalPrefixes) | |
| 298 | llvm::sys::fs::make_absolute(InstalledPath); | |
| 299 | ||
| 300 | StringRef InstalledPathParent(llvm::sys::path::parent_path(InstalledPath)); | |
| 301 | if (llvm::sys::fs::exists(InstalledPathParent)) | |
| 302 | TheDriver.setInstalledDir(InstalledPathParent); | |
| 303 | } | |
| 304 | ||
| 305 | static int ExecuteCC1Tool(ArrayRef<const char *> argv, StringRef Tool) { | |
| 306 | void *GetExecutablePathVP = (void *)(intptr_t) GetExecutablePath; | |
| 307 | if (Tool == "") | |
| 308 | return cc1_main(argv.slice(2), argv[0], GetExecutablePathVP); | |
| 309 | if (Tool == "as") | |
| 310 | return cc1as_main(argv.slice(2), argv[0], GetExecutablePathVP); | |
| 311 | ||
| 312 | // Reject unknown tools. | |
| 313 | llvm::errs() << "error: unknown integrated tool '" << Tool << "'. " | |
| 314 | << "Valid tools include '-cc1' and '-cc1as'.\n"; | |
| 315 | return 1; | |
| 316 | } | |
| 317 | ||
| 318 | extern "C" int ZigClang_main(int argc_, const char **argv_); | |
| 319 | int ZigClang_main(int argc_, const char **argv_) { | |
| 320 | llvm::InitLLVM X(argc_, argv_); | |
| 321 | SmallVector<const char *, 256> argv(argv_, argv_ + argc_); | |
| 322 | ||
| 323 | if (llvm::sys::Process::FixupStandardFileDescriptors()) | |
| 324 | return 1; | |
| 325 | ||
| 326 | llvm::InitializeAllTargets(); | |
| 327 | auto TargetAndMode = ToolChain::getTargetAndModeFromProgramName(argv[0]); | |
| 328 | ||
| 329 | llvm::BumpPtrAllocator A; | |
| 330 | llvm::StringSaver Saver(A); | |
| 331 | ||
| 332 | // Parse response files using the GNU syntax, unless we're in CL mode. There | |
| 333 | // are two ways to put clang in CL compatibility mode: argv[0] is either | |
| 334 | // clang-cl or cl, or --driver-mode=cl is on the command line. The normal | |
| 335 | // command line parsing can't happen until after response file parsing, so we | |
| 336 | // have to manually search for a --driver-mode=cl argument the hard way. | |
| 337 | // Finally, our -cc1 tools don't care which tokenization mode we use because | |
| 338 | // response files written by clang will tokenize the same way in either mode. | |
| 339 | bool ClangCLMode = false; | |
| 340 | if (StringRef(TargetAndMode.DriverMode).equals("--driver-mode=cl") || | |
| 341 | std::find_if(argv.begin(), argv.end(), [](const char *F) { | |
| 342 | return F && strcmp(F, "--driver-mode=cl") == 0; | |
| 343 | }) != argv.end()) { | |
| 344 | ClangCLMode = true; | |
| 345 | } | |
| 346 | enum { Default, POSIX, Windows } RSPQuoting = Default; | |
| 347 | for (const char *F : argv) { | |
| 348 | if (strcmp(F, "--rsp-quoting=posix") == 0) | |
| 349 | RSPQuoting = POSIX; | |
| 350 | else if (strcmp(F, "--rsp-quoting=windows") == 0) | |
| 351 | RSPQuoting = Windows; | |
| 352 | } | |
| 353 | ||
| 354 | // Determines whether we want nullptr markers in argv to indicate response | |
| 355 | // files end-of-lines. We only use this for the /LINK driver argument with | |
| 356 | // clang-cl.exe on Windows. | |
| 357 | bool MarkEOLs = ClangCLMode; | |
| 358 | ||
| 359 | llvm::cl::TokenizerCallback Tokenizer; | |
| 360 | if (RSPQuoting == Windows || (RSPQuoting == Default && ClangCLMode)) | |
| 361 | Tokenizer = &llvm::cl::TokenizeWindowsCommandLine; | |
| 362 | else | |
| 363 | Tokenizer = &llvm::cl::TokenizeGNUCommandLine; | |
| 364 | ||
| 365 | if (MarkEOLs && argv.size() > 1 && StringRef(argv[1]).startswith("-cc1")) | |
| 366 | MarkEOLs = false; | |
| 367 | llvm::cl::ExpandResponseFiles(Saver, Tokenizer, argv, MarkEOLs); | |
| 368 | ||
| 369 | // Handle -cc1 integrated tools, even if -cc1 was expanded from a response | |
| 370 | // file. | |
| 371 | auto FirstArg = std::find_if(argv.begin() + 1, argv.end(), | |
| 372 | [](const char *A) { return A != nullptr; }); | |
| 373 | if (FirstArg != argv.end() && StringRef(*FirstArg).startswith("-cc1")) { | |
| 374 | // If -cc1 came from a response file, remove the EOL sentinels. | |
| 375 | if (MarkEOLs) { | |
| 376 | auto newEnd = std::remove(argv.begin(), argv.end(), nullptr); | |
| 377 | argv.resize(newEnd - argv.begin()); | |
| 378 | } | |
| 379 | return ExecuteCC1Tool(argv, argv[1] + 4); | |
| 380 | } | |
| 381 | ||
| 382 | bool CanonicalPrefixes = true; | |
| 383 | for (int i = 1, size = argv.size(); i < size; ++i) { | |
| 384 | // Skip end-of-line response file markers | |
| 385 | if (argv[i] == nullptr) | |
| 386 | continue; | |
| 387 | if (StringRef(argv[i]) == "-no-canonical-prefixes") { | |
| 388 | CanonicalPrefixes = false; | |
| 389 | break; | |
| 390 | } | |
| 391 | } | |
| 392 | ||
| 393 | // Handle CL and _CL_ which permits additional command line options to be | |
| 394 | // prepended or appended. | |
| 395 | if (ClangCLMode) { | |
| 396 | // Arguments in "CL" are prepended. | |
| 397 | llvm::Optional<std::string> OptCL = llvm::sys::Process::GetEnv("CL"); | |
| 398 | if (OptCL.hasValue()) { | |
| 399 | SmallVector<const char *, 8> PrependedOpts; | |
| 400 | getCLEnvVarOptions(OptCL.getValue(), Saver, PrependedOpts); | |
| 401 | ||
| 402 | // Insert right after the program name to prepend to the argument list. | |
| 403 | argv.insert(argv.begin() + 1, PrependedOpts.begin(), PrependedOpts.end()); | |
| 404 | } | |
| 405 | // Arguments in "_CL_" are appended. | |
| 406 | llvm::Optional<std::string> Opt_CL_ = llvm::sys::Process::GetEnv("_CL_"); | |
| 407 | if (Opt_CL_.hasValue()) { | |
| 408 | SmallVector<const char *, 8> AppendedOpts; | |
| 409 | getCLEnvVarOptions(Opt_CL_.getValue(), Saver, AppendedOpts); | |
| 410 | ||
| 411 | // Insert at the end of the argument list to append. | |
| 412 | argv.append(AppendedOpts.begin(), AppendedOpts.end()); | |
| 413 | } | |
| 414 | } | |
| 415 | ||
| 416 | std::set<std::string> SavedStrings; | |
| 417 | // Handle CCC_OVERRIDE_OPTIONS, used for editing a command line behind the | |
| 418 | // scenes. | |
| 419 | if (const char *OverrideStr = ::getenv("CCC_OVERRIDE_OPTIONS")) { | |
| 420 | // FIXME: Driver shouldn't take extra initial argument. | |
| 421 | ApplyQAOverride(argv, OverrideStr, SavedStrings); | |
| 422 | } | |
| 423 | ||
| 424 | std::string Path = GetExecutablePath(argv[0], CanonicalPrefixes); | |
| 425 | ||
| 426 | IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = | |
| 427 | CreateAndPopulateDiagOpts(argv); | |
| 428 | ||
| 429 | TextDiagnosticPrinter *DiagClient | |
| 430 | = new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts); | |
| 431 | FixupDiagPrefixExeName(DiagClient, Path); | |
| 432 | ||
| 433 | IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); | |
| 434 | ||
| 435 | DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient); | |
| 436 | ||
| 437 | if (!DiagOpts->DiagnosticSerializationFile.empty()) { | |
| 438 | auto SerializedConsumer = | |
| 439 | clang::serialized_diags::create(DiagOpts->DiagnosticSerializationFile, | |
| 440 | &*DiagOpts, /*MergeChildRecords=*/true); | |
| 441 | Diags.setClient(new ChainedDiagnosticConsumer( | |
| 442 | Diags.takeClient(), std::move(SerializedConsumer))); | |
| 443 | } | |
| 444 | ||
| 445 | ProcessWarningOptions(Diags, *DiagOpts, /*ReportDiags=*/false); | |
| 446 | ||
| 447 | Driver TheDriver(Path, llvm::sys::getDefaultTargetTriple(), Diags); | |
| 448 | SetInstallDir(argv, TheDriver, CanonicalPrefixes); | |
| 449 | TheDriver.setTargetAndMode(TargetAndMode); | |
| 450 | ||
| 451 | insertTargetAndModeArgs(TargetAndMode, argv, SavedStrings); | |
| 452 | ||
| 453 | SetBackdoorDriverOutputsFromEnvVars(TheDriver); | |
| 454 | ||
| 455 | std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(argv)); | |
| 456 | int Res = 1; | |
| 457 | if (C && !C->containsError()) { | |
| 458 | SmallVector<std::pair<int, const Command *>, 4> FailingCommands; | |
| 459 | Res = TheDriver.ExecuteCompilation(*C, FailingCommands); | |
| 460 | ||
| 461 | // Force a crash to test the diagnostics. | |
| 462 | if (TheDriver.GenReproducer) { | |
| 463 | Diags.Report(diag::err_drv_force_crash) | |
| 464 | << !::getenv("FORCE_CLANG_DIAGNOSTICS_CRASH"); | |
| 465 | ||
| 466 | // Pretend that every command failed. | |
| 467 | FailingCommands.clear(); | |
| 468 | for (const auto &J : C->getJobs()) | |
| 469 | if (const Command *C = dyn_cast<Command>(&J)) | |
| 470 | FailingCommands.push_back(std::make_pair(-1, C)); | |
| 471 | } | |
| 472 | ||
| 473 | for (const auto &P : FailingCommands) { | |
| 474 | int CommandRes = P.first; | |
| 475 | const Command *FailingCommand = P.second; | |
| 476 | if (!Res) | |
| 477 | Res = CommandRes; | |
| 478 | ||
| 479 | // If result status is < 0, then the driver command signalled an error. | |
| 480 | // If result status is 70, then the driver command reported a fatal error. | |
| 481 | // On Windows, abort will return an exit code of 3. In these cases, | |
| 482 | // generate additional diagnostic information if possible. | |
| 483 | bool DiagnoseCrash = CommandRes < 0 || CommandRes == 70; | |
| 484 | #ifdef _WIN32 | |
| 485 | DiagnoseCrash |= CommandRes == 3; | |
| 486 | #endif | |
| 487 | if (DiagnoseCrash) { | |
| 488 | TheDriver.generateCompilationDiagnostics(*C, *FailingCommand); | |
| 489 | break; | |
| 490 | } | |
| 491 | } | |
| 492 | } | |
| 493 | ||
| 494 | Diags.getClient()->finish(); | |
| 495 | ||
| 496 | // If any timers were active but haven't been destroyed yet, print their | |
| 497 | // results now. This happens in -disable-free mode. | |
| 498 | llvm::TimerGroup::printAll(llvm::errs()); | |
| 499 | ||
| 500 | #ifdef _WIN32 | |
| 501 | // Exit status should not be negative on Win32, unless abnormal termination. | |
| 502 | // Once abnormal termiation was caught, negative status should not be | |
| 503 | // propagated. | |
| 504 | if (Res < 0) | |
| 505 | Res = 1; | |
| 506 | #endif | |
| 507 | ||
| 508 | // If we have multiple failing commands, we return the result of the first | |
| 509 | // failing command. | |
| 510 | return Res; | |
| 511 | } | |
| 512 |