void ananas::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { const ToolChain &ToolChain = getToolChain(); const Driver &D = ToolChain.getDriver(); ArgStringList CmdArgs; // Silence warning for "clang -g foo.o -o foo" Args.ClaimAllArgs(options::OPT_g_Group); // and "clang -emit-llvm foo.o -o foo" Args.ClaimAllArgs(options::OPT_emit_llvm); // and for "clang -w foo.o -o foo". Other warning options are already // handled somewhere else. Args.ClaimAllArgs(options::OPT_w); if (!D.SysRoot.empty()) CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); // Ananas only supports static linkage for now. CmdArgs.push_back("-Bstatic"); if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); } else { assert(Output.isNothing() && "Invalid output."); } if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o"))); CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o"))); CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtbegin.o"))); } Args.AddAllArgs(CmdArgs, options::OPT_L); ToolChain.AddFilePathLibArgs(Args, CmdArgs); Args.AddAllArgs(CmdArgs, {options::OPT_T_Group, options::OPT_e, options::OPT_s, options::OPT_t, options::OPT_Z_Flag, options::OPT_r}); if (D.isUsingLTO()) AddGoldPlugin(ToolChain, Args, CmdArgs, D.getLTOMode() == LTOK_Thin, D); AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); if (ToolChain.ShouldLinkCXXStdlib(Args)) ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) CmdArgs.push_back("-lc"); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o"))); CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o"))); } const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); }
// Claim options we don't want to warn if they are unused. We do this for // options that build systems might add but are unused when assembling or only // running the preprocessor for example. void tools::claimNoWarnArgs(const ArgList &Args) { // Don't warn about unused -f(no-)?lto. This can happen when we're // preprocessing, precompiling or assembling. Args.ClaimAllArgs(options::OPT_flto_EQ); Args.ClaimAllArgs(options::OPT_flto); Args.ClaimAllArgs(options::OPT_fno_lto); }
void tools::SHAVE::Compiler::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { ArgStringList CmdArgs; assert(Inputs.size() == 1); const InputInfo &II = Inputs[0]; assert(II.getType() == types::TY_C || II.getType() == types::TY_CXX || II.getType() == types::TY_PP_CXX); if (JA.getKind() == Action::PreprocessJobClass) { Args.ClaimAllArgs(); CmdArgs.push_back("-E"); } else { assert(Output.getType() == types::TY_PP_Asm); // Require preprocessed asm. CmdArgs.push_back("-S"); CmdArgs.push_back("-fno-exceptions"); // Always do this even if unspecified. } CmdArgs.push_back("-DMYRIAD2"); // Append all -I, -iquote, -isystem paths, defines/undefines, 'f' // flags, 'g' flags, 'M' flags, optimize flags, warning options, // mcpu flags, mllvm flags, and Xclang flags. // These are spelled the same way in clang and moviCompile. Args.AddAllArgsExcept( CmdArgs, {options::OPT_I_Group, options::OPT_clang_i_Group, options::OPT_std_EQ, options::OPT_D, options::OPT_U, options::OPT_f_Group, options::OPT_f_clang_Group, options::OPT_g_Group, options::OPT_M_Group, options::OPT_O_Group, options::OPT_W_Group, options::OPT_mcpu_EQ, options::OPT_mllvm, options::OPT_Xclang}, {options::OPT_fno_split_dwarf_inlining}); Args.hasArg(options::OPT_fno_split_dwarf_inlining); // Claim it if present. // If we're producing a dependency file, and assembly is the final action, // then the name of the target in the dependency file should be the '.o' // file, not the '.s' file produced by this step. For example, instead of // /tmp/mumble.s: mumble.c .../someheader.h // the filename on the lefthand side should be "mumble.o" if (Args.getLastArg(options::OPT_MF) && !Args.getLastArg(options::OPT_MT) && C.getActions().size() == 1 && C.getActions()[0]->getKind() == Action::AssembleJobClass) { Arg *A = Args.getLastArg(options::OPT_o); if (A) { CmdArgs.push_back("-MT"); CmdArgs.push_back(Args.MakeArgString(A->getValue())); } } CmdArgs.push_back(II.getFilename()); CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); std::string Exec = Args.MakeArgString(getToolChain().GetProgramPath("moviCompile")); C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Exec), CmdArgs, Inputs)); }
static bool ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, DiagnosticEngine &Diags) { using namespace options; if (const Arg *A = Args.getLastArg(OPT_debug_crash_Group)) { Option Opt = A->getOption(); if (Opt.matches(OPT_debug_assert_immediately)) { debugFailWithAssertion(); } else if (Opt.matches(OPT_debug_crash_immediately)) { debugFailWithCrash(); } else if (Opt.matches(OPT_debug_assert_after_parse)) { // Set in FrontendOptions Opts.CrashMode = FrontendOptions::DebugCrashMode::AssertAfterParse; } else if (Opt.matches(OPT_debug_crash_after_parse)) { // Set in FrontendOptions Opts.CrashMode = FrontendOptions::DebugCrashMode::CrashAfterParse; } else { llvm_unreachable("Unknown debug_crash_Group option!"); } } if (const Arg *A = Args.getLastArg(OPT_dump_api_path)) { Opts.DumpAPIPath = A->getValue(); } Opts.EmitVerboseSIL |= Args.hasArg(OPT_emit_verbose_sil); Opts.EmitSortedSIL |= Args.hasArg(OPT_emit_sorted_sil); Opts.DelayedFunctionBodyParsing |= Args.hasArg(OPT_delayed_function_body_parsing); Opts.EnableTesting |= Args.hasArg(OPT_enable_testing); Opts.EnableResilience |= Args.hasArg(OPT_enable_resilience); Opts.PrintStats |= Args.hasArg(OPT_print_stats); Opts.PrintClangStats |= Args.hasArg(OPT_print_clang_stats); Opts.DebugTimeFunctionBodies |= Args.hasArg(OPT_debug_time_function_bodies); Opts.DebugTimeCompilation |= Args.hasArg(OPT_debug_time_compilation); Opts.PlaygroundTransform |= Args.hasArg(OPT_playground); if (Args.hasArg(OPT_disable_playground_transform)) Opts.PlaygroundTransform = false; Opts.PlaygroundHighPerformance |= Args.hasArg(OPT_playground_high_performance); if (const Arg *A = Args.getLastArg(OPT_help, OPT_help_hidden)) { if (A->getOption().matches(OPT_help)) { Opts.PrintHelp = true; } else if (A->getOption().matches(OPT_help_hidden)) { Opts.PrintHelpHidden = true; } else { llvm_unreachable("Unknown help option parsed"); } } if (const Arg *A = Args.getLastArg(OPT_filelist)) { const Arg *primaryFileArg = Args.getLastArg(OPT_primary_file); auto primaryFileIndex = readFileList(Opts.InputFilenames, A, primaryFileArg); if (primaryFileArg) Opts.PrimaryInput = SelectedInput(primaryFileIndex); assert(!Args.hasArg(OPT_INPUT) && "mixing -filelist with inputs"); } else { for (const Arg *A : make_range(Args.filtered_begin(OPT_INPUT, OPT_primary_file), Args.filtered_end())) { if (A->getOption().matches(OPT_INPUT)) { Opts.InputFilenames.push_back(A->getValue()); } else if (A->getOption().matches(OPT_primary_file)) { Opts.PrimaryInput = SelectedInput(Opts.InputFilenames.size()); Opts.InputFilenames.push_back(A->getValue()); } else { llvm_unreachable("Unknown input-related argument!"); } } } Opts.ParseStdlib |= Args.hasArg(OPT_parse_stdlib); // Determine what the user has asked the frontend to do. FrontendOptions::ActionType &Action = Opts.RequestedAction; if (const Arg *A = Args.getLastArg(OPT_modes_Group)) { Option Opt = A->getOption(); if (Opt.matches(OPT_emit_object)) { Action = FrontendOptions::EmitObject; } else if (Opt.matches(OPT_emit_assembly)) { Action = FrontendOptions::EmitAssembly; } else if (Opt.matches(OPT_emit_ir)) { Action = FrontendOptions::EmitIR; } else if (Opt.matches(OPT_emit_bc)) { Action = FrontendOptions::EmitBC; } else if (Opt.matches(OPT_emit_sil)) { Action = FrontendOptions::EmitSIL; } else if (Opt.matches(OPT_emit_silgen)) { Action = FrontendOptions::EmitSILGen; } else if (Opt.matches(OPT_emit_sib)) { Action = FrontendOptions::EmitSIB; } else if (Opt.matches(OPT_emit_sibgen)) { Action = FrontendOptions::EmitSIBGen; } else if (Opt.matches(OPT_parse)) { Action = FrontendOptions::Parse; } else if (Opt.matches(OPT_dump_parse)) { Action = FrontendOptions::DumpParse; } else if (Opt.matches(OPT_dump_ast)) { Action = FrontendOptions::DumpAST; } else if (Opt.matches(OPT_dump_type_refinement_contexts)) { Action = FrontendOptions::DumpTypeRefinementContexts; } else if (Opt.matches(OPT_dump_interface_hash)) { Action = FrontendOptions::DumpInterfaceHash; } else if (Opt.matches(OPT_print_ast)) { Action = FrontendOptions::PrintAST; } else if (Opt.matches(OPT_repl) || Opt.matches(OPT_deprecated_integrated_repl)) { Action = FrontendOptions::REPL; } else if (Opt.matches(OPT_interpret)) { Action = FrontendOptions::Immediate; } else { llvm_unreachable("Unhandled mode option"); } } else { // We don't have a mode, so determine a default. if (Args.hasArg(OPT_emit_module, OPT_emit_module_path)) { // We've been told to emit a module, but have no other mode indicators. // As a result, put the frontend into EmitModuleOnly mode. // (Setting up module output will be handled below.) Action = FrontendOptions::EmitModuleOnly; } } if (Opts.RequestedAction == FrontendOptions::Immediate && Opts.PrimaryInput.hasValue()) { Diags.diagnose(SourceLoc(), diag::error_immediate_mode_primary_file); return true; } bool TreatAsSIL = Args.hasArg(OPT_parse_sil); if (!TreatAsSIL && Opts.InputFilenames.size() == 1) { // If we have exactly one input filename, and its extension is "sil", // treat the input as SIL. StringRef Input(Opts.InputFilenames[0]); TreatAsSIL = llvm::sys::path::extension(Input).endswith(SIL_EXTENSION); } else if (Opts.PrimaryInput.hasValue() && Opts.PrimaryInput->isFilename()) { // If we have a primary input and it's a filename with extension "sil", // treat the input as SIL. StringRef Input(Opts.InputFilenames[Opts.PrimaryInput->Index]); TreatAsSIL = llvm::sys::path::extension(Input).endswith(SIL_EXTENSION); } // If we have exactly one input filename, and its extension is "bc" or "ll", // treat the input as LLVM_IR. bool TreatAsLLVM = false; if (Opts.InputFilenames.size() == 1) { StringRef Input(Opts.InputFilenames[0]); TreatAsLLVM = llvm::sys::path::extension(Input).endswith(LLVM_BC_EXTENSION) || llvm::sys::path::extension(Input).endswith(LLVM_IR_EXTENSION); } if (Opts.RequestedAction == FrontendOptions::REPL) { if (!Opts.InputFilenames.empty()) { Diags.diagnose(SourceLoc(), diag::error_repl_requires_no_input_files); return true; } } else if (TreatAsSIL && Opts.PrimaryInput.hasValue()) { // If we have the SIL as our primary input, we can waive the one file // requirement as long as all the other inputs are SIBs. if (Opts.PrimaryInput.hasValue()) { for (unsigned i = 0, e = Opts.InputFilenames.size(); i != e; ++i) { if (i == Opts.PrimaryInput->Index) continue; StringRef File(Opts.InputFilenames[i]); if (!llvm::sys::path::extension(File).endswith(SIB_EXTENSION)) { Diags.diagnose(SourceLoc(), diag::error_mode_requires_one_sil_multi_sib); return true; } } } } else if (TreatAsSIL) { if (Opts.InputFilenames.size() != 1) { Diags.diagnose(SourceLoc(), diag::error_mode_requires_one_input_file); return true; } } else if (Opts.RequestedAction != FrontendOptions::NoneAction) { if (Opts.InputFilenames.empty()) { Diags.diagnose(SourceLoc(), diag::error_mode_requires_an_input_file); return true; } } if (Opts.RequestedAction == FrontendOptions::Immediate) { assert(!Opts.InputFilenames.empty()); Opts.ImmediateArgv.push_back(Opts.InputFilenames[0]); // argv[0] if (const Arg *A = Args.getLastArg(OPT__DASH_DASH)) { for (unsigned i = 0, e = A->getNumValues(); i != e; ++i) { Opts.ImmediateArgv.push_back(A->getValue(i)); } } } if (TreatAsSIL) Opts.InputKind = InputFileKind::IFK_SIL; else if (TreatAsLLVM) Opts.InputKind = InputFileKind::IFK_LLVM_IR; else if (Args.hasArg(OPT_parse_as_library)) Opts.InputKind = InputFileKind::IFK_Swift_Library; else if (Action == FrontendOptions::REPL) Opts.InputKind = InputFileKind::IFK_Swift_REPL; else Opts.InputKind = InputFileKind::IFK_Swift; if (const Arg *A = Args.getLastArg(OPT_output_filelist)) { readFileList(Opts.OutputFilenames, A); assert(!Args.hasArg(OPT_o) && "don't use -o with -output-filelist"); } else { Opts.OutputFilenames = Args.getAllArgValues(OPT_o); } bool UserSpecifiedModuleName = false; { const Arg *A = Args.getLastArg(OPT_module_name); StringRef ModuleName = Opts.ModuleName; if (A) { ModuleName = A->getValue(); UserSpecifiedModuleName = true; } else if (ModuleName.empty()) { // The user did not specify a module name, so determine a default fallback // based on other options. // Note: this code path will only be taken when running the frontend // directly; the driver should always pass -module-name when invoking the // frontend. if (Opts.RequestedAction == FrontendOptions::REPL) { // Default to a module named "REPL" if we're in REPL mode. ModuleName = "REPL"; } else if (!Opts.InputFilenames.empty()) { StringRef OutputFilename = Opts.getSingleOutputFilename(); if (OutputFilename.empty() || OutputFilename == "-" || llvm::sys::fs::is_directory(OutputFilename)) { ModuleName = Opts.InputFilenames[0]; } else { ModuleName = OutputFilename; } ModuleName = llvm::sys::path::stem(ModuleName); } } if (!Lexer::isIdentifier(ModuleName) || (ModuleName == STDLIB_NAME && !Opts.ParseStdlib)) { if (!Opts.actionHasOutput() || (Opts.InputKind == InputFileKind::IFK_Swift && Opts.InputFilenames.size() == 1)) { ModuleName = "main"; } else { auto DID = (ModuleName == STDLIB_NAME) ? diag::error_stdlib_module_name : diag::error_bad_module_name; Diags.diagnose(SourceLoc(), DID, ModuleName, A == nullptr); ModuleName = "__bad__"; } } Opts.ModuleName = ModuleName; } if (Opts.OutputFilenames.empty() || llvm::sys::fs::is_directory(Opts.getSingleOutputFilename())) { // No output filename was specified, or an output directory was specified. // Determine the correct output filename. // Note: this should typically only be used when invoking the frontend // directly, as the driver will always pass -o with an appropriate filename // if output is required for the requested action. StringRef Suffix; switch (Opts.RequestedAction) { case FrontendOptions::NoneAction: break; case FrontendOptions::Parse: case FrontendOptions::DumpParse: case FrontendOptions::DumpInterfaceHash: case FrontendOptions::DumpAST: case FrontendOptions::PrintAST: case FrontendOptions::DumpTypeRefinementContexts: // Textual modes. Opts.setSingleOutputFilename("-"); break; case FrontendOptions::EmitSILGen: case FrontendOptions::EmitSIL: { if (Opts.OutputFilenames.empty()) Opts.setSingleOutputFilename("-"); else Suffix = SIL_EXTENSION; break; } case FrontendOptions::EmitSIBGen: case FrontendOptions::EmitSIB: Suffix = SIB_EXTENSION; break; case FrontendOptions::EmitModuleOnly: Suffix = SERIALIZED_MODULE_EXTENSION; break; case FrontendOptions::Immediate: case FrontendOptions::REPL: // These modes have no frontend-generated output. Opts.OutputFilenames.clear(); break; case FrontendOptions::EmitAssembly: { if (Opts.OutputFilenames.empty()) Opts.setSingleOutputFilename("-"); else Suffix = "s"; break; } case FrontendOptions::EmitIR: { if (Opts.OutputFilenames.empty()) Opts.setSingleOutputFilename("-"); else Suffix = "ll"; break; } case FrontendOptions::EmitBC: { Suffix = "bc"; break; } case FrontendOptions::EmitObject: Suffix = "o"; break; } if (!Suffix.empty()) { // We need to deduce a file name. // First, if we're reading from stdin and we don't have a directory, // output to stdout. if (Opts.InputFilenames.size() == 1 && Opts.InputFilenames[0] == "-" && Opts.OutputFilenames.empty()) Opts.setSingleOutputFilename("-"); else { // We have a suffix, so determine an appropriate name. llvm::SmallString<128> Path(Opts.getSingleOutputFilename()); StringRef BaseName; if (Opts.PrimaryInput.hasValue() && Opts.PrimaryInput->isFilename()) { unsigned Index = Opts.PrimaryInput->Index; BaseName = llvm::sys::path::stem(Opts.InputFilenames[Index]); } else if (!UserSpecifiedModuleName && Opts.InputFilenames.size() == 1) { BaseName = llvm::sys::path::stem(Opts.InputFilenames[0]); } else { BaseName = Opts.ModuleName; } llvm::sys::path::append(Path, BaseName); llvm::sys::path::replace_extension(Path, Suffix); Opts.setSingleOutputFilename(Path.str()); } } if (Opts.OutputFilenames.empty()) { if (Opts.RequestedAction != FrontendOptions::REPL && Opts.RequestedAction != FrontendOptions::Immediate && Opts.RequestedAction != FrontendOptions::NoneAction) { Diags.diagnose(SourceLoc(), diag::error_no_output_filename_specified); return true; } } else if (Opts.getSingleOutputFilename() != "-" && llvm::sys::fs::is_directory(Opts.getSingleOutputFilename())) { Diags.diagnose(SourceLoc(), diag::error_implicit_output_file_is_directory, Opts.getSingleOutputFilename()); return true; } } auto determineOutputFilename = [&](std::string &output, OptSpecifier optWithoutPath, OptSpecifier optWithPath, const char *extension, bool useMainOutput) { if (const Arg *A = Args.getLastArg(optWithPath)) { Args.ClaimAllArgs(optWithoutPath); output = A->getValue(); return; } if (!Args.hasArg(optWithoutPath)) return; if (useMainOutput && !Opts.OutputFilenames.empty()) { output = Opts.getSingleOutputFilename(); return; } if (!output.empty()) return; StringRef OriginalPath; if (!Opts.OutputFilenames.empty() && Opts.getSingleOutputFilename() != "-") // Put the serialized diagnostics file next to the output file. OriginalPath = Opts.getSingleOutputFilename(); else if (Opts.PrimaryInput.hasValue() && Opts.PrimaryInput->isFilename()) // We have a primary input, so use that as the basis for the name of the // serialized diagnostics file. OriginalPath = llvm::sys::path::filename( Opts.InputFilenames[Opts.PrimaryInput->Index]); else // We don't have any better indication of name, so fall back on the // module name. OriginalPath = Opts.ModuleName; llvm::SmallString<128> Path(OriginalPath); llvm::sys::path::replace_extension(Path, extension); output = Path.str(); }; determineOutputFilename(Opts.DependenciesFilePath, OPT_emit_dependencies, OPT_emit_dependencies_path, "d", false); determineOutputFilename(Opts.ReferenceDependenciesFilePath, OPT_emit_reference_dependencies, OPT_emit_reference_dependencies_path, "swiftdeps", false); determineOutputFilename(Opts.SerializedDiagnosticsPath, OPT_serialize_diagnostics, OPT_serialize_diagnostics_path, "dia", false); determineOutputFilename(Opts.ObjCHeaderOutputPath, OPT_emit_objc_header, OPT_emit_objc_header_path, "h", false); if (const Arg *A = Args.getLastArg(OPT_emit_fixits_path)) { Opts.FixitsOutputPath = A->getValue(); } bool IsSIB = Opts.RequestedAction == FrontendOptions::EmitSIB || Opts.RequestedAction == FrontendOptions::EmitSIBGen; bool canUseMainOutputForModule = Opts.RequestedAction == FrontendOptions::EmitModuleOnly || IsSIB; auto ext = IsSIB ? SIB_EXTENSION : SERIALIZED_MODULE_EXTENSION; auto sibOpt = Opts.RequestedAction == FrontendOptions::EmitSIB ? OPT_emit_sib : OPT_emit_sibgen; determineOutputFilename(Opts.ModuleOutputPath, IsSIB ? sibOpt : OPT_emit_module, OPT_emit_module_path, ext, canUseMainOutputForModule); determineOutputFilename(Opts.ModuleDocOutputPath, OPT_emit_module_doc, OPT_emit_module_doc_path, SERIALIZED_MODULE_DOC_EXTENSION, false); if (!Opts.DependenciesFilePath.empty()) { switch (Opts.RequestedAction) { case FrontendOptions::NoneAction: case FrontendOptions::DumpParse: case FrontendOptions::DumpInterfaceHash: case FrontendOptions::DumpAST: case FrontendOptions::PrintAST: case FrontendOptions::DumpTypeRefinementContexts: case FrontendOptions::Immediate: case FrontendOptions::REPL: Diags.diagnose(SourceLoc(), diag::error_mode_cannot_emit_dependencies); return true; case FrontendOptions::Parse: case FrontendOptions::EmitModuleOnly: case FrontendOptions::EmitSILGen: case FrontendOptions::EmitSIL: case FrontendOptions::EmitSIBGen: case FrontendOptions::EmitSIB: case FrontendOptions::EmitIR: case FrontendOptions::EmitBC: case FrontendOptions::EmitAssembly: case FrontendOptions::EmitObject: break; } } if (!Opts.ObjCHeaderOutputPath.empty()) { switch (Opts.RequestedAction) { case FrontendOptions::NoneAction: case FrontendOptions::DumpParse: case FrontendOptions::DumpInterfaceHash: case FrontendOptions::DumpAST: case FrontendOptions::PrintAST: case FrontendOptions::DumpTypeRefinementContexts: case FrontendOptions::Immediate: case FrontendOptions::REPL: Diags.diagnose(SourceLoc(), diag::error_mode_cannot_emit_header); return true; case FrontendOptions::Parse: case FrontendOptions::EmitModuleOnly: case FrontendOptions::EmitSILGen: case FrontendOptions::EmitSIL: case FrontendOptions::EmitSIBGen: case FrontendOptions::EmitSIB: case FrontendOptions::EmitIR: case FrontendOptions::EmitBC: case FrontendOptions::EmitAssembly: case FrontendOptions::EmitObject: break; } } if (!Opts.ModuleOutputPath.empty() || !Opts.ModuleDocOutputPath.empty()) { switch (Opts.RequestedAction) { case FrontendOptions::NoneAction: case FrontendOptions::Parse: case FrontendOptions::DumpParse: case FrontendOptions::DumpInterfaceHash: case FrontendOptions::DumpAST: case FrontendOptions::PrintAST: case FrontendOptions::DumpTypeRefinementContexts: case FrontendOptions::EmitSILGen: case FrontendOptions::Immediate: case FrontendOptions::REPL: if (!Opts.ModuleOutputPath.empty()) Diags.diagnose(SourceLoc(), diag::error_mode_cannot_emit_module); else Diags.diagnose(SourceLoc(), diag::error_mode_cannot_emit_module_doc); return true; case FrontendOptions::EmitModuleOnly: case FrontendOptions::EmitSIL: case FrontendOptions::EmitSIBGen: case FrontendOptions::EmitSIB: case FrontendOptions::EmitIR: case FrontendOptions::EmitBC: case FrontendOptions::EmitAssembly: case FrontendOptions::EmitObject: break; } } if (const Arg *A = Args.getLastArg(OPT_module_link_name)) { Opts.ModuleLinkName = A->getValue(); } Opts.AlwaysSerializeDebuggingOptions |= Args.hasArg(OPT_serialize_debugging_options); Opts.EnableSourceImport |= Args.hasArg(OPT_enable_source_import); Opts.ImportUnderlyingModule |= Args.hasArg(OPT_import_underlying_module); Opts.SILSerializeAll |= Args.hasArg(OPT_sil_serialize_all); if (const Arg *A = Args.getLastArg(OPT_import_objc_header)) { Opts.ImplicitObjCHeaderPath = A->getValue(); Opts.SerializeBridgingHeader |= !Opts.PrimaryInput && !Opts.ModuleOutputPath.empty(); } for (const Arg *A : make_range(Args.filtered_begin(OPT_import_module), Args.filtered_end())) { Opts.ImplicitImportModuleNames.push_back(A->getValue()); } for (const Arg *A : make_range(Args.filtered_begin(OPT_Xllvm), Args.filtered_end())) { Opts.LLVMArgs.push_back(A->getValue()); } return false; }
void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { const toolchains::FreeBSD &ToolChain = static_cast<const toolchains::FreeBSD &>(getToolChain()); const Driver &D = ToolChain.getDriver(); const llvm::Triple::ArchType Arch = ToolChain.getArch(); const bool IsPIE = !Args.hasArg(options::OPT_shared) && (Args.hasArg(options::OPT_pie) || ToolChain.isPIEDefault()); ArgStringList CmdArgs; // Silence warning for "clang -g foo.o -o foo" Args.ClaimAllArgs(options::OPT_g_Group); // and "clang -emit-llvm foo.o -o foo" Args.ClaimAllArgs(options::OPT_emit_llvm); // and for "clang -w foo.o -o foo". Other warning options are already // handled somewhere else. Args.ClaimAllArgs(options::OPT_w); if (!D.SysRoot.empty()) CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); if (IsPIE) CmdArgs.push_back("-pie"); CmdArgs.push_back("--eh-frame-hdr"); if (Args.hasArg(options::OPT_static)) { CmdArgs.push_back("-Bstatic"); } else { if (Args.hasArg(options::OPT_rdynamic)) CmdArgs.push_back("-export-dynamic"); if (Args.hasArg(options::OPT_shared)) { CmdArgs.push_back("-Bshareable"); } else { CmdArgs.push_back("-dynamic-linker"); CmdArgs.push_back("/libexec/ld-elf.so.1"); } if (ToolChain.getTriple().getOSMajorVersion() >= 9) { if (Arch == llvm::Triple::arm || Arch == llvm::Triple::sparc || Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64) { CmdArgs.push_back("--hash-style=both"); } } CmdArgs.push_back("--enable-new-dtags"); } // Explicitly set the linker emulation for platforms that might not // be the default emulation for the linker. switch (Arch) { case llvm::Triple::x86: CmdArgs.push_back("-m"); CmdArgs.push_back("elf_i386_fbsd"); break; case llvm::Triple::ppc: CmdArgs.push_back("-m"); CmdArgs.push_back("elf32ppc_fbsd"); break; case llvm::Triple::mips: CmdArgs.push_back("-m"); CmdArgs.push_back("elf32btsmip_fbsd"); break; case llvm::Triple::mipsel: CmdArgs.push_back("-m"); CmdArgs.push_back("elf32ltsmip_fbsd"); break; case llvm::Triple::mips64: CmdArgs.push_back("-m"); if (tools::mips::hasMipsAbiArg(Args, "n32")) CmdArgs.push_back("elf32btsmipn32_fbsd"); else CmdArgs.push_back("elf64btsmip_fbsd"); break; case llvm::Triple::mips64el: CmdArgs.push_back("-m"); if (tools::mips::hasMipsAbiArg(Args, "n32")) CmdArgs.push_back("elf32ltsmipn32_fbsd"); else CmdArgs.push_back("elf64ltsmip_fbsd"); break; default: break; } if (Arg *A = Args.getLastArg(options::OPT_G)) { if (ToolChain.getTriple().isMIPS()) { StringRef v = A->getValue(); CmdArgs.push_back(Args.MakeArgString("-G" + v)); A->claim(); } } if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); } else { assert(Output.isNothing() && "Invalid output."); } if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { const char *crt1 = nullptr; if (!Args.hasArg(options::OPT_shared)) { if (Args.hasArg(options::OPT_pg)) crt1 = "gcrt1.o"; else if (IsPIE) crt1 = "Scrt1.o"; else crt1 = "crt1.o"; } if (crt1) CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crt1))); CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o"))); const char *crtbegin = nullptr; if (Args.hasArg(options::OPT_static)) crtbegin = "crtbeginT.o"; else if (Args.hasArg(options::OPT_shared) || IsPIE) crtbegin = "crtbeginS.o"; else crtbegin = "crtbegin.o"; CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin))); } Args.AddAllArgs(CmdArgs, options::OPT_L); ToolChain.AddFilePathLibArgs(Args, CmdArgs); Args.AddAllArgs(CmdArgs, options::OPT_T_Group); Args.AddAllArgs(CmdArgs, options::OPT_e); Args.AddAllArgs(CmdArgs, options::OPT_s); Args.AddAllArgs(CmdArgs, options::OPT_t); Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag); Args.AddAllArgs(CmdArgs, options::OPT_r); if (D.isUsingLTO()) { assert(!Inputs.empty() && "Must have at least one input."); AddGoldPlugin(ToolChain, Args, CmdArgs, Output, Inputs[0], D.getLTOMode() == LTOK_Thin); } bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs); bool NeedsXRayDeps = addXRayRuntime(ToolChain, Args, CmdArgs); AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { addOpenMPRuntime(CmdArgs, ToolChain, Args); if (D.CCCIsCXX()) { if (ToolChain.ShouldLinkCXXStdlib(Args)) ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); if (Args.hasArg(options::OPT_pg)) CmdArgs.push_back("-lm_p"); else CmdArgs.push_back("-lm"); } if (NeedsSanitizerDeps) linkSanitizerRuntimeDeps(ToolChain, CmdArgs); if (NeedsXRayDeps) linkXRayRuntimeDeps(ToolChain, CmdArgs); // FIXME: For some reason GCC passes -lgcc and -lgcc_s before adding // the default system libraries. Just mimic this for now. if (Args.hasArg(options::OPT_pg)) CmdArgs.push_back("-lgcc_p"); else CmdArgs.push_back("-lgcc"); if (Args.hasArg(options::OPT_static)) { CmdArgs.push_back("-lgcc_eh"); } else if (Args.hasArg(options::OPT_pg)) { CmdArgs.push_back("-lgcc_eh_p"); } else { CmdArgs.push_back("--as-needed"); CmdArgs.push_back("-lgcc_s"); CmdArgs.push_back("--no-as-needed"); } if (Args.hasArg(options::OPT_pthread)) { if (Args.hasArg(options::OPT_pg)) CmdArgs.push_back("-lpthread_p"); else CmdArgs.push_back("-lpthread"); } if (Args.hasArg(options::OPT_pg)) { if (Args.hasArg(options::OPT_shared)) CmdArgs.push_back("-lc"); else CmdArgs.push_back("-lc_p"); CmdArgs.push_back("-lgcc_p"); } else { CmdArgs.push_back("-lc"); CmdArgs.push_back("-lgcc"); } if (Args.hasArg(options::OPT_static)) { CmdArgs.push_back("-lgcc_eh"); } else if (Args.hasArg(options::OPT_pg)) { CmdArgs.push_back("-lgcc_eh_p"); } else { CmdArgs.push_back("--as-needed"); CmdArgs.push_back("-lgcc_s"); CmdArgs.push_back("--no-as-needed"); } } if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { if (Args.hasArg(options::OPT_shared) || IsPIE) CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtendS.o"))); else CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o"))); CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o"))); } ToolChain.addProfileRTLibs(Args, CmdArgs); const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); }
static void constructHexagonLinkArgs(Compilation &C, const JobAction &JA, const toolchains::HexagonToolChain &HTC, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, ArgStringList &CmdArgs, const char *LinkingOutput) { const Driver &D = HTC.getDriver(); //---------------------------------------------------------------------------- // //---------------------------------------------------------------------------- bool IsStatic = Args.hasArg(options::OPT_static); bool IsShared = Args.hasArg(options::OPT_shared); bool IsPIE = Args.hasArg(options::OPT_pie); bool IncStdLib = !Args.hasArg(options::OPT_nostdlib); bool IncStartFiles = !Args.hasArg(options::OPT_nostartfiles); bool IncDefLibs = !Args.hasArg(options::OPT_nodefaultlibs); bool UseG0 = false; bool UseShared = IsShared && !IsStatic; //---------------------------------------------------------------------------- // Silence warnings for various options //---------------------------------------------------------------------------- Args.ClaimAllArgs(options::OPT_g_Group); Args.ClaimAllArgs(options::OPT_emit_llvm); Args.ClaimAllArgs(options::OPT_w); // Other warning options are already // handled somewhere else. Args.ClaimAllArgs(options::OPT_static_libgcc); //---------------------------------------------------------------------------- // //---------------------------------------------------------------------------- if (Args.hasArg(options::OPT_s)) CmdArgs.push_back("-s"); if (Args.hasArg(options::OPT_r)) CmdArgs.push_back("-r"); for (const auto &Opt : HTC.ExtraOpts) CmdArgs.push_back(Opt.c_str()); CmdArgs.push_back("-march=hexagon"); std::string CpuVer = toolchains::HexagonToolChain::GetTargetCPUVersion(Args).str(); std::string MCpuString = "-mcpu=hexagon" + CpuVer; CmdArgs.push_back(Args.MakeArgString(MCpuString)); if (IsShared) { CmdArgs.push_back("-shared"); // The following should be the default, but doing as hexagon-gcc does. CmdArgs.push_back("-call_shared"); } if (IsStatic) CmdArgs.push_back("-static"); if (IsPIE && !IsShared) CmdArgs.push_back("-pie"); if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) { std::string N = llvm::utostr(G.getValue()); CmdArgs.push_back(Args.MakeArgString(std::string("-G") + N)); UseG0 = G.getValue() == 0; } //---------------------------------------------------------------------------- // //---------------------------------------------------------------------------- CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); //---------------------------------------------------------------------------- // moslib //---------------------------------------------------------------------------- std::vector<std::string> OsLibs; bool HasStandalone = false; for (const Arg *A : Args.filtered(options::OPT_moslib_EQ)) { A->claim(); OsLibs.emplace_back(A->getValue()); HasStandalone = HasStandalone || (OsLibs.back() == "standalone"); } if (OsLibs.empty()) { OsLibs.push_back("standalone"); HasStandalone = true; } //---------------------------------------------------------------------------- // Start Files //---------------------------------------------------------------------------- const std::string MCpuSuffix = "/" + CpuVer; const std::string MCpuG0Suffix = MCpuSuffix + "/G0"; const std::string RootDir = HTC.getHexagonTargetDir(D.InstalledDir, D.PrefixDirs) + "/"; const std::string StartSubDir = "hexagon/lib" + (UseG0 ? MCpuG0Suffix : MCpuSuffix); auto Find = [&HTC] (const std::string &RootDir, const std::string &SubDir, const char *Name) -> std::string { std::string RelName = SubDir + Name; std::string P = HTC.GetFilePath(RelName.c_str()); if (llvm::sys::fs::exists(P)) return P; return RootDir + RelName; }; if (IncStdLib && IncStartFiles) { if (!IsShared) { if (HasStandalone) { std::string Crt0SA = Find(RootDir, StartSubDir, "/crt0_standalone.o"); CmdArgs.push_back(Args.MakeArgString(Crt0SA)); } std::string Crt0 = Find(RootDir, StartSubDir, "/crt0.o"); CmdArgs.push_back(Args.MakeArgString(Crt0)); } std::string Init = UseShared ? Find(RootDir, StartSubDir + "/pic", "/initS.o") : Find(RootDir, StartSubDir, "/init.o"); CmdArgs.push_back(Args.MakeArgString(Init)); } //---------------------------------------------------------------------------- // Library Search Paths //---------------------------------------------------------------------------- const ToolChain::path_list &LibPaths = HTC.getFilePaths(); for (const auto &LibPath : LibPaths) CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + LibPath)); //---------------------------------------------------------------------------- // //---------------------------------------------------------------------------- Args.AddAllArgs(CmdArgs, {options::OPT_T_Group, options::OPT_e, options::OPT_s, options::OPT_t, options::OPT_u_Group}); AddLinkerInputs(HTC, Inputs, Args, CmdArgs, JA); //---------------------------------------------------------------------------- // Libraries //---------------------------------------------------------------------------- if (IncStdLib && IncDefLibs) { if (D.CCCIsCXX()) { if (HTC.ShouldLinkCXXStdlib(Args)) HTC.AddCXXStdlibLibArgs(Args, CmdArgs); CmdArgs.push_back("-lm"); } CmdArgs.push_back("--start-group"); if (!IsShared) { for (const std::string &Lib : OsLibs) CmdArgs.push_back(Args.MakeArgString("-l" + Lib)); CmdArgs.push_back("-lc"); } CmdArgs.push_back("-lgcc"); CmdArgs.push_back("--end-group"); } //---------------------------------------------------------------------------- // End files //---------------------------------------------------------------------------- if (IncStdLib && IncStartFiles) { std::string Fini = UseShared ? Find(RootDir, StartSubDir + "/pic", "/finiS.o") : Find(RootDir, StartSubDir, "/fini.o"); CmdArgs.push_back(Args.MakeArgString(Fini)); } }
void tools::Myriad::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { const auto &TC = static_cast<const toolchains::MyriadToolChain &>(getToolChain()); const llvm::Triple &T = TC.getTriple(); ArgStringList CmdArgs; bool UseStartfiles = !Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles); bool UseDefaultLibs = !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs); // Silence warning if the args contain both -nostdlib and -stdlib=. Args.getLastArg(options::OPT_stdlib_EQ); if (T.getArch() == llvm::Triple::sparc) CmdArgs.push_back("-EB"); else // SHAVE assumes little-endian, and sparcel is expressly so. CmdArgs.push_back("-EL"); // The remaining logic is mostly like gnutools::Linker::ConstructJob, // but we never pass through a --sysroot option and various other bits. // For example, there are no sanitizers (yet) nor gold linker. // Eat some arguments that may be present but have no effect. Args.ClaimAllArgs(options::OPT_g_Group); Args.ClaimAllArgs(options::OPT_w); Args.ClaimAllArgs(options::OPT_static_libgcc); if (Args.hasArg(options::OPT_s)) // Pass the 'strip' option. CmdArgs.push_back("-s"); CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); if (UseStartfiles) { // If you want startfiles, it means you want the builtin crti and crtbegin, // but not crt0. Myriad link commands provide their own crt0.o as needed. CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crti.o"))); CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtbegin.o"))); } Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group, options::OPT_e, options::OPT_s, options::OPT_t, options::OPT_Z_Flag, options::OPT_r}); TC.AddFilePathLibArgs(Args, CmdArgs); bool NeedsSanitizerDeps = addSanitizerRuntimes(TC, Args, CmdArgs); AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); if (UseDefaultLibs) { if (NeedsSanitizerDeps) linkSanitizerRuntimeDeps(TC, CmdArgs); if (C.getDriver().CCCIsCXX()) { if (TC.GetCXXStdlibType(Args) == ToolChain::CST_Libcxx) { CmdArgs.push_back("-lc++"); CmdArgs.push_back("-lc++abi"); } else CmdArgs.push_back("-lstdc++"); } if (T.getOS() == llvm::Triple::RTEMS) { CmdArgs.push_back("--start-group"); CmdArgs.push_back("-lc"); CmdArgs.push_back("-lgcc"); // circularly dependent on rtems // You must provide your own "-L" option to enable finding these. CmdArgs.push_back("-lrtemscpu"); CmdArgs.push_back("-lrtemsbsp"); CmdArgs.push_back("--end-group"); } else { CmdArgs.push_back("-lc"); CmdArgs.push_back("-lgcc"); } } if (UseStartfiles) { CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtend.o"))); CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtn.o"))); } std::string Exec = Args.MakeArgString(TC.GetProgramPath("sparc-myriad-elf-ld")); C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Exec), CmdArgs, Inputs)); }
void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { const toolchains::Fuchsia &ToolChain = static_cast<const toolchains::Fuchsia &>(getToolChain()); const Driver &D = ToolChain.getDriver(); ArgStringList CmdArgs; // Silence warning for "clang -g foo.o -o foo" Args.ClaimAllArgs(options::OPT_g_Group); // and "clang -emit-llvm foo.o -o foo" Args.ClaimAllArgs(options::OPT_emit_llvm); // and for "clang -w foo.o -o foo". Other warning options are already // handled somewhere else. Args.ClaimAllArgs(options::OPT_w); const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); if (llvm::sys::path::stem(Exec).equals_lower("lld")) { CmdArgs.push_back("-flavor"); CmdArgs.push_back("gnu"); CmdArgs.push_back("-z"); CmdArgs.push_back("rodynamic"); } if (!D.SysRoot.empty()) CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); if (!Args.hasArg(options::OPT_shared) && !Args.hasArg(options::OPT_r)) CmdArgs.push_back("-pie"); if (Args.hasArg(options::OPT_rdynamic)) CmdArgs.push_back("-export-dynamic"); if (Args.hasArg(options::OPT_s)) CmdArgs.push_back("-s"); if (Args.hasArg(options::OPT_r)) { CmdArgs.push_back("-r"); } else { CmdArgs.push_back("--build-id"); CmdArgs.push_back("--hash-style=gnu"); } CmdArgs.push_back("--eh-frame-hdr"); if (Args.hasArg(options::OPT_static)) CmdArgs.push_back("-Bstatic"); else if (Args.hasArg(options::OPT_shared)) CmdArgs.push_back("-shared"); if (!Args.hasArg(options::OPT_shared)) { std::string Dyld = D.DyldPrefix; if (ToolChain.getSanitizerArgs().needsAsanRt() && ToolChain.getSanitizerArgs().needsSharedAsanRt()) Dyld += "asan/"; Dyld += "ld.so.1"; CmdArgs.push_back("-dynamic-linker"); CmdArgs.push_back(Args.MakeArgString(Dyld)); } CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { if (!Args.hasArg(options::OPT_shared)) { CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("Scrt1.o"))); } } Args.AddAllArgs(CmdArgs, options::OPT_L); Args.AddAllArgs(CmdArgs, options::OPT_u); ToolChain.AddFilePathLibArgs(Args, CmdArgs); addSanitizerRuntimes(ToolChain, Args, CmdArgs); AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { if (Args.hasArg(options::OPT_static)) CmdArgs.push_back("-Bdynamic"); if (D.CCCIsCXX()) { if (ToolChain.ShouldLinkCXXStdlib(Args)) ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); CmdArgs.push_back("-lm"); } AddRunTimeLibs(ToolChain, D, CmdArgs, Args); if (Args.hasArg(options::OPT_pthread) || Args.hasArg(options::OPT_pthreads)) CmdArgs.push_back("-lpthread"); if (Args.hasArg(options::OPT_fsplit_stack)) CmdArgs.push_back("--wrap=pthread_create"); CmdArgs.push_back("-lc"); } C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); }
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.hasArgNoClaim(options::OPT_E)) 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; // If the driver is invoked as C++ compiler (like clang++ or c++) it // should autodetect some input files as C++ for g++ compatibility. if (CCCIsCXX) { types::ID OldTy = Ty; Ty = types::lookupCXXTypeForCType(Ty); if (Ty != OldTy) Diag(clang::diag::warn_drv_treating_input_as_cxx) << getTypeName(OldTy) << getTypeName(Ty); } } // -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, if enabled. if (CheckInputsExist && 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().matches(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-ast,S} only run up to the compiler. } else if ((FinalPhaseArg = Args.getLastArg(options::OPT_fsyntax_only)) || (FinalPhaseArg = Args.getLastArg(options::OPT_rewrite_objc)) || (FinalPhaseArg = Args.getLastArg(options::OPT__analyze, options::OPT__analyze_auto)) || (FinalPhaseArg = Args.getLastArg(options::OPT_emit_ast)) || (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(); // Special case '-E' warning on a previously preprocessed file to make // more sense. if (InitialPhase == phases::Compile && FinalPhase == phases::Preprocess && getPreprocessedType(InputType) == types::TY_INVALID) Diag(clang::diag::warn_drv_preprocessed_input_file_unused) << InputArg->getAsString(Args) << FinalPhaseArg->getOption().getName(); else Diag(clang::diag::warn_drv_input_file_unused) << InputArg->getAsString(Args) << getPhaseName(InitialPhase) << FinalPhaseArg->getOption().getName(); continue; } // Build the pipeline for this file. llvm::OwningPtr<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.take()); 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.reset(ConstructPhaseAction(Args, Phase, Current.take())); if (Current->getType() == types::TY_Nothing) break; } // If we ended with something, add to the output list. if (Current) Actions.push_back(Current.take()); } // Add a link action if necessary. if (!LinkerInputs.empty()) Actions.push_back(new LinkJobAction(LinkerInputs, types::TY_Image)); // If we are linking, claim any options which are obviously only used for // compilation. if (FinalPhase == phases::Link) Args.ClaimAllArgs(options::OPT_CompileOnly_Group); }
void cloudabi::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { const ToolChain &ToolChain = getToolChain(); const Driver &D = ToolChain.getDriver(); ArgStringList CmdArgs; // Silence warning for "clang -g foo.o -o foo" Args.ClaimAllArgs(options::OPT_g_Group); // and "clang -emit-llvm foo.o -o foo" Args.ClaimAllArgs(options::OPT_emit_llvm); // and for "clang -w foo.o -o foo". Other warning options are already // handled somewhere else. Args.ClaimAllArgs(options::OPT_w); if (!D.SysRoot.empty()) CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); // CloudABI only supports static linkage. CmdArgs.push_back("-Bstatic"); CmdArgs.push_back("--no-dynamic-linker"); // Provide PIE linker flags in case PIE is default for the architecture. if (ToolChain.isPIEDefault()) { CmdArgs.push_back("-pie"); CmdArgs.push_back("-zrelro"); } CmdArgs.push_back("--eh-frame-hdr"); CmdArgs.push_back("--gc-sections"); if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); } else { assert(Output.isNothing() && "Invalid output."); } if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o"))); CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtbegin.o"))); } Args.AddAllArgs(CmdArgs, options::OPT_L); ToolChain.AddFilePathLibArgs(Args, CmdArgs); Args.AddAllArgs(CmdArgs, {options::OPT_T_Group, options::OPT_e, options::OPT_s, options::OPT_t, options::OPT_Z_Flag, options::OPT_r}); if (D.isUsingLTO()) { assert(!Inputs.empty() && "Must have at least one input."); AddGoldPlugin(ToolChain, Args, CmdArgs, Output, Inputs[0], D.getLTOMode() == LTOK_Thin); } AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); if (ToolChain.ShouldLinkCXXStdlib(Args)) ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { CmdArgs.push_back("-lc"); CmdArgs.push_back("-lcompiler_rt"); } if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o"))); const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); }
void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { const toolchains::OpenBSD &ToolChain = static_cast<const toolchains::OpenBSD &>(getToolChain()); const Driver &D = getToolChain().getDriver(); ArgStringList CmdArgs; // Silence warning for "clang -g foo.o -o foo" Args.ClaimAllArgs(options::OPT_g_Group); // and "clang -emit-llvm foo.o -o foo" Args.ClaimAllArgs(options::OPT_emit_llvm); // and for "clang -w foo.o -o foo". Other warning options are already // handled somewhere else. Args.ClaimAllArgs(options::OPT_w); if (getToolChain().getArch() == llvm::Triple::mips64) CmdArgs.push_back("-EB"); else if (getToolChain().getArch() == llvm::Triple::mips64el) CmdArgs.push_back("-EL"); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_shared)) { CmdArgs.push_back("-e"); CmdArgs.push_back("__start"); } CmdArgs.push_back("--eh-frame-hdr"); if (Args.hasArg(options::OPT_static)) { CmdArgs.push_back("-Bstatic"); } else { if (Args.hasArg(options::OPT_rdynamic)) CmdArgs.push_back("-export-dynamic"); CmdArgs.push_back("-Bdynamic"); if (Args.hasArg(options::OPT_shared)) { CmdArgs.push_back("-shared"); } else { CmdArgs.push_back("-dynamic-linker"); CmdArgs.push_back("/usr/libexec/ld.so"); } } if (Args.hasArg(options::OPT_pie)) CmdArgs.push_back("-pie"); if (Args.hasArg(options::OPT_nopie)) CmdArgs.push_back("-nopie"); if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); } else { assert(Output.isNothing() && "Invalid output."); } if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { if (!Args.hasArg(options::OPT_shared)) { if (Args.hasArg(options::OPT_pg)) CmdArgs.push_back( Args.MakeArgString(getToolChain().GetFilePath("gcrt0.o"))); else if (Args.hasArg(options::OPT_static) && !Args.hasArg(options::OPT_nopie)) CmdArgs.push_back( Args.MakeArgString(getToolChain().GetFilePath("rcrt0.o"))); else CmdArgs.push_back( Args.MakeArgString(getToolChain().GetFilePath("crt0.o"))); CmdArgs.push_back( Args.MakeArgString(getToolChain().GetFilePath("crtbegin.o"))); } else { CmdArgs.push_back( Args.MakeArgString(getToolChain().GetFilePath("crtbeginS.o"))); } } std::string Triple = getToolChain().getTripleString(); if (Triple.substr(0, 6) == "x86_64") Triple.replace(0, 6, "amd64"); CmdArgs.push_back( Args.MakeArgString("-L/usr/lib/gcc-lib/" + Triple + "/4.2.1")); CmdArgs.push_back(Args.MakeArgString("-L/usr/lib")); Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group, options::OPT_e, options::OPT_s, options::OPT_t, options::OPT_Z_Flag, options::OPT_r}); bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs); bool NeedsXRayDeps = addXRayRuntime(ToolChain, Args, CmdArgs); AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { if (D.CCCIsCXX()) { if (getToolChain().ShouldLinkCXXStdlib(Args)) getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); if (Args.hasArg(options::OPT_pg)) CmdArgs.push_back("-lm_p"); else CmdArgs.push_back("-lm"); } if (NeedsSanitizerDeps) { CmdArgs.push_back(ToolChain.getCompilerRTArgString(Args, "builtins", false)); linkSanitizerRuntimeDeps(ToolChain, CmdArgs); } if (NeedsXRayDeps) { CmdArgs.push_back(ToolChain.getCompilerRTArgString(Args, "builtins", false)); linkXRayRuntimeDeps(ToolChain, CmdArgs); } // FIXME: For some reason GCC passes -lgcc before adding // the default system libraries. Just mimic this for now. CmdArgs.push_back("-lgcc"); if (Args.hasArg(options::OPT_pthread)) { if (!Args.hasArg(options::OPT_shared) && Args.hasArg(options::OPT_pg)) CmdArgs.push_back("-lpthread_p"); else CmdArgs.push_back("-lpthread"); } if (!Args.hasArg(options::OPT_shared)) { if (Args.hasArg(options::OPT_pg)) CmdArgs.push_back("-lc_p"); else CmdArgs.push_back("-lc"); } CmdArgs.push_back("-lgcc"); } if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { if (!Args.hasArg(options::OPT_shared)) CmdArgs.push_back( Args.MakeArgString(getToolChain().GetFilePath("crtend.o"))); else CmdArgs.push_back( Args.MakeArgString(getToolChain().GetFilePath("crtendS.o"))); } const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); }
// This is quite similar to gnutools::Linker::ConstructJob with changes that // we use static by default, do not yet support sanitizers or LTO, and a few // others. Eventually we can support more of that and hopefully migrate back // to gnutools::Linker. void nacltools::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { const toolchains::NaClToolChain &ToolChain = static_cast<const toolchains::NaClToolChain &>(getToolChain()); const Driver &D = ToolChain.getDriver(); const llvm::Triple::ArchType Arch = ToolChain.getArch(); const bool IsStatic = !Args.hasArg(options::OPT_dynamic) && !Args.hasArg(options::OPT_shared); ArgStringList CmdArgs; // Silence warning for "clang -g foo.o -o foo" Args.ClaimAllArgs(options::OPT_g_Group); // and "clang -emit-llvm foo.o -o foo" Args.ClaimAllArgs(options::OPT_emit_llvm); // and for "clang -w foo.o -o foo". Other warning options are already // handled somewhere else. Args.ClaimAllArgs(options::OPT_w); if (!D.SysRoot.empty()) CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); if (Args.hasArg(options::OPT_rdynamic)) CmdArgs.push_back("-export-dynamic"); if (Args.hasArg(options::OPT_s)) CmdArgs.push_back("-s"); // NaClToolChain doesn't have ExtraOpts like Linux; the only relevant flag // from there is --build-id, which we do want. CmdArgs.push_back("--build-id"); if (!IsStatic) CmdArgs.push_back("--eh-frame-hdr"); CmdArgs.push_back("-m"); if (Arch == llvm::Triple::x86) CmdArgs.push_back("elf_i386_nacl"); else if (Arch == llvm::Triple::arm) CmdArgs.push_back("armelf_nacl"); else if (Arch == llvm::Triple::x86_64) CmdArgs.push_back("elf_x86_64_nacl"); else if (Arch == llvm::Triple::mipsel) CmdArgs.push_back("mipselelf_nacl"); else D.Diag(diag::err_target_unsupported_arch) << ToolChain.getArchName() << "Native Client"; if (IsStatic) CmdArgs.push_back("-static"); else if (Args.hasArg(options::OPT_shared)) CmdArgs.push_back("-shared"); CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { if (!Args.hasArg(options::OPT_shared)) CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt1.o"))); CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o"))); const char *crtbegin; if (IsStatic) crtbegin = "crtbeginT.o"; else if (Args.hasArg(options::OPT_shared)) crtbegin = "crtbeginS.o"; else crtbegin = "crtbegin.o"; CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin))); } Args.AddAllArgs(CmdArgs, options::OPT_L); Args.AddAllArgs(CmdArgs, options::OPT_u); ToolChain.AddFilePathLibArgs(Args, CmdArgs); if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) CmdArgs.push_back("--no-demangle"); AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); if (D.CCCIsCXX() && !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { if (ToolChain.ShouldLinkCXXStdlib(Args)) { bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) && !IsStatic; if (OnlyLibstdcxxStatic) CmdArgs.push_back("-Bstatic"); ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); if (OnlyLibstdcxxStatic) CmdArgs.push_back("-Bdynamic"); } CmdArgs.push_back("-lm"); } if (!Args.hasArg(options::OPT_nostdlib)) { if (!Args.hasArg(options::OPT_nodefaultlibs)) { // Always use groups, since it has no effect on dynamic libraries. CmdArgs.push_back("--start-group"); CmdArgs.push_back("-lc"); // NaCl's libc++ currently requires libpthread, so just always include it // in the group for C++. if (Args.hasArg(options::OPT_pthread) || Args.hasArg(options::OPT_pthreads) || D.CCCIsCXX()) { // Gold, used by Mips, handles nested groups differently than ld, and // without '-lnacl' it prefers symbols from libpthread.a over libnacl.a, // which is not a desired behaviour here. // See https://sourceware.org/ml/binutils/2015-03/msg00034.html if (getToolChain().getArch() == llvm::Triple::mipsel) CmdArgs.push_back("-lnacl"); CmdArgs.push_back("-lpthread"); } CmdArgs.push_back("-lgcc"); CmdArgs.push_back("--as-needed"); if (IsStatic) CmdArgs.push_back("-lgcc_eh"); else CmdArgs.push_back("-lgcc_s"); CmdArgs.push_back("--no-as-needed"); // Mips needs to create and use pnacl_legacy library that contains // definitions from bitcode/pnaclmm.c and definitions for // __nacl_tp_tls_offset() and __nacl_tp_tdb_offset(). if (getToolChain().getArch() == llvm::Triple::mipsel) CmdArgs.push_back("-lpnacl_legacy"); CmdArgs.push_back("--end-group"); } if (!Args.hasArg(options::OPT_nostartfiles)) { const char *crtend; if (Args.hasArg(options::OPT_shared)) crtend = "crtendS.o"; else crtend = "crtend.o"; CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend))); CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o"))); } } const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); }