authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-02-24 12:53:28-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-02-24 12:53:28-05:00
loga77a17e2c2dc8c2add8a3ed47708c90799425c70
treea1fcec35c29f5324b215ba477bc53ce1e3a3ed00
parent00d8f4a1bb634ec5b0569e6ff6c2679ade2bd6b0
signature Commit is signed but in an unrecognized format.

add `zig cc` command to act like a C compiler

closes #490

6 files changed, 1360 insertions(+), 0 deletions(-)

CMakeLists.txt+3
...@@ -431,6 +431,9 @@ set(BLAKE_SOURCES...@@ -431,6 +431,9 @@ set(BLAKE_SOURCES
431set(ZIG_CPP_SOURCES431set(ZIG_CPP_SOURCES
432 "${CMAKE_SOURCE_DIR}/src/zig_llvm.cpp"432 "${CMAKE_SOURCE_DIR}/src/zig_llvm.cpp"
433 "${CMAKE_SOURCE_DIR}/src/zig_clang.cpp"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 "${CMAKE_SOURCE_DIR}/src/windows_sdk.cpp"437 "${CMAKE_SOURCE_DIR}/src/windows_sdk.cpp"
435)438)
436439
cmake/Findclang.cmake+22
...@@ -11,17 +11,28 @@ if(MSVC)...@@ -11,17 +11,28 @@ if(MSVC)
11 find_package(CLANG REQUIRED CONFIG)11 find_package(CLANG REQUIRED CONFIG)
1212
13 set(CLANG_LIBRARIES13 set(CLANG_LIBRARIES
14 clangFrontendTool
15 clangCodeGen
14 clangFrontend16 clangFrontend
15 clangDriver17 clangDriver
16 clangSerialization18 clangSerialization
17 clangSema19 clangSema
20 clangStaticAnalyzerFrontend
21 clangStaticAnalyzerCheckers
22 clangStaticAnalyzerCore
18 clangAnalysis23 clangAnalysis
24 clangASTMatchers
19 clangAST25 clangAST
20 clangParse26 clangParse
21 clangSema27 clangSema
22 clangBasic28 clangBasic
23 clangEdit29 clangEdit
24 clangLex30 clangLex
31 clangARCMigrate
32 clangRewriteFrontend
33 clangRewrite
34 clangCrossTU
35 clangIndex
25 )36 )
2637
27else()38else()
...@@ -50,17 +61,28 @@ else()...@@ -50,17 +61,28 @@ else()
50 endif()61 endif()
51 endmacro(FIND_AND_ADD_CLANG_LIB)62 endmacro(FIND_AND_ADD_CLANG_LIB)
5263
64 FIND_AND_ADD_CLANG_LIB(clangFrontendTool)
65 FIND_AND_ADD_CLANG_LIB(clangCodeGen)
53 FIND_AND_ADD_CLANG_LIB(clangFrontend)66 FIND_AND_ADD_CLANG_LIB(clangFrontend)
54 FIND_AND_ADD_CLANG_LIB(clangDriver)67 FIND_AND_ADD_CLANG_LIB(clangDriver)
55 FIND_AND_ADD_CLANG_LIB(clangSerialization)68 FIND_AND_ADD_CLANG_LIB(clangSerialization)
56 FIND_AND_ADD_CLANG_LIB(clangSema)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 FIND_AND_ADD_CLANG_LIB(clangAnalysis)73 FIND_AND_ADD_CLANG_LIB(clangAnalysis)
74 FIND_AND_ADD_CLANG_LIB(clangASTMatchers)
58 FIND_AND_ADD_CLANG_LIB(clangAST)75 FIND_AND_ADD_CLANG_LIB(clangAST)
59 FIND_AND_ADD_CLANG_LIB(clangParse)76 FIND_AND_ADD_CLANG_LIB(clangParse)
60 FIND_AND_ADD_CLANG_LIB(clangSema)77 FIND_AND_ADD_CLANG_LIB(clangSema)
61 FIND_AND_ADD_CLANG_LIB(clangBasic)78 FIND_AND_ADD_CLANG_LIB(clangBasic)
62 FIND_AND_ADD_CLANG_LIB(clangEdit)79 FIND_AND_ADD_CLANG_LIB(clangEdit)
63 FIND_AND_ADD_CLANG_LIB(clangLex)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)
64endif()86endif()
6587
66include(FindPackageHandleStandardArgs)88include(FindPackageHandleStandardArgs)
src/main.cpp+13
...@@ -32,6 +32,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {...@@ -32,6 +32,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {
32 " build-lib [source] create library from source or object files\n"32 " build-lib [source] create library from source or object files\n"
33 " build-obj [source] create object from source or assembly\n"33 " build-obj [source] create object from source or assembly\n"
34 " builtin show the source code of that @import(\"builtin\")\n"34 " builtin show the source code of that @import(\"builtin\")\n"
35 " cc C compiler\n"
35 " fmt parse files and render in canonical zig format\n"36 " fmt parse files and render in canonical zig format\n"
36 " help show this usage information\n"37 " help show this usage information\n"
37 " id print the base64-encoded compiler id\n"38 " id print the base64-encoded compiler id\n"
...@@ -240,6 +241,8 @@ static bool get_cache_opt(CacheOpt opt, bool default_value) {...@@ -240,6 +241,8 @@ static bool get_cache_opt(CacheOpt opt, bool default_value) {
240 zig_unreachable();241 zig_unreachable();
241}242}
242243
244extern "C" int ZigClang_main(int argc, char **argv);
245
243int main(int argc, char **argv) {246int main(int argc, char **argv) {
244 char *arg0 = argv[0];247 char *arg0 = argv[0];
245 Error err;248 Error err;
...@@ -257,6 +260,16 @@ int main(int argc, char **argv) {...@@ -257,6 +260,16 @@ int main(int argc, char **argv) {
257 return 0;260 return 0;
258 }261 }
259262
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 // Must be before all os.hpp function calls.273 // Must be before all os.hpp function calls.
261 os_init();274 os_init();
262275
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
47using namespace clang;
48using namespace llvm::opt;
49
50//===----------------------------------------------------------------------===//
51// Main driver
52//===----------------------------------------------------------------------===//
53
54static 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
71namespace polly {
72void initializePollyPasses(llvm::PassRegistry &Registry);
73}
74#endif
75
76#ifdef CLANG_HAVE_RLIMITS
77#if defined(__linux__) && defined(__PIE__)
78static 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
113LLVM_ATTRIBUTE_NOINLINE
114static 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
132static void ensureStackAddressSpace() {}
133#endif
134
135/// Attempt to ensure that we have at least 8MiB of usable stack space.
136static 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
164static void ensureSufficientStack() {}
165#endif
166
167int 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>
57using namespace clang;
58using namespace clang::driver;
59using namespace clang::driver::options;
60using namespace llvm;
61using namespace llvm::opt;
62
63namespace {
64
65/// Helper class for representing a single invocation of the assembler.
66struct 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
141public:
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
165bool 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
290static std::unique_ptr<raw_fd_ostream>
291getOutputStream(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
308static 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
501static 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
511int 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>
49using namespace clang;
50using namespace clang::driver;
51using namespace llvm::opt;
52
53std::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
70static 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.
102static 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.
175static 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
202extern int cc1_main(ArrayRef<const char *> Argv, const char *Argv0,
203 void *MainAddr);
204extern int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0,
205 void *MainAddr);
206
207static 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
231static 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
240static 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
257static 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.
269static DiagnosticOptions *
270CreateAndPopulateDiagOpts(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
283static 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
305static 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
318extern "C" int ZigClang_main(int argc_, const char **argv_);
319int 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