authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-02-24 16:28:49-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2019-02-24 16:28:49-05:00
loge5d4862e145c38ffc1111ee578ddcafc1e35ad57
treea74e9fcd5a0fb92cf34963cbb72c44430ef9c396
parent98869edb8b44f164bb46851cff88e2338fe6f399
parent8c2c6368f9645def45374c2fb9027bf72b15ab2e
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #2003 from ziglang/zig-cc

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

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

CMakeLists.txt+3
......@@ -431,6 +431,9 @@ set(BLAKE_SOURCES
431431set(ZIG_CPP_SOURCES
432432 "${CMAKE_SOURCE_DIR}/src/zig_llvm.cpp"
433433 "${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"
434437 "${CMAKE_SOURCE_DIR}/src/windows_sdk.cpp"
435438)
436439
cmake/Findclang.cmake+22
......@@ -11,17 +11,28 @@ if(MSVC)
1111 find_package(CLANG REQUIRED CONFIG)
1212
1313 set(CLANG_LIBRARIES
14 clangFrontendTool
15 clangCodeGen
1416 clangFrontend
1517 clangDriver
1618 clangSerialization
1719 clangSema
20 clangStaticAnalyzerFrontend
21 clangStaticAnalyzerCheckers
22 clangStaticAnalyzerCore
1823 clangAnalysis
24 clangASTMatchers
1925 clangAST
2026 clangParse
2127 clangSema
2228 clangBasic
2329 clangEdit
2430 clangLex
31 clangARCMigrate
32 clangRewriteFrontend
33 clangRewrite
34 clangCrossTU
35 clangIndex
2536 )
2637
2738else()
......@@ -50,17 +61,28 @@ else()
5061 endif()
5162 endmacro(FIND_AND_ADD_CLANG_LIB)
5263
64 FIND_AND_ADD_CLANG_LIB(clangFrontendTool)
65 FIND_AND_ADD_CLANG_LIB(clangCodeGen)
5366 FIND_AND_ADD_CLANG_LIB(clangFrontend)
5467 FIND_AND_ADD_CLANG_LIB(clangDriver)
5568 FIND_AND_ADD_CLANG_LIB(clangSerialization)
5669 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)
5773 FIND_AND_ADD_CLANG_LIB(clangAnalysis)
74 FIND_AND_ADD_CLANG_LIB(clangASTMatchers)
5875 FIND_AND_ADD_CLANG_LIB(clangAST)
5976 FIND_AND_ADD_CLANG_LIB(clangParse)
6077 FIND_AND_ADD_CLANG_LIB(clangSema)
6178 FIND_AND_ADD_CLANG_LIB(clangBasic)
6279 FIND_AND_ADD_CLANG_LIB(clangEdit)
6380 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)
6486endif()
6587
6688include(FindPackageHandleStandardArgs)
src/main.cpp+9
......@@ -32,6 +32,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {
3232 " build-lib [source] create library from source or object files\n"
3333 " build-obj [source] create object from source or assembly\n"
3434 " builtin show the source code of that @import(\"builtin\")\n"
35 " cc C compiler\n"
3536 " fmt parse files and render in canonical zig format\n"
3637 " help show this usage information\n"
3738 " id print the base64-encoded compiler id\n"
......@@ -240,6 +241,8 @@ static bool get_cache_opt(CacheOpt opt, bool default_value) {
240241 zig_unreachable();
241242}
242243
244extern "C" int ZigClang_main(int argc, char **argv);
245
243246int main(int argc, char **argv) {
244247 char *arg0 = argv[0];
245248 Error err;
......@@ -257,6 +260,12 @@ int main(int argc, char **argv) {
257260 return 0;
258261 }
259262
263 if (argc >= 2 && (strcmp(argv[1], "cc") == 0 ||
264 strcmp(argv[1], "-cc1") == 0 || strcmp(argv[1], "-cc1as") == 0))
265 {
266 return ZigClang_main(argc, argv);
267 }
268
260269 // Must be before all os.hpp function calls.
261270 os_init();
262271
src/zig_clang_cc1_main.cpp created+226
......@@ -0,0 +1,226 @@
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 CLANG_HAVE_RLIMITS
71#if defined(__linux__) && defined(__PIE__)
72static size_t getCurrentStackAllocation() {
73 // If we can't compute the current stack usage, allow for 512K of command
74 // line arguments and environment.
75 size_t Usage = 512 * 1024;
76 if (FILE *StatFile = fopen("/proc/self/stat", "r")) {
77 // We assume that the stack extends from its current address to the end of
78 // the environment space. In reality, there is another string literal (the
79 // program name) after the environment, but this is close enough (we only
80 // need to be within 100K or so).
81 unsigned long StackPtr, EnvEnd;
82 // Disable silly GCC -Wformat warning that complains about length
83 // modifiers on ignored format specifiers. We want to retain these
84 // for documentation purposes even though they have no effect.
85#if defined(__GNUC__) && !defined(__clang__)
86#pragma GCC diagnostic push
87#pragma GCC diagnostic ignored "-Wformat"
88#endif
89 if (fscanf(StatFile,
90 "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*lu %*lu %*lu %*lu %*lu "
91 "%*lu %*ld %*ld %*ld %*ld %*ld %*ld %*llu %*lu %*ld %*lu %*lu "
92 "%*lu %*lu %lu %*lu %*lu %*lu %*lu %*lu %*llu %*lu %*lu %*d %*d "
93 "%*u %*u %*llu %*lu %*ld %*lu %*lu %*lu %*lu %*lu %*lu %lu %*d",
94 &StackPtr, &EnvEnd) == 2) {
95#if defined(__GNUC__) && !defined(__clang__)
96#pragma GCC diagnostic pop
97#endif
98 Usage = StackPtr < EnvEnd ? EnvEnd - StackPtr : StackPtr - EnvEnd;
99 }
100 fclose(StatFile);
101 }
102 return Usage;
103}
104
105#include <alloca.h>
106
107LLVM_ATTRIBUTE_NOINLINE
108static void ensureStackAddressSpace() {
109 // Linux kernels prior to 4.1 will sometimes locate the heap of a PIE binary
110 // relatively close to the stack (they are only guaranteed to be 128MiB
111 // apart). This results in crashes if we happen to heap-allocate more than
112 // 128MiB before we reach our stack high-water mark.
113 //
114 // To avoid these crashes, ensure that we have sufficient virtual memory
115 // pages allocated before we start running.
116 size_t Curr = getCurrentStackAllocation();
117 const int kTargetStack = DesiredStackSize - 256 * 1024;
118 if (Curr < kTargetStack) {
119 volatile char *volatile Alloc =
120 static_cast<volatile char *>(alloca(kTargetStack - Curr));
121 Alloc[0] = 0;
122 Alloc[kTargetStack - Curr - 1] = 0;
123 }
124}
125#else
126static void ensureStackAddressSpace() {}
127#endif
128
129/// Attempt to ensure that we have at least 8MiB of usable stack space.
130static void ensureSufficientStack() {
131 struct rlimit rlim;
132 if (getrlimit(RLIMIT_STACK, &rlim) != 0)
133 return;
134
135 // Increase the soft stack limit to our desired level, if necessary and
136 // possible.
137 if (rlim.rlim_cur != RLIM_INFINITY &&
138 rlim.rlim_cur < rlim_t(DesiredStackSize)) {
139 // Try to allocate sufficient stack.
140 if (rlim.rlim_max == RLIM_INFINITY ||
141 rlim.rlim_max >= rlim_t(DesiredStackSize))
142 rlim.rlim_cur = DesiredStackSize;
143 else if (rlim.rlim_cur == rlim.rlim_max)
144 return;
145 else
146 rlim.rlim_cur = rlim.rlim_max;
147
148 if (setrlimit(RLIMIT_STACK, &rlim) != 0 ||
149 rlim.rlim_cur != DesiredStackSize)
150 return;
151 }
152
153 // We should now have a stack of size at least DesiredStackSize. Ensure
154 // that we can actually use that much, if necessary.
155 ensureStackAddressSpace();
156}
157#else
158static void ensureSufficientStack() {}
159#endif
160
161int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
162 ensureSufficientStack();
163
164 std::unique_ptr<CompilerInstance> Clang(new CompilerInstance());
165 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
166
167 // Register the support for object-file-wrapped Clang modules.
168 auto PCHOps = Clang->getPCHContainerOperations();
169 PCHOps->registerWriter(llvm::make_unique<ObjectFilePCHContainerWriter>());
170 PCHOps->registerReader(llvm::make_unique<ObjectFilePCHContainerReader>());
171
172 // Initialize targets first, so that --version shows registered targets.
173 llvm::InitializeAllTargets();
174 llvm::InitializeAllTargetMCs();
175 llvm::InitializeAllAsmPrinters();
176 llvm::InitializeAllAsmParsers();
177
178 // Buffer diagnostics from argument parsing so that we can output them using a
179 // well formed diagnostic object.
180 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
181 TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer;
182 DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagsBuffer);
183 bool Success = CompilerInvocation::CreateFromArgs(
184 Clang->getInvocation(), Argv.begin(), Argv.end(), Diags);
185
186 // Infer the builtin include path if unspecified.
187 if (Clang->getHeaderSearchOpts().UseBuiltinIncludes &&
188 Clang->getHeaderSearchOpts().ResourceDir.empty())
189 Clang->getHeaderSearchOpts().ResourceDir =
190 CompilerInvocation::GetResourcesPath(Argv0, MainAddr);
191
192 // Create the actual diagnostics engine.
193 Clang->createDiagnostics();
194 if (!Clang->hasDiagnostics())
195 return 1;
196
197 // Set an error handler, so that any LLVM backend diagnostics go through our
198 // error handler.
199 llvm::install_fatal_error_handler(LLVMErrorHandler,
200 static_cast<void*>(&Clang->getDiagnostics()));
201
202 DiagsBuffer->FlushDiagnostics(Clang->getDiagnostics());
203 if (!Success)
204 return 1;
205
206 // Execute the frontend actions.
207 Success = ExecuteCompilerInvocation(Clang.get());
208
209 // If any timers were active but haven't been destroyed yet, print their
210 // results now. This happens in -disable-free mode.
211 llvm::TimerGroup::printAll(llvm::errs());
212
213 // Our error handler depends on the Diagnostics object, which we're
214 // potentially about to delete. Uninstall the handler now so that any
215 // later errors use the default handling behavior instead.
216 llvm::remove_fatal_error_handler();
217
218 // When running with -disable-free, don't do any destruction or shutdown.
219 if (Clang->getFrontendOpts().DisableFree) {
220 BuryPointer(std::move(Clang));
221 return !Success;
222 }
223
224 return !Success;
225}
226
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+513
......@@ -0,0 +1,513 @@
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 size_t argv_offset = (strcmp(argv_[1], "-cc1") == 0 || strcmp(argv_[1], "-cc1as") == 0) ? 0 : 1;
322 SmallVector<const char *, 256> argv(argv_ + argv_offset, argv_ + argc_);
323
324 if (llvm::sys::Process::FixupStandardFileDescriptors())
325 return 1;
326
327 llvm::InitializeAllTargets();
328 auto TargetAndMode = ToolChain::getTargetAndModeFromProgramName(argv[0]);
329
330 llvm::BumpPtrAllocator A;
331 llvm::StringSaver Saver(A);
332
333 // Parse response files using the GNU syntax, unless we're in CL mode. There
334 // are two ways to put clang in CL compatibility mode: argv[0] is either
335 // clang-cl or cl, or --driver-mode=cl is on the command line. The normal
336 // command line parsing can't happen until after response file parsing, so we
337 // have to manually search for a --driver-mode=cl argument the hard way.
338 // Finally, our -cc1 tools don't care which tokenization mode we use because
339 // response files written by clang will tokenize the same way in either mode.
340 bool ClangCLMode = false;
341 if (StringRef(TargetAndMode.DriverMode).equals("--driver-mode=cl") ||
342 std::find_if(argv.begin(), argv.end(), [](const char *F) {
343 return F && strcmp(F, "--driver-mode=cl") == 0;
344 }) != argv.end()) {
345 ClangCLMode = true;
346 }
347 enum { Default, POSIX, Windows } RSPQuoting = Default;
348 for (const char *F : argv) {
349 if (strcmp(F, "--rsp-quoting=posix") == 0)
350 RSPQuoting = POSIX;
351 else if (strcmp(F, "--rsp-quoting=windows") == 0)
352 RSPQuoting = Windows;
353 }
354
355 // Determines whether we want nullptr markers in argv to indicate response
356 // files end-of-lines. We only use this for the /LINK driver argument with
357 // clang-cl.exe on Windows.
358 bool MarkEOLs = ClangCLMode;
359
360 llvm::cl::TokenizerCallback Tokenizer;
361 if (RSPQuoting == Windows || (RSPQuoting == Default && ClangCLMode))
362 Tokenizer = &llvm::cl::TokenizeWindowsCommandLine;
363 else
364 Tokenizer = &llvm::cl::TokenizeGNUCommandLine;
365
366 if (MarkEOLs && argv.size() > 1 && StringRef(argv[1]).startswith("-cc1"))
367 MarkEOLs = false;
368 llvm::cl::ExpandResponseFiles(Saver, Tokenizer, argv, MarkEOLs);
369
370 // Handle -cc1 integrated tools, even if -cc1 was expanded from a response
371 // file.
372 auto FirstArg = std::find_if(argv.begin() + 1, argv.end(),
373 [](const char *A) { return A != nullptr; });
374 if (FirstArg != argv.end() && StringRef(*FirstArg).startswith("-cc1")) {
375 // If -cc1 came from a response file, remove the EOL sentinels.
376 if (MarkEOLs) {
377 auto newEnd = std::remove(argv.begin(), argv.end(), nullptr);
378 argv.resize(newEnd - argv.begin());
379 }
380 return ExecuteCC1Tool(argv, argv[1] + 4);
381 }
382
383 bool CanonicalPrefixes = true;
384 for (int i = 1, size = argv.size(); i < size; ++i) {
385 // Skip end-of-line response file markers
386 if (argv[i] == nullptr)
387 continue;
388 if (StringRef(argv[i]) == "-no-canonical-prefixes") {
389 CanonicalPrefixes = false;
390 break;
391 }
392 }
393
394 // Handle CL and _CL_ which permits additional command line options to be
395 // prepended or appended.
396 if (ClangCLMode) {
397 // Arguments in "CL" are prepended.
398 llvm::Optional<std::string> OptCL = llvm::sys::Process::GetEnv("CL");
399 if (OptCL.hasValue()) {
400 SmallVector<const char *, 8> PrependedOpts;
401 getCLEnvVarOptions(OptCL.getValue(), Saver, PrependedOpts);
402
403 // Insert right after the program name to prepend to the argument list.
404 argv.insert(argv.begin() + 1, PrependedOpts.begin(), PrependedOpts.end());
405 }
406 // Arguments in "_CL_" are appended.
407 llvm::Optional<std::string> Opt_CL_ = llvm::sys::Process::GetEnv("_CL_");
408 if (Opt_CL_.hasValue()) {
409 SmallVector<const char *, 8> AppendedOpts;
410 getCLEnvVarOptions(Opt_CL_.getValue(), Saver, AppendedOpts);
411
412 // Insert at the end of the argument list to append.
413 argv.append(AppendedOpts.begin(), AppendedOpts.end());
414 }
415 }
416
417 std::set<std::string> SavedStrings;
418 // Handle CCC_OVERRIDE_OPTIONS, used for editing a command line behind the
419 // scenes.
420 if (const char *OverrideStr = ::getenv("CCC_OVERRIDE_OPTIONS")) {
421 // FIXME: Driver shouldn't take extra initial argument.
422 ApplyQAOverride(argv, OverrideStr, SavedStrings);
423 }
424
425 std::string Path = GetExecutablePath(argv[0], CanonicalPrefixes);
426
427 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts =
428 CreateAndPopulateDiagOpts(argv);
429
430 TextDiagnosticPrinter *DiagClient
431 = new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
432 FixupDiagPrefixExeName(DiagClient, Path);
433
434 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
435
436 DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient);
437
438 if (!DiagOpts->DiagnosticSerializationFile.empty()) {
439 auto SerializedConsumer =
440 clang::serialized_diags::create(DiagOpts->DiagnosticSerializationFile,
441 &*DiagOpts, /*MergeChildRecords=*/true);
442 Diags.setClient(new ChainedDiagnosticConsumer(
443 Diags.takeClient(), std::move(SerializedConsumer)));
444 }
445
446 ProcessWarningOptions(Diags, *DiagOpts, /*ReportDiags=*/false);
447
448 Driver TheDriver(Path, llvm::sys::getDefaultTargetTriple(), Diags);
449 SetInstallDir(argv, TheDriver, CanonicalPrefixes);
450 TheDriver.setTargetAndMode(TargetAndMode);
451
452 insertTargetAndModeArgs(TargetAndMode, argv, SavedStrings);
453
454 SetBackdoorDriverOutputsFromEnvVars(TheDriver);
455
456 std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(argv));
457 int Res = 1;
458 if (C && !C->containsError()) {
459 SmallVector<std::pair<int, const Command *>, 4> FailingCommands;
460 Res = TheDriver.ExecuteCompilation(*C, FailingCommands);
461
462 // Force a crash to test the diagnostics.
463 if (TheDriver.GenReproducer) {
464 Diags.Report(diag::err_drv_force_crash)
465 << !::getenv("FORCE_CLANG_DIAGNOSTICS_CRASH");
466
467 // Pretend that every command failed.
468 FailingCommands.clear();
469 for (const auto &J : C->getJobs())
470 if (const Command *C = dyn_cast<Command>(&J))
471 FailingCommands.push_back(std::make_pair(-1, C));
472 }
473
474 for (const auto &P : FailingCommands) {
475 int CommandRes = P.first;
476 const Command *FailingCommand = P.second;
477 if (!Res)
478 Res = CommandRes;
479
480 // If result status is < 0, then the driver command signalled an error.
481 // If result status is 70, then the driver command reported a fatal error.
482 // On Windows, abort will return an exit code of 3. In these cases,
483 // generate additional diagnostic information if possible.
484 bool DiagnoseCrash = CommandRes < 0 || CommandRes == 70;
485#ifdef _WIN32
486 DiagnoseCrash |= CommandRes == 3;
487#endif
488 if (DiagnoseCrash) {
489 TheDriver.generateCompilationDiagnostics(*C, *FailingCommand);
490 break;
491 }
492 }
493 }
494
495 Diags.getClient()->finish();
496
497 // If any timers were active but haven't been destroyed yet, print their
498 // results now. This happens in -disable-free mode.
499 llvm::TimerGroup::printAll(llvm::errs());
500
501#ifdef _WIN32
502 // Exit status should not be negative on Win32, unless abnormal termination.
503 // Once abnormal termiation was caught, negative status should not be
504 // propagated.
505 if (Res < 0)
506 Res = 1;
507#endif
508
509 // If we have multiple failing commands, we return the result of the first
510 // failing command.
511 return Res;
512}
513