ToolChain::InvocationInfo ToolChain::constructInvocation(const MergeModuleJobAction &job, const JobContext &context) const { ArgStringList Arguments; if (context.OI.CompilerMode != OutputInfo::Mode::UpdateCode) Arguments.push_back("-frontend"); // We just want to emit a module, so pass -emit-module without any other // mode options. Arguments.push_back("-emit-module"); size_t origLen = Arguments.size(); (void)origLen; addInputsOfType(Arguments, context.Inputs, types::TY_SwiftModuleFile); addInputsOfType(Arguments, context.InputActions, types::TY_SwiftModuleFile); assert(Arguments.size() - origLen >= context.Inputs.size() + context.InputActions.size()); assert((Arguments.size() - origLen == context.Inputs.size() || !context.InputActions.empty()) && "every input to MergeModule must generate a swiftmodule"); // Tell all files to parse as library, which is necessary to load them as // serialized ASTs. Arguments.push_back("-parse-as-library"); addCommonFrontendArgs(*this, context.OI, context.Output, context.Args, Arguments); Arguments.push_back("-module-name"); Arguments.push_back(context.Args.MakeArgString(context.OI.ModuleName)); assert(context.Output.getPrimaryOutputType() == types::TY_SwiftModuleFile && "The MergeModule tool only produces swiftmodule files!"); const std::string &ObjCHeaderOutputPath = context.Output.getAdditionalOutputForType(types::TY_ObjCHeader); if (!ObjCHeaderOutputPath.empty()) { Arguments.push_back("-emit-objc-header-path"); Arguments.push_back(ObjCHeaderOutputPath.c_str()); } Arguments.push_back("-o"); Arguments.push_back( context.Args.MakeArgString(context.Output.getPrimaryOutputFilename())); auto program = SWIFT_EXECUTABLE_NAME; if (context.OI.CompilerMode == OutputInfo::Mode::UpdateCode) program = SWIFT_UPDATE_NAME; return {program, Arguments}; }
TEST(Option, OptionParsing) { TestOptTable T; unsigned MAI, MAC; InputArgList AL = T.ParseArgs(Args, MAI, MAC); // Check they all exist. EXPECT_TRUE(AL.hasArg(OPT_A)); EXPECT_TRUE(AL.hasArg(OPT_B)); EXPECT_TRUE(AL.hasArg(OPT_C)); EXPECT_TRUE(AL.hasArg(OPT_D)); EXPECT_TRUE(AL.hasArg(OPT_E)); EXPECT_TRUE(AL.hasArg(OPT_F)); EXPECT_TRUE(AL.hasArg(OPT_G)); // Check the values. EXPECT_EQ("hi", AL.getLastArgValue(OPT_B)); EXPECT_EQ("bye", AL.getLastArgValue(OPT_C)); EXPECT_EQ("adena", AL.getLastArgValue(OPT_D)); std::vector<std::string> Es = AL.getAllArgValues(OPT_E); EXPECT_EQ("apple", Es[0]); EXPECT_EQ("bloom", Es[1]); EXPECT_EQ("42", AL.getLastArgValue(OPT_F)); std::vector<std::string> Gs = AL.getAllArgValues(OPT_G); EXPECT_EQ("chuu", Gs[0]); EXPECT_EQ("2", Gs[1]); // Check the help text. std::string Help; raw_string_ostream RSO(Help); T.PrintHelp(RSO, "test", "title!"); EXPECT_NE(std::string::npos, Help.find("-A")); // Check usage line. T.PrintHelp(RSO, "name [options] file...", "title!"); EXPECT_NE(std::string::npos, Help.find("USAGE: name [options] file...\n")); // Test aliases. auto Cs = AL.filtered(OPT_C); ASSERT_NE(Cs.begin(), Cs.end()); EXPECT_EQ("desu", StringRef((*Cs.begin())->getValue())); ArgStringList ASL; (*Cs.begin())->render(AL, ASL); ASSERT_EQ(2u, ASL.size()); EXPECT_EQ("-C", StringRef(ASL[0])); EXPECT_EQ("desu", StringRef(ASL[1])); }
TEST(Support, OptionParsing) { TestOptTable T; unsigned MAI, MAC; OwningPtr<InputArgList> AL(T.ParseArgs(Args, Args + (sizeof(Args) / sizeof(Args[0])), MAI, MAC)); // Check they all exist. EXPECT_TRUE(AL->hasArg(OPT_A)); EXPECT_TRUE(AL->hasArg(OPT_B)); EXPECT_TRUE(AL->hasArg(OPT_C)); EXPECT_TRUE(AL->hasArg(OPT_D)); EXPECT_TRUE(AL->hasArg(OPT_E)); EXPECT_TRUE(AL->hasArg(OPT_F)); EXPECT_TRUE(AL->hasArg(OPT_G)); // Check the values. EXPECT_EQ(AL->getLastArgValue(OPT_B), "hi"); EXPECT_EQ(AL->getLastArgValue(OPT_C), "bye"); EXPECT_EQ(AL->getLastArgValue(OPT_D), "adena"); std::vector<std::string> Es = AL->getAllArgValues(OPT_E); EXPECT_EQ(Es[0], "apple"); EXPECT_EQ(Es[1], "bloom"); EXPECT_EQ(AL->getLastArgValue(OPT_F), "42"); std::vector<std::string> Gs = AL->getAllArgValues(OPT_G); EXPECT_EQ(Gs[0], "chuu"); EXPECT_EQ(Gs[1], "2"); // Check the help text. std::string Help; raw_string_ostream RSO(Help); T.PrintHelp(RSO, "test", "title!"); EXPECT_NE(Help.find("-A"), std::string::npos); // Test aliases. arg_iterator Cs = AL->filtered_begin(OPT_C); ASSERT_NE(Cs, AL->filtered_end()); EXPECT_EQ(StringRef((*Cs)->getValue()), "desu"); ArgStringList ASL; (*Cs)->render(*AL, ASL); ASSERT_EQ(ASL.size(), 2u); EXPECT_EQ(StringRef(ASL[0]), "-C"); EXPECT_EQ(StringRef(ASL[1]), "desu"); }
ToolChain::InvocationInfo ToolChain::constructInvocation(const ModuleWrapJobAction &job, const JobContext &context) const { ArgStringList Arguments; Arguments.push_back("-modulewrap"); addInputsOfType(Arguments, context.Inputs, types::TY_SwiftModuleFile); addInputsOfType(Arguments, context.InputActions, types::TY_SwiftModuleFile); assert(Arguments.size() == 2 && "ModuleWrap expects exactly one merged swiftmodule as input"); assert(context.Output.getPrimaryOutputType() == types::TY_Object && "The -modulewrap mode only produces object files"); Arguments.push_back("-o"); Arguments.push_back( context.Args.MakeArgString(context.Output.getPrimaryOutputFilename())); return {SWIFT_EXECUTABLE_NAME, Arguments}; }
ToolChain::InvocationInfo toolchains::Darwin::constructInvocation(const LinkJobAction &job, const JobContext &context) const { assert(context.Output.getPrimaryOutputType() == types::TY_Image && "Invalid linker output type."); const Driver &D = getDriver(); const llvm::Triple &Triple = getTriple(); ArgStringList Arguments; addPrimaryInputsOfType(Arguments, context.Inputs, types::TY_Object); addInputsOfType(Arguments, context.InputActions, types::TY_Object); if (context.OI.DebugInfoKind == IRGenDebugInfoKind::Normal) { size_t argCount = Arguments.size(); if (context.OI.CompilerMode == OutputInfo::Mode::SingleCompile) addInputsOfType(Arguments, context.Inputs, types::TY_SwiftModuleFile); else addPrimaryInputsOfType(Arguments, context.Inputs, types::TY_SwiftModuleFile); if (Arguments.size() > argCount) { assert(argCount + 1 == Arguments.size() && "multiple swiftmodules found for -g"); Arguments.insert(Arguments.end() - 1, "-add_ast_path"); } } switch (job.getKind()) { case LinkKind::None: llvm_unreachable("invalid link kind"); case LinkKind::Executable: // The default for ld; no extra flags necessary. break; case LinkKind::DynamicLibrary: Arguments.push_back("-dylib"); break; } assert(Triple.isOSDarwin()); // FIXME: If we used Clang as a linker instead of going straight to ld, // we wouldn't have to replicate Clang's logic here. bool wantsObjCRuntime = false; if (Triple.isiOS()) wantsObjCRuntime = Triple.isOSVersionLT(8); else if (Triple.isWatchOS()) wantsObjCRuntime = Triple.isOSVersionLT(2); else if (Triple.isMacOSX()) wantsObjCRuntime = Triple.isMacOSXVersionLT(10, 10); if (context.Args.hasFlag(options::OPT_link_objc_runtime, options::OPT_no_link_objc_runtime, /*default=*/wantsObjCRuntime)) { llvm::SmallString<128> ARCLiteLib(D.getSwiftProgramPath()); llvm::sys::path::remove_filename(ARCLiteLib); // 'swift' llvm::sys::path::remove_filename(ARCLiteLib); // 'bin' llvm::sys::path::append(ARCLiteLib, "lib", "arc"); if (!llvm::sys::fs::is_directory(ARCLiteLib)) { // If we don't have a 'lib/arc/' directory, find the "arclite" library // relative to the Clang in the active Xcode. ARCLiteLib.clear(); if (findXcodeClangPath(ARCLiteLib)) { llvm::sys::path::remove_filename(ARCLiteLib); // 'clang' llvm::sys::path::remove_filename(ARCLiteLib); // 'bin' llvm::sys::path::append(ARCLiteLib, "lib", "arc"); } } if (!ARCLiteLib.empty()) { llvm::sys::path::append(ARCLiteLib, "libarclite_"); ARCLiteLib += getPlatformNameForTriple(Triple); ARCLiteLib += ".a"; Arguments.push_back("-force_load"); Arguments.push_back(context.Args.MakeArgString(ARCLiteLib)); // Arclite depends on CoreFoundation. Arguments.push_back("-framework"); Arguments.push_back("CoreFoundation"); } else { // FIXME: We should probably diagnose this, but this is not a place where // we can emit diagnostics. Silently ignore it for now. } } context.Args.AddAllArgValues(Arguments, options::OPT_Xlinker); context.Args.AddAllArgs(Arguments, options::OPT_linker_option_Group); context.Args.AddAllArgs(Arguments, options::OPT_F); if (context.Args.hasArg(options::OPT_enable_app_extension)) { // Keep this string fixed in case the option used by the // compiler itself changes. Arguments.push_back("-application_extension"); } if (context.Args.hasArg(options::OPT_embed_bitcode, options::OPT_embed_bitcode_marker)) { Arguments.push_back("-bitcode_bundle"); } if (!context.OI.SDKPath.empty()) { Arguments.push_back("-syslibroot"); Arguments.push_back(context.Args.MakeArgString(context.OI.SDKPath)); } Arguments.push_back("-lobjc"); Arguments.push_back("-lSystem"); Arguments.push_back("-arch"); Arguments.push_back(context.Args.MakeArgString(getTriple().getArchName())); // Add the runtime library link path, which is platform-specific and found // relative to the compiler. SmallString<128> RuntimeLibPath; getRuntimeLibraryPath(RuntimeLibPath, context.Args, *this); Arguments.push_back("-L"); Arguments.push_back(context.Args.MakeArgString(RuntimeLibPath)); if (context.Args.hasArg(options::OPT_profile_generate)) { SmallString<128> LibProfile(RuntimeLibPath); llvm::sys::path::remove_filename(LibProfile); // remove platform name llvm::sys::path::append(LibProfile, "clang", CLANG_VERSION_STRING); StringRef RT; if (Triple.isiOS()) { if (Triple.isTvOS()) RT = "tvos"; else RT = "ios"; } else if (Triple.isWatchOS()) RT = "watchos"; else RT = "osx"; llvm::sys::path::append(LibProfile, "lib", "darwin", "libclang_rt.profile_" + RT + ".a"); Arguments.push_back(context.Args.MakeArgString(LibProfile)); } // FIXME: We probably shouldn't be adding an rpath here unless we know ahead // of time the standard library won't be copied. Arguments.push_back("-rpath"); Arguments.push_back(context.Args.MakeArgString(RuntimeLibPath)); // FIXME: Properly handle deployment targets. assert(Triple.isiOS() || Triple.isWatchOS() || Triple.isMacOSX()); if (Triple.isiOS()) { bool isiOSSimulator = tripleIsiOSSimulator(Triple); if (Triple.isTvOS()) { if (isiOSSimulator) Arguments.push_back("-tvos_simulator_version_min"); else Arguments.push_back("-tvos_version_min"); } else { if (isiOSSimulator) Arguments.push_back("-ios_simulator_version_min"); else Arguments.push_back("-iphoneos_version_min"); } unsigned major, minor, micro; Triple.getiOSVersion(major, minor, micro); addVersionString(context.Args, Arguments, major, minor, micro); } else if (Triple.isWatchOS()) { if (tripleIsWatchSimulator(Triple)) Arguments.push_back("-watchos_simulator_version_min"); else Arguments.push_back("-watchos_version_min"); unsigned major, minor, micro; Triple.getOSVersion(major, minor, micro); addVersionString(context.Args, Arguments, major, minor, micro); } else { Arguments.push_back("-macosx_version_min"); unsigned major, minor, micro; Triple.getMacOSXVersion(major, minor, micro); addVersionString(context.Args, Arguments, major, minor, micro); } Arguments.push_back("-no_objc_category_merging"); // This should be the last option, for convenience in checking output. Arguments.push_back("-o"); Arguments.push_back(context.Output.getPrimaryOutputFilename().c_str()); return {"ld", Arguments}; }