Arg *ArgList::getLastArg(OptSpecifier Id0, OptSpecifier Id1, OptSpecifier Id2) const { Arg *Res = 0; Arg *A0 = getLastArgNoClaim(Id0); Arg *A1 = getLastArgNoClaim(Id1); Arg *A2 = getLastArgNoClaim(Id2); int A0Idx = A0 ? (int) A0->getIndex() : -1; int A1Idx = A1 ? (int) A1->getIndex() : -1; int A2Idx = A2 ? (int) A2->getIndex() : -1; if (A0Idx > A1Idx) { if (A0Idx > A2Idx) Res = A0; else if (A2Idx != -1) Res = A2; } else { if (A1Idx > A2Idx) Res = A1; else if (A2Idx != -1) Res = A2; } if (Res) Res->claim(); return Res; }
Arg *ArgList::getLastArg(OptSpecifier Id) const { Arg *Res = nullptr; for (const_iterator it = begin(), ie = end(); it != ie; ++it) { if ((*it)->getOption().matches(Id)) { Res = *it; Res->claim(); } } return Res; }
Arg *ArgList::getLastArg(OptSpecifier Id0, OptSpecifier Id1, OptSpecifier Id2, OptSpecifier Id3) const { Arg *Res = 0; for (const_iterator it = begin(), ie = end(); it != ie; ++it) { if ((*it)->getOption().matches(Id0) || (*it)->getOption().matches(Id1) || (*it)->getOption().matches(Id2) || (*it)->getOption().matches(Id3)) { Res = *it; Res->claim(); } } return Res; }
void Driver::BuildActions(const ArgList &Args, ActionList &Actions) const { llvm::PrettyStackTraceString CrashInfo("Building compilation actions"); // Start by constructing the list of inputs and their types. // Track the current user specified (-x) input. We also explicitly // track the argument used to set the type; we only want to claim // the type when we actually use it, so we warn about unused -x // arguments. types::ID InputType = types::TY_Nothing; Arg *InputTypeArg = 0; llvm::SmallVector<std::pair<types::ID, const Arg*>, 16> Inputs; for (ArgList::const_iterator it = Args.begin(), ie = Args.end(); it != ie; ++it) { Arg *A = *it; if (isa<InputOption>(A->getOption())) { const char *Value = A->getValue(Args); types::ID Ty = types::TY_INVALID; // Infer the input type if necessary. if (InputType == types::TY_Nothing) { // If there was an explicit arg for this, claim it. if (InputTypeArg) InputTypeArg->claim(); // stdin must be handled specially. if (memcmp(Value, "-", 2) == 0) { // If running with -E, treat as a C input (this changes the // builtin macros, for example). This may be overridden by // -ObjC below. // // Otherwise emit an error but still use a valid type to // avoid spurious errors (e.g., no inputs). if (!Args.hasArg(options::OPT_E, false)) Diag(clang::diag::err_drv_unknown_stdin_type); Ty = types::TY_C; } else { // Otherwise lookup by extension, and fallback to ObjectType // if not found. We use a host hook here because Darwin at // least has its own idea of what .s is. if (const char *Ext = strrchr(Value, '.')) Ty = Host->lookupTypeForExtension(Ext + 1); if (Ty == types::TY_INVALID) Ty = types::TY_Object; } // -ObjC and -ObjC++ override the default language, but only for "source // files". We just treat everything that isn't a linker input as a // source file. // // FIXME: Clean this up if we move the phase sequence into the type. if (Ty != types::TY_Object) { if (Args.hasArg(options::OPT_ObjC)) Ty = types::TY_ObjC; else if (Args.hasArg(options::OPT_ObjCXX)) Ty = types::TY_ObjCXX; } } else { assert(InputTypeArg && "InputType set w/o InputTypeArg"); InputTypeArg->claim(); Ty = InputType; } // Check that the file exists. It isn't clear this is worth // doing, since the tool presumably does this anyway, and this // just adds an extra stat to the equation, but this is gcc // compatible. if (memcmp(Value, "-", 2) != 0 && !llvm::sys::Path(Value).exists()) Diag(clang::diag::err_drv_no_such_file) << A->getValue(Args); else Inputs.push_back(std::make_pair(Ty, A)); } else if (A->getOption().isLinkerInput()) { // Just treat as object type, we could make a special type for // this if necessary. Inputs.push_back(std::make_pair(types::TY_Object, A)); } else if (A->getOption().getId() == options::OPT_x) { InputTypeArg = A; InputType = types::lookupTypeForTypeSpecifier(A->getValue(Args)); // Follow gcc behavior and treat as linker input for invalid -x // options. Its not clear why we shouldn't just revert to // unknown; but this isn't very important, we might as well be // bug comatible. if (!InputType) { Diag(clang::diag::err_drv_unknown_language) << A->getValue(Args); InputType = types::TY_Object; } } } if (!SuppressMissingInputWarning && Inputs.empty()) { Diag(clang::diag::err_drv_no_input_files); return; } // Determine which compilation mode we are in. We look for options // which affect the phase, starting with the earliest phases, and // record which option we used to determine the final phase. Arg *FinalPhaseArg = 0; phases::ID FinalPhase; // -{E,M,MM} only run the preprocessor. if ((FinalPhaseArg = Args.getLastArg(options::OPT_E)) || (FinalPhaseArg = Args.getLastArg(options::OPT_M)) || (FinalPhaseArg = Args.getLastArg(options::OPT_MM))) { FinalPhase = phases::Preprocess; // -{fsyntax-only,-analyze,emit-llvm,S} only run up to the compiler. } else if ((FinalPhaseArg = Args.getLastArg(options::OPT_fsyntax_only)) || (FinalPhaseArg = Args.getLastArg(options::OPT__analyze, options::OPT__analyze_auto)) || (FinalPhaseArg = Args.getLastArg(options::OPT_S))) { FinalPhase = phases::Compile; // -c only runs up to the assembler. } else if ((FinalPhaseArg = Args.getLastArg(options::OPT_c))) { FinalPhase = phases::Assemble; // Otherwise do everything. } else FinalPhase = phases::Link; // Reject -Z* at the top level, these options should never have been // exposed by gcc. if (Arg *A = Args.getLastArg(options::OPT_Z_Joined)) Diag(clang::diag::err_drv_use_of_Z_option) << A->getAsString(Args); // Construct the actions to perform. ActionList LinkerInputs; for (unsigned i = 0, e = Inputs.size(); i != e; ++i) { types::ID InputType = Inputs[i].first; const Arg *InputArg = Inputs[i].second; unsigned NumSteps = types::getNumCompilationPhases(InputType); assert(NumSteps && "Invalid number of steps!"); // If the first step comes after the final phase we are doing as // part of this compilation, warn the user about it. phases::ID InitialPhase = types::getCompilationPhase(InputType, 0); if (InitialPhase > FinalPhase) { // Claim here to avoid the more general unused warning. InputArg->claim(); Diag(clang::diag::warn_drv_input_file_unused) << InputArg->getAsString(Args) << getPhaseName(InitialPhase) << FinalPhaseArg->getOption().getName(); continue; } // Build the pipeline for this file. Action *Current = new InputAction(*InputArg, InputType); for (unsigned i = 0; i != NumSteps; ++i) { phases::ID Phase = types::getCompilationPhase(InputType, i); // We are done if this step is past what the user requested. if (Phase > FinalPhase) break; // Queue linker inputs. if (Phase == phases::Link) { assert(i + 1 == NumSteps && "linking must be final compilation step."); LinkerInputs.push_back(Current); Current = 0; break; } // Some types skip the assembler phase (e.g., llvm-bc), but we // can't encode this in the steps because the intermediate type // depends on arguments. Just special case here. if (Phase == phases::Assemble && Current->getType() != types::TY_PP_Asm) continue; // Otherwise construct the appropriate action. Current = ConstructPhaseAction(Args, Phase, Current); if (Current->getType() == types::TY_Nothing) break; } // If we ended with something, add to the output list. if (Current) Actions.push_back(Current); } // Add a link action if necessary. if (!LinkerInputs.empty()) Actions.push_back(new LinkJobAction(LinkerInputs, types::TY_Image)); }
void Driver::BuildUniversalActions(const ArgList &Args, ActionList &Actions) const { llvm::PrettyStackTraceString CrashInfo("Building actions for universal build"); // Collect the list of architectures. Duplicates are allowed, but // should only be handled once (in the order seen). llvm::StringSet<> ArchNames; llvm::SmallVector<const char *, 4> Archs; for (ArgList::const_iterator it = Args.begin(), ie = Args.end(); it != ie; ++it) { Arg *A = *it; if (A->getOption().getId() == options::OPT_arch) { const char *Name = A->getValue(Args); // FIXME: We need to handle canonicalization of the specified // arch? A->claim(); if (ArchNames.insert(Name)) Archs.push_back(Name); } } // When there is no explicit arch for this platform, make sure we // still bind the architecture (to the default) so that -Xarch_ is // handled correctly. if (!Archs.size()) Archs.push_back(0); // FIXME: We killed off some others but these aren't yet detected in // a functional manner. If we added information to jobs about which // "auxiliary" files they wrote then we could detect the conflict // these cause downstream. if (Archs.size() > 1) { // No recovery needed, the point of this is just to prevent // overwriting the same files. if (const Arg *A = Args.getLastArg(options::OPT_save_temps)) Diag(clang::diag::err_drv_invalid_opt_with_multiple_archs) << A->getAsString(Args); } ActionList SingleActions; BuildActions(Args, SingleActions); // Add in arch binding and lipo (if necessary) for every top level // action. for (unsigned i = 0, e = SingleActions.size(); i != e; ++i) { Action *Act = SingleActions[i]; // Make sure we can lipo this kind of output. If not (and it is an // actual output) then we disallow, since we can't create an // output file with the right name without overwriting it. We // could remove this oddity by just changing the output names to // include the arch, which would also fix // -save-temps. Compatibility wins for now. if (Archs.size() > 1 && !types::canLipoType(Act->getType())) Diag(clang::diag::err_drv_invalid_output_with_multiple_archs) << types::getTypeName(Act->getType()); ActionList Inputs; for (unsigned i = 0, e = Archs.size(); i != e; ++i) Inputs.push_back(new BindArchAction(Act, Archs[i])); // Lipo if necessary, We do it this way because we need to set the // arch flag so that -Xarch_ gets overwritten. if (Inputs.size() == 1 || Act->getType() == types::TY_Nothing) Actions.append(Inputs.begin(), Inputs.end()); else Actions.push_back(new LipoJobAction(Inputs, Act->getType())); } }
Arg *ArgList::getLastArg(OptSpecifier Id) const { Arg *A = getLastArgNoClaim(Id); if (A) A->claim(); return A; }