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(); InvocationInfo II{"ld"}; ArgStringList &Arguments = II.Arguments; if (context.Args.hasArg(options::OPT_driver_use_filelists) || context.Inputs.size() > TOO_MANY_FILES) { Arguments.push_back("-filelist"); Arguments.push_back(context.getTemporaryFilePath("inputs", "LinkFileList")); II.FilelistInfo = {Arguments.back(), types::TY_Object, FilelistInfo::Input}; } else { 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"); } // Liking in sanitizers will add rpaths, which might negatively interact when // other rpaths are involved, so we should make sure we add the rpaths after // all user-specified rpaths. if (context.OI.SelectedSanitizer == SanitizerKind::Address) addLinkSanitizerLibArgsForDarwin(context.Args, Arguments, "asan", *this); if (context.OI.SelectedSanitizer == SanitizerKind::Thread) addLinkSanitizerLibArgsForDarwin(context.Args, Arguments, "tsan", *this); 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", "lib", "darwin"); StringRef RT; if (Triple.isiOS()) { if (Triple.isTvOS()) RT = "tvos"; else RT = "ios"; } else if (Triple.isWatchOS()) { RT = "watchos"; } else { assert(Triple.isMacOSX()); RT = "osx"; } StringRef Sim; if (tripleIsAnySimulator(Triple)) { Sim = "sim"; } llvm::sys::path::append(LibProfile, "libclang_rt.profile_" + RT + Sim + ".a"); // FIXME: Continue accepting the old path for simulator libraries for now. if (!Sim.empty() && !llvm::sys::fs::exists(LibProfile)) { llvm::sys::path::remove_filename(LibProfile); llvm::sys::path::append(LibProfile, "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 II; }
ToolChain::InvocationInfo toolchains::GenericUnix::constructInvocation(const LinkJobAction &job, const JobContext &context) const { const Driver &D = getDriver(); assert(context.Output.getPrimaryOutputType() == types::TY_Image && "Invalid linker output type."); ArgStringList Arguments; switch (job.getKind()) { case LinkKind::None: llvm_unreachable("invalid link kind"); case LinkKind::Executable: // Default case, nothing extra needed break; case LinkKind::DynamicLibrary: Arguments.push_back("-shared"); break; } addPrimaryInputsOfType(Arguments, context.Inputs, types::TY_Object); addInputsOfType(Arguments, context.InputActions, types::TY_Object); context.Args.AddAllArgs(Arguments, options::OPT_Xlinker); context.Args.AddAllArgs(Arguments, options::OPT_linker_option_Group); context.Args.AddAllArgs(Arguments, options::OPT_F); if (!context.OI.SDKPath.empty()) { Arguments.push_back("--sysroot"); Arguments.push_back(context.Args.MakeArgString(context.OI.SDKPath)); } // Add the runtime library link path, which is platform-specific and found // relative to the compiler. // FIXME: Duplicated from CompilerInvocation, but in theory the runtime // library link path and the standard library module import path don't // need to be the same. llvm::SmallString<128> RuntimeLibPath; if (const Arg *A = context.Args.getLastArg(options::OPT_resource_dir)) { RuntimeLibPath = A->getValue(); } else { RuntimeLibPath = D.getSwiftProgramPath(); llvm::sys::path::remove_filename(RuntimeLibPath); // remove /swift llvm::sys::path::remove_filename(RuntimeLibPath); // remove /bin llvm::sys::path::append(RuntimeLibPath, "lib", "swift"); } llvm::sys::path::append(RuntimeLibPath, getPlatformNameForTriple(getTriple())); 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); llvm::sys::path::append(LibProfile, "lib", getTriple().getOSName(), Twine("libclang_rt.profile-") + getTriple().getArchName() + ".a"); Arguments.push_back(context.Args.MakeArgString(LibProfile)); } if (getTriple().isAndroid()) { // FIXME: Android: hard-coded paths to arm; needs to fix for arm64, x86 Arguments.push_back("-target"); Arguments.push_back("armv7-none-linux-androideabi"); //Arguments.push_back(context.Args.MakeArgString(getTriple().str())); const char* ndkhome = getenv("ANDROID_NDK_HOME"); assert(ndkhome && "ANDROID_NDK_HOME needs to be set to NDK " "install directory for linking"); auto libgccpath = Twine(ndkhome) + "/toolchains/" "arm-linux-androideabi-4.8/prebuilt/linux-x86_64/" "lib/gcc/arm-linux-androideabi/4.8"; Arguments.push_back("-L"); Arguments.push_back(context.Args.MakeArgString(libgccpath)); auto libcxxpath = Twine(ndkhome) + "/sources/" "cxx-stl/llvm-libc++/libs/armeabi-v7a"; Arguments.push_back("-L"); Arguments.push_back(context.Args.MakeArgString(libcxxpath)); Arguments.push_back("-lgcc"); Arguments.push_back("-lc"); } else { // rpaths are not supported on Android. // 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("-Xlinker"); Arguments.push_back("-rpath"); Arguments.push_back("-Xlinker"); Arguments.push_back(context.Args.MakeArgString(RuntimeLibPath)); } // Always add the stdlib Arguments.push_back("-lswiftCore"); // Add any autolinking scripts to the arguments for (const Job *Cmd : context.Inputs) { auto &OutputInfo = Cmd->getOutput(); if (OutputInfo.getPrimaryOutputType() == types::TY_AutolinkFile) Arguments.push_back(context.Args.MakeArgString( Twine("@") + OutputInfo.getPrimaryOutputFilename())); } // Add the linker script that coalesces protocol conformance sections. Arguments.push_back("-Xlinker"); Arguments.push_back("-T"); // FIXME: This should also query the abi type (i.e. gnueabihf) Arguments.push_back(context.Args.MakeArgString( Twine(RuntimeLibPath) + "/" + getTriple().getArchName() + "/swift.ld")); // This should be the last option, for convenience in checking output. Arguments.push_back("-o"); Arguments.push_back(context.Output.getPrimaryOutputFilename().c_str()); return {"clang++", Arguments}; }
ToolChain::InvocationInfo toolchains::GenericUnix::constructInvocation(const LinkJobAction &job, const JobContext &context) const { assert(context.Output.getPrimaryOutputType() == types::TY_Image && "Invalid linker output type."); ArgStringList Arguments; switch (job.getKind()) { case LinkKind::None: llvm_unreachable("invalid link kind"); case LinkKind::Executable: // Default case, nothing extra needed break; case LinkKind::DynamicLibrary: Arguments.push_back("-shared"); break; } // Select the linker to use std::string Linker; if (const Arg *A = context.Args.getLastArg(options::OPT_use_ld)) { Linker = A->getValue(); } else { Linker = getDefaultLinker(); } if (!Linker.empty()) { Arguments.push_back(context.Args.MakeArgString("-fuse-ld=" + Linker)); } std::string Target = getTargetForLinker(); if (!Target.empty()) { Arguments.push_back("-target"); Arguments.push_back(context.Args.MakeArgString(Target)); } // Add the runtime library link path, which is platform-specific and found // relative to the compiler. llvm::SmallString<128> RuntimeLibPath; getRuntimeLibraryPath(RuntimeLibPath, context.Args, *this); if (shouldProvideRPathToLinker()) { // 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("-Xlinker"); Arguments.push_back("-rpath"); Arguments.push_back("-Xlinker"); Arguments.push_back(context.Args.MakeArgString(RuntimeLibPath)); } auto PreInputObjectPath = getPreInputObjectPath(RuntimeLibPath); if (!PreInputObjectPath.empty()) { Arguments.push_back(context.Args.MakeArgString(PreInputObjectPath)); } addPrimaryInputsOfType(Arguments, context.Inputs, types::TY_Object); addInputsOfType(Arguments, context.InputActions, types::TY_Object); context.Args.AddAllArgs(Arguments, options::OPT_Xlinker); context.Args.AddAllArgs(Arguments, options::OPT_linker_option_Group); context.Args.AddAllArgs(Arguments, options::OPT_F); if (!context.OI.SDKPath.empty()) { Arguments.push_back("--sysroot"); Arguments.push_back(context.Args.MakeArgString(context.OI.SDKPath)); } 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", "lib"); llvm::sys::path::append(LibProfile, getTriple().getOSName(), Twine("libclang_rt.profile-") + getTriple().getArchName() + ".a"); Arguments.push_back(context.Args.MakeArgString(LibProfile)); } // Always add the stdlib Arguments.push_back("-lswiftCore"); // Add any autolinking scripts to the arguments for (const Job *Cmd : context.Inputs) { auto &OutputInfo = Cmd->getOutput(); if (OutputInfo.getPrimaryOutputType() == types::TY_AutolinkFile) Arguments.push_back(context.Args.MakeArgString( Twine("@") + OutputInfo.getPrimaryOutputFilename())); } // Just before the output option, allow GenericUnix toolchains to add // additional inputs. auto PostInputObjectPath = getPostInputObjectPath(RuntimeLibPath); if (!PostInputObjectPath.empty()) { Arguments.push_back(context.Args.MakeArgString(PostInputObjectPath)); } // This should be the last option, for convenience in checking output. Arguments.push_back("-o"); Arguments.push_back(context.Output.getPrimaryOutputFilename().c_str()); return {"clang++", Arguments}; }
ToolChain::InvocationInfo toolchains::Windows::constructInvocation(const LinkJobAction &job, const JobContext &context) const { assert(context.Output.getPrimaryOutputType() == file_types::TY_Image && "Invalid linker output type."); ArgStringList Arguments; switch (job.getKind()) { case LinkKind::None: llvm_unreachable("invalid link kind"); case LinkKind::Executable: // Default case, nothing extra needed. break; case LinkKind::DynamicLibrary: Arguments.push_back("-shared"); break; } // Select the linker to use. std::string Linker; if (const Arg *A = context.Args.getLastArg(options::OPT_use_ld)) { Linker = A->getValue(); } if (!Linker.empty()) Arguments.push_back(context.Args.MakeArgString("-fuse-ld=" + Linker)); if (context.OI.DebugInfoFormat == IRGenDebugInfoFormat::CodeView) Arguments.push_back("-Wl,/DEBUG"); // Configure the toolchain. // By default, use the system clang++ to link. const char *Clang = nullptr; if (const Arg *A = context.Args.getLastArg(options::OPT_tools_directory)) { StringRef toolchainPath(A->getValue()); // If there is a clang in the toolchain folder, use that instead. if (auto toolchainClang = llvm::sys::findProgramByName("clang++", {toolchainPath})) Clang = context.Args.MakeArgString(toolchainClang.get()); } if (Clang == nullptr) { if (auto pathClang = llvm::sys::findProgramByName("clang++", None)) Clang = context.Args.MakeArgString(pathClang.get()); } assert(Clang && "clang++ was not found in the toolchain directory or system path."); std::string Target = getTriple().str(); if (!Target.empty()) { Arguments.push_back("-target"); Arguments.push_back(context.Args.MakeArgString(Target)); } SmallString<128> SharedRuntimeLibPath; getRuntimeLibraryPath(SharedRuntimeLibPath, context.Args, /*Shared=*/true); // Link the standard library. Arguments.push_back("-L"); if (context.Args.hasFlag(options::OPT_static_stdlib, options::OPT_no_static_stdlib, false)) { SmallString<128> StaticRuntimeLibPath; getRuntimeLibraryPath(StaticRuntimeLibPath, context.Args, /*Shared=*/false); // Since Windows has separate libraries per architecture, link against the // architecture specific version of the static library. Arguments.push_back(context.Args.MakeArgString(StaticRuntimeLibPath + "/" + getTriple().getArchName())); } else { Arguments.push_back(context.Args.MakeArgString(SharedRuntimeLibPath + "/" + getTriple().getArchName())); } SmallString<128> swiftrtPath = SharedRuntimeLibPath; llvm::sys::path::append(swiftrtPath, swift::getMajorArchitectureName(getTriple())); llvm::sys::path::append(swiftrtPath, "swiftrt.o"); Arguments.push_back(context.Args.MakeArgString(swiftrtPath)); addPrimaryInputsOfType(Arguments, context.Inputs, context.Args, file_types::TY_Object); addInputsOfType(Arguments, context.InputActions, file_types::TY_Object); for (const Arg *arg : context.Args.filtered(options::OPT_F, options::OPT_Fsystem)) { if (arg->getOption().matches(options::OPT_Fsystem)) Arguments.push_back("-iframework"); else Arguments.push_back(context.Args.MakeArgString(arg->getSpelling())); Arguments.push_back(arg->getValue()); } if (!context.OI.SDKPath.empty()) { Arguments.push_back("-I"); Arguments.push_back(context.Args.MakeArgString(context.OI.SDKPath)); } if (job.getKind() == LinkKind::Executable) { if (context.OI.SelectedSanitizers & SanitizerKind::Address) addLinkRuntimeLib(context.Args, Arguments, sanitizerRuntimeLibName("asan")); } if (context.Args.hasArg(options::OPT_profile_generate)) { SmallString<128> LibProfile(SharedRuntimeLibPath); llvm::sys::path::remove_filename(LibProfile); // remove platform name llvm::sys::path::append(LibProfile, "clang", "lib"); llvm::sys::path::append(LibProfile, getTriple().getOSName(), Twine("clang_rt.profile-") + getTriple().getArchName() + ".lib"); Arguments.push_back(context.Args.MakeArgString(LibProfile)); Arguments.push_back(context.Args.MakeArgString( Twine("-u", llvm::getInstrProfRuntimeHookVarName()))); } context.Args.AddAllArgs(Arguments, options::OPT_Xlinker); context.Args.AddAllArgs(Arguments, options::OPT_linker_option_Group); // Run clang++ in verbose mode if "-v" is set if (context.Args.hasArg(options::OPT_v)) { Arguments.push_back("-v"); } // This should be the last option, for convenience in checking output. Arguments.push_back("-o"); Arguments.push_back( context.Args.MakeArgString(context.Output.getPrimaryOutputFilename())); InvocationInfo II{Clang, Arguments}; II.allowsResponseFiles = true; return II; }
ToolChain::InvocationInfo toolchains::Windows::constructInvocation(const LinkJobAction &job, const JobContext &context) const { const Driver &D = getDriver(); assert(context.Output.getPrimaryOutputType() == types::TY_Image && "Invalid linker output type."); ArgStringList Arguments; switch (job.getKind()) { case LinkKind::None: llvm_unreachable("invalid link kind"); case LinkKind::Executable: // Default case, nothing extra needed break; case LinkKind::DynamicLibrary: Arguments.push_back("-shared"); break; } addPrimaryInputsOfType(Arguments, context.Inputs, types::TY_Object); addInputsOfType(Arguments, context.InputActions, types::TY_Object); context.Args.AddAllArgs(Arguments, options::OPT_Xlinker); context.Args.AddAllArgs(Arguments, options::OPT_linker_option_Group); context.Args.AddAllArgs(Arguments, options::OPT_F); if (!context.OI.SDKPath.empty()) { Arguments.push_back("--sysroot"); Arguments.push_back(context.Args.MakeArgString(context.OI.SDKPath)); } // Add the runtime library link path, which is platform-specific and found // relative to the compiler. // FIXME: Duplicated from CompilerInvocation, but in theory the runtime // library link path and the standard library module import path don't // need to be the same. llvm::SmallString<128> RuntimeLibPath; if (const Arg *A = context.Args.getLastArg(options::OPT_resource_dir)) { RuntimeLibPath = A->getValue(); } else { RuntimeLibPath = D.getSwiftProgramPath(); llvm::sys::path::remove_filename(RuntimeLibPath); // remove /swift llvm::sys::path::remove_filename(RuntimeLibPath); // remove /bin llvm::sys::path::append(RuntimeLibPath, "lib", "swift"); } llvm::sys::path::append(RuntimeLibPath, getPlatformNameForTriple(getTriple())); 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); llvm::sys::path::append(LibProfile, "lib", getTriple().getOSName(), Twine("libclang_rt.profile-") + getTriple().getArchName() + ".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("-Xlinker"); Arguments.push_back("-rpath"); Arguments.push_back("-Xlinker"); Arguments.push_back(context.Args.MakeArgString(RuntimeLibPath)); // Always add the stdlib Arguments.push_back("-lswiftCore"); // Add any autolinking scripts to the arguments for (const Job *Cmd : context.Inputs) { auto &OutputInfo = Cmd->getOutput(); if (OutputInfo.getPrimaryOutputType() == types::TY_AutolinkFile) Arguments.push_back(context.Args.MakeArgString( Twine("@") + OutputInfo.getPrimaryOutputFilename())); } // This should be the last option, for convenience in checking output. Arguments.push_back("-o"); Arguments.push_back(context.Output.getPrimaryOutputFilename().c_str()); return {"clang++", Arguments}; }
ToolChain::InvocationInfo toolchains::GenericUnix::constructInvocation(const LinkJobAction &job, const JobContext &context) const { const Driver &D = getDriver(); assert(context.Output.getPrimaryOutputType() == types::TY_Image && "Invalid linker output type."); ArgStringList Arguments; switch (job.getKind()) { case LinkKind::None: llvm_unreachable("invalid link kind"); case LinkKind::Executable: // Default case, nothing extra needed break; case LinkKind::DynamicLibrary: Arguments.push_back("-shared"); break; } // Select the linker to use StringRef Linker; if (const Arg *A = context.Args.getLastArg(options::OPT_use_ld)) { Linker = A->getValue(); } else { switch(getTriple().getArch()) { default: break; case llvm::Triple::arm: case llvm::Triple::armeb: case llvm::Triple::thumb: case llvm::Triple::thumbeb: // BFD linker has issues wrt relocation of the protocol conformance // section on these targets, it also generates COPY relocations for // final executables, as such, unless specified, we default to gold // linker. Linker = "gold"; } } if (!Linker.empty()) { Arguments.push_back(context.Args.MakeArgString("-fuse-ld=" + Linker)); } // Add the runtime library link path, which is platform-specific and found // relative to the compiler. // FIXME: Duplicated from CompilerInvocation, but in theory the runtime // library link path and the standard library module import path don't // need to be the same. llvm::SmallString<128> RuntimeLibPath; if (const Arg *A = context.Args.getLastArg(options::OPT_resource_dir)) { RuntimeLibPath = A->getValue(); } else { RuntimeLibPath = D.getSwiftProgramPath(); llvm::sys::path::remove_filename(RuntimeLibPath); // remove /swift llvm::sys::path::remove_filename(RuntimeLibPath); // remove /bin llvm::sys::path::append(RuntimeLibPath, "lib", "swift"); } llvm::sys::path::append(RuntimeLibPath, getPlatformNameForTriple(getTriple())); // On Linux and FreeBSD (really, ELF binaries) we need to add objects // to provide markers and size for the metadata sections. Arguments.push_back(context.Args.MakeArgString( Twine(RuntimeLibPath) + "/" + getSectionMagicArch(getTriple()) + "/swift_begin.o")); addPrimaryInputsOfType(Arguments, context.Inputs, types::TY_Object); addInputsOfType(Arguments, context.InputActions, types::TY_Object); context.Args.AddAllArgs(Arguments, options::OPT_Xlinker); context.Args.AddAllArgs(Arguments, options::OPT_linker_option_Group); context.Args.AddAllArgs(Arguments, options::OPT_F); if (!context.OI.SDKPath.empty()) { Arguments.push_back("--sysroot"); Arguments.push_back(context.Args.MakeArgString(context.OI.SDKPath)); } Arguments.push_back("-L"); Arguments.push_back(context.Args.MakeArgString(RuntimeLibPath)); // Explicitly pass the target to the linker Arguments.push_back(context.Args.MakeArgString("--target=" + getTriple().str())); 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", "lib"); llvm::sys::path::append(LibProfile, getTriple().getOSName(), Twine("libclang_rt.profile-") + getTriple().getArchName() + ".a"); Arguments.push_back(context.Args.MakeArgString(LibProfile)); } if (getTriple().isAndroid()) { // FIXME: These should be set in CMake. Arguments.push_back("-target"); Arguments.push_back("armv7-none-linux-androideabi"); const char* ndkhome = getenv("ANDROID_NDK_HOME"); assert(ndkhome && "ANDROID_NDK_HOME needs to be set to NDK " "install directory for linking"); auto libgccpath = Twine(ndkhome) + "/toolchains/" "arm-linux-androideabi-4.8/prebuilt/linux-x86_64/" "lib/gcc/arm-linux-androideabi/4.8"; Arguments.push_back("-L"); Arguments.push_back(context.Args.MakeArgString(libgccpath)); auto libcxxpath = Twine(ndkhome) + "/sources/" "cxx-stl/llvm-libc++/libs/armeabi-v7a"; Arguments.push_back("-L"); Arguments.push_back(context.Args.MakeArgString(libcxxpath)); } else { // 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("-Xlinker"); Arguments.push_back("-rpath"); Arguments.push_back("-Xlinker"); Arguments.push_back(context.Args.MakeArgString(RuntimeLibPath)); } // Always add the stdlib Arguments.push_back("-lswiftCore"); // Add any autolinking scripts to the arguments for (const Job *Cmd : context.Inputs) { auto &OutputInfo = Cmd->getOutput(); if (OutputInfo.getPrimaryOutputType() == types::TY_AutolinkFile) Arguments.push_back(context.Args.MakeArgString( Twine("@") + OutputInfo.getPrimaryOutputFilename())); } // It is important that swift_end.o be the last object on the link line // therefore, it is included just before the output filename. Arguments.push_back(context.Args.MakeArgString( Twine(RuntimeLibPath) + "/" + getSectionMagicArch(getTriple()) + "/swift_end.o")); // This should be the last option, for convenience in checking output. Arguments.push_back("-o"); Arguments.push_back(context.Output.getPrimaryOutputFilename().c_str()); return {"clang++", Arguments}; }
ToolChain::InvocationInfo toolchains::GenericUnix::constructInvocation(const LinkJobAction &job, const JobContext &context) const { assert(context.Output.getPrimaryOutputType() == file_types::TY_Image && "Invalid linker output type."); ArgStringList Arguments; switch (job.getKind()) { case LinkKind::None: llvm_unreachable("invalid link kind"); case LinkKind::Executable: // Default case, nothing extra needed. break; case LinkKind::DynamicLibrary: Arguments.push_back("-shared"); break; } // Select the linker to use. std::string Linker; if (const Arg *A = context.Args.getLastArg(options::OPT_use_ld)) { Linker = A->getValue(); } else { Linker = getDefaultLinker(); } if (!Linker.empty()) { #if defined(__HAIKU__) // For now, passing -fuse-ld on Haiku doesn't work as swiftc doesn't // recognise it. Passing -use-ld= as the argument works fine. Arguments.push_back(context.Args.MakeArgString("-use-ld=" + Linker)); #else Arguments.push_back(context.Args.MakeArgString("-fuse-ld=" + Linker)); #endif } // Configure the toolchain. // By default, use the system clang++ to link. const char *Clang = "clang++"; if (const Arg *A = context.Args.getLastArg(options::OPT_tools_directory)) { StringRef toolchainPath(A->getValue()); // If there is a clang in the toolchain folder, use that instead. if (auto toolchainClang = llvm::sys::findProgramByName("clang++", {toolchainPath})) { Clang = context.Args.MakeArgString(toolchainClang.get()); } // Look for binutils in the toolchain folder. Arguments.push_back("-B"); Arguments.push_back(context.Args.MakeArgString(A->getValue())); } if (getTriple().getOS() == llvm::Triple::Linux && job.getKind() == LinkKind::Executable) { Arguments.push_back("-pie"); } std::string Target = getTargetForLinker(); if (!Target.empty()) { Arguments.push_back("-target"); Arguments.push_back(context.Args.MakeArgString(Target)); } bool staticExecutable = false; bool staticStdlib = false; if (context.Args.hasFlag(options::OPT_static_executable, options::OPT_no_static_executable, false)) { staticExecutable = true; } else if (context.Args.hasFlag(options::OPT_static_stdlib, options::OPT_no_static_stdlib, false)) { staticStdlib = true; } SmallString<128> SharedRuntimeLibPath; getRuntimeLibraryPath(SharedRuntimeLibPath, context.Args, /*Shared=*/true); SmallString<128> StaticRuntimeLibPath; getRuntimeLibraryPath(StaticRuntimeLibPath, context.Args, /*Shared=*/false); // Add the runtime library link path, which is platform-specific and found // relative to the compiler. if (!(staticExecutable || staticStdlib) && shouldProvideRPathToLinker()) { // 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("-Xlinker"); Arguments.push_back("-rpath"); Arguments.push_back("-Xlinker"); Arguments.push_back(context.Args.MakeArgString(SharedRuntimeLibPath)); } SmallString<128> swiftrtPath = SharedRuntimeLibPath; llvm::sys::path::append(swiftrtPath, swift::getMajorArchitectureName(getTriple())); llvm::sys::path::append(swiftrtPath, "swiftrt.o"); Arguments.push_back(context.Args.MakeArgString(swiftrtPath)); addPrimaryInputsOfType(Arguments, context.Inputs, context.Args, file_types::TY_Object); addInputsOfType(Arguments, context.InputActions, file_types::TY_Object); for (const Arg *arg : context.Args.filtered(options::OPT_F, options::OPT_Fsystem)) { if (arg->getOption().matches(options::OPT_Fsystem)) Arguments.push_back("-iframework"); else Arguments.push_back(context.Args.MakeArgString(arg->getSpelling())); Arguments.push_back(arg->getValue()); } if (!context.OI.SDKPath.empty()) { Arguments.push_back("--sysroot"); Arguments.push_back(context.Args.MakeArgString(context.OI.SDKPath)); } // Add any autolinking scripts to the arguments for (const Job *Cmd : context.Inputs) { auto &OutputInfo = Cmd->getOutput(); if (OutputInfo.getPrimaryOutputType() == file_types::TY_AutolinkFile) Arguments.push_back(context.Args.MakeArgString( Twine("@") + OutputInfo.getPrimaryOutputFilename())); } // Link the standard library. Arguments.push_back("-L"); if (staticExecutable) { Arguments.push_back(context.Args.MakeArgString(StaticRuntimeLibPath)); SmallString<128> linkFilePath = StaticRuntimeLibPath; llvm::sys::path::append(linkFilePath, "static-executable-args.lnk"); auto linkFile = linkFilePath.str(); if (llvm::sys::fs::is_regular_file(linkFile)) { Arguments.push_back(context.Args.MakeArgString(Twine("@") + linkFile)); } else { llvm::report_fatal_error( "-static-executable not supported on this platform"); } } else if (staticStdlib) { Arguments.push_back(context.Args.MakeArgString(StaticRuntimeLibPath)); SmallString<128> linkFilePath = StaticRuntimeLibPath; llvm::sys::path::append(linkFilePath, "static-stdlib-args.lnk"); auto linkFile = linkFilePath.str(); if (llvm::sys::fs::is_regular_file(linkFile)) { Arguments.push_back(context.Args.MakeArgString(Twine("@") + linkFile)); } else { llvm::report_fatal_error(linkFile + " not found"); } } else { Arguments.push_back(context.Args.MakeArgString(SharedRuntimeLibPath)); Arguments.push_back("-lswiftCore"); } // Explicitly pass the target to the linker Arguments.push_back( context.Args.MakeArgString("--target=" + getTriple().str())); if (getTriple().getOS() == llvm::Triple::Linux) { // Make sure we only add SanitizerLibs for executables if (job.getKind() == LinkKind::Executable) { if (context.OI.SelectedSanitizers & SanitizerKind::Address) addLinkSanitizerLibArgsForLinux(context.Args, Arguments, "asan", *this); if (context.OI.SelectedSanitizers & SanitizerKind::Thread) addLinkSanitizerLibArgsForLinux(context.Args, Arguments, "tsan", *this); if (context.OI.SelectedSanitizers & SanitizerKind::Fuzzer) addLinkRuntimeLib(context.Args, Arguments, sanitizerRuntimeLibName("fuzzer")); } } if (context.Args.hasArg(options::OPT_profile_generate)) { SmallString<128> LibProfile(SharedRuntimeLibPath); llvm::sys::path::remove_filename(LibProfile); // remove platform name llvm::sys::path::append(LibProfile, "clang", "lib"); llvm::sys::path::append(LibProfile, getTriple().getOSName(), Twine("libclang_rt.profile-") + getTriple().getArchName() + ".a"); Arguments.push_back(context.Args.MakeArgString(LibProfile)); Arguments.push_back(context.Args.MakeArgString( Twine("-u", llvm::getInstrProfRuntimeHookVarName()))); } context.Args.AddAllArgs(Arguments, options::OPT_Xlinker); context.Args.AddAllArgs(Arguments, options::OPT_linker_option_Group); // This should be the last option, for convenience in checking output. Arguments.push_back("-o"); Arguments.push_back( context.Args.MakeArgString(context.Output.getPrimaryOutputFilename())); InvocationInfo II{Clang, Arguments}; II.allowsResponseFiles = true; return II; }
ToolChain::InvocationInfo toolchains::Darwin::constructInvocation(const LinkJobAction &job, const JobContext &context) const { assert(context.Output.getPrimaryOutputType() == file_types::TY_Image && "Invalid linker output type."); if (context.Args.hasFlag(options::OPT_static_executable, options::OPT_no_static_executable, false)) { llvm::report_fatal_error("-static-executable is not supported on Darwin"); } const Driver &D = getDriver(); const llvm::Triple &Triple = getTriple(); // Configure the toolchain. // By default, use the system `ld` to link. const char *LD = "ld"; if (const Arg *A = context.Args.getLastArg(options::OPT_tools_directory)) { StringRef toolchainPath(A->getValue()); // If there is a 'ld' in the toolchain folder, use that instead. if (auto toolchainLD = llvm::sys::findProgramByName("ld", {toolchainPath})) { LD = context.Args.MakeArgString(toolchainLD.get()); } } InvocationInfo II = {LD}; ArgStringList &Arguments = II.Arguments; if (context.shouldUseInputFileList()) { Arguments.push_back("-filelist"); Arguments.push_back(context.getTemporaryFilePath("inputs", "LinkFileList")); II.FilelistInfos.push_back({Arguments.back(), file_types::TY_Object, FilelistInfo::WhichFiles::Input}); } else { addPrimaryInputsOfType(Arguments, context.Inputs, context.Args, file_types::TY_Object); } addInputsOfType(Arguments, context.InputActions, file_types::TY_Object); if (context.OI.CompilerMode == OutputInfo::Mode::SingleCompile) addInputsOfType(Arguments, context.Inputs, context.Args, file_types::TY_SwiftModuleFile, "-add_ast_path"); else addPrimaryInputsOfType(Arguments, context.Inputs, context.Args, file_types::TY_SwiftModuleFile, "-add_ast_path"); // Add all .swiftmodule file inputs as arguments, preceded by the // "-add_ast_path" linker option. addInputsOfType(Arguments, context.InputActions, file_types::TY_SwiftModuleFile, "-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 a bunch of Clang's logic here. // Always link the regular compiler_rt if it's present. // // Note: Normally we'd just add this unconditionally, but it's valid to build // Swift and use it as a linker without building compiler_rt. SmallString<128> CompilerRTPath; getClangLibraryPath(context.Args, CompilerRTPath); llvm::sys::path::append( CompilerRTPath, Twine("libclang_rt.") + getDarwinLibraryNameSuffixForTriple(Triple, /*simulator*/false) + ".a"); if (llvm::sys::fs::exists(CompilerRTPath)) Arguments.push_back(context.Args.MakeArgString(CompilerRTPath)); if (context.Args.hasFlag(options::OPT_link_objc_runtime, options::OPT_no_link_objc_runtime, /*Default=*/wantsObjCRuntime(Triple))) { 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); for (const Arg *arg : context.Args.filtered(options::OPT_F, options::OPT_Fsystem)) { Arguments.push_back("-F"); Arguments.push_back(arg->getValue()); } 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"); } // Linking sanitizers will add rpaths, which might negatively interact when // other rpaths are involved, so we should make sure we add the rpaths after // all user-specified rpaths. if (context.OI.SelectedSanitizers & SanitizerKind::Address) addLinkSanitizerLibArgsForDarwin(context.Args, Arguments, "asan", *this); if (context.OI.SelectedSanitizers & SanitizerKind::Thread) addLinkSanitizerLibArgsForDarwin(context.Args, Arguments, "tsan", *this); // Only link in libFuzzer for executables. if (job.getKind() == LinkKind::Executable && (context.OI.SelectedSanitizers & SanitizerKind::Fuzzer)) addLinkSanitizerLibArgsForDarwin(context.Args, Arguments, "fuzzer", *this, /*shared=*/false); 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, /*Shared=*/true); // Link the standard library. Arguments.push_back("-L"); if (context.Args.hasFlag(options::OPT_static_stdlib, options::OPT_no_static_stdlib, false)) { SmallString<128> StaticRuntimeLibPath; getRuntimeLibraryPath(StaticRuntimeLibPath, context.Args, /*Shared=*/false); Arguments.push_back(context.Args.MakeArgString(StaticRuntimeLibPath)); Arguments.push_back("-lc++"); Arguments.push_back("-framework"); Arguments.push_back("Foundation"); Arguments.push_back("-force_load_swift_libs"); } else { Arguments.push_back(context.Args.MakeArgString(RuntimeLibPath)); // FIXME: We probably shouldn't be adding an rpath here unless we know ahead // of time the standard library won't be copied. SR-1967 Arguments.push_back("-rpath"); Arguments.push_back(context.Args.MakeArgString(RuntimeLibPath)); } if (context.Args.hasArg(options::OPT_profile_generate)) { SmallString<128> LibProfile; getClangLibraryPath(context.Args, LibProfile); StringRef RT; if (Triple.isiOS()) { if (Triple.isTvOS()) RT = "tvos"; else RT = "ios"; } else if (Triple.isWatchOS()) { RT = "watchos"; } else { assert(Triple.isMacOSX()); RT = "osx"; } StringRef Sim; if (tripleIsAnySimulator(Triple)) { Sim = "sim"; } llvm::sys::path::append(LibProfile, "libclang_rt.profile_" + RT + Sim + ".a"); // FIXME: Continue accepting the old path for simulator libraries for now. if (!Sim.empty() && !llvm::sys::fs::exists(LibProfile)) { llvm::sys::path::remove_filename(LibProfile); llvm::sys::path::append(LibProfile, "libclang_rt.profile_" + RT + ".a"); } Arguments.push_back(context.Args.MakeArgString(LibProfile)); } // 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.Args.MakeArgString(context.Output.getPrimaryOutputFilename())); return II; }