diff --git a/include/swift/AST/IRGenOptions.h b/include/swift/AST/IRGenOptions.h index c4a7965e292..82c550a0ca1 100644 --- a/include/swift/AST/IRGenOptions.h +++ b/include/swift/AST/IRGenOptions.h @@ -59,6 +59,10 @@ public: /// The libraries and frameworks specified on the command line. SmallVector LinkLibraries; + /// If non-empty, the (unmangled) name of a dummy symbol to emit that can be + /// used to force-load this module. + std::string ForceLoadSymbolName; + /// The kind of compilation we should do. IRGenOutputKind OutputKind : 3; @@ -87,7 +91,7 @@ public: /// \brief Whether we should omit dynamic safety checks from the emitted IR. unsigned DisableAllRuntimeChecks : 1; - // Disable frame pointer elimination? + /// Disable frame pointer elimination? unsigned DisableFPElim : 1; IRGenOptions() : OutputKind(IRGenOutputKind::LLVMAssembly), Verify(true), diff --git a/include/swift/Driver/Options.td b/include/swift/Driver/Options.td index 62d38255620..d58f6b59186 100644 --- a/include/swift/Driver/Options.td +++ b/include/swift/Driver/Options.td @@ -151,6 +151,9 @@ def module_link_name : Separate<["-"], "module-link-name">, HelpText<"Library to link against when using this module">; def module_link_name_EQ : Joined<["-"], "module-link-name=">, Flags<[FrontendOption]>, Alias; +def autolink_force_load : Flag<["-"], "autolink-force-load">, + Flags<[FrontendOption, HelpHidden]>, + HelpText<"Force ld to link against this module even if no symbols are used">; def emit_module : Flag<["-"], "emit-module">, Flags<[FrontendOption]>, HelpText<"Emit an importable module">; diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index d901156ac41..3aa7c799f13 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -263,6 +263,9 @@ Job *Swift::constructJob(const JobAction &JA, std::unique_ptr Inputs, Args.AddLastArg(Arguments, options::OPT_module_link_name); Args.AddLastArg(Arguments, options::OPT_import_underlying_module); + // FIXME: Warn if -module-link-name is not present. + Args.AddLastArg(Arguments, options::OPT_autolink_force_load); + Args.AddLastArg(Arguments, options::OPT_split_objc_selectors); Args.AddLastArg(Arguments, options::OPT_implicit_objc_with); Args.AddLastArg(Arguments, options::OPT_strict_keyword_arguments); diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 1c0da9e6551..1ac6d504130 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -858,6 +858,9 @@ static bool ParseIRGenArgs(IRGenOptions &Opts, ArgList &Args, Opts.EnableDynamicValueTypeLayout = true; } + if (Args.hasArg(OPT_autolink_force_load)) + Opts.ForceLoadSymbolName = Args.getLastArgValue(OPT_module_link_name); + if (const Arg *A = Args.getLastArg(OPT_target)) { Opts.Triple = llvm::Triple::normalize(A->getValue()); } diff --git a/lib/IRGen/IRGenModule.cpp b/lib/IRGen/IRGenModule.cpp index 5add6f23d7e..bb329ad2086 100644 --- a/lib/IRGen/IRGenModule.cpp +++ b/lib/IRGen/IRGenModule.cpp @@ -20,6 +20,7 @@ #include "swift/AST/IRGenOptions.h" #include "swift/ClangImporter/ClangImporter.h" #include "clang/AST/ASTContext.h" +#include "clang/Basic/CharInfo.h" #include "clang/Basic/TargetInfo.h" #include "clang/CodeGen/CodeGenABITypes.h" #include "clang/CodeGen/ModuleBuilder.h" @@ -424,6 +425,19 @@ static int pointerPODSortComparator(T * const *lhs, T * const *rhs) { return 0; } +static StringRef encodeForceLoadSymbolName(llvm::SmallVectorImpl &buf, + StringRef name) { + llvm::raw_svector_ostream os{buf}; + os << "_swift_FORCE_LOAD_$"; + if (clang::isValidIdentifier(name)) { + os << "_" << name; + } else { + for (auto c : name) + os.write_hex(static_cast(c)); + } + return os.str(); +} + void IRGenModule::emitAutolinkInfo() { // FIXME: This constant should be vended by LLVM somewhere. static const char * const LinkerOptionsFlagName = "Linker Options"; @@ -437,6 +451,15 @@ void IRGenModule::emitAutolinkInfo() { llvm::LLVMContext &ctx = Module.getContext(); Module.addModuleFlag(llvm::Module::AppendUnique, LinkerOptionsFlagName, llvm::MDNode::get(ctx, AutolinkEntries)); + + if (!Opts.ForceLoadSymbolName.empty()) { + llvm::SmallString<64> buf; + encodeForceLoadSymbolName(buf, Opts.ForceLoadSymbolName); + (void)new llvm::GlobalVariable(Module, Int1Ty, /*constant=*/true, + llvm::GlobalVariable::LinkOnceAnyLinkage, + llvm::Constant::getNullValue(Int1Ty), + buf.str()); + } } void IRGenModule::finalize() {