diff --git a/include/swift/AST/DiagnosticsDriver.def b/include/swift/AST/DiagnosticsDriver.def index 74561817ca550..3fc50d240d8e5 100644 --- a/include/swift/AST/DiagnosticsDriver.def +++ b/include/swift/AST/DiagnosticsDriver.def @@ -64,6 +64,9 @@ ERROR(error_expected_frontend_command,none, ERROR(error_cannot_specify__o_for_multiple_outputs,none, "cannot specify -o when generating multiple output files", ()) +ERROR(error_static_emit_executable_disallowed,none, + "-static may not be used with -emit-executable", ()) + ERROR(error_unable_to_load_output_file_map, none, "unable to load output file map '%1': %0", (StringRef, StringRef)) diff --git a/include/swift/Driver/Action.h b/include/swift/Driver/Action.h index c230b0925ecc7..4dae1eb336ba0 100644 --- a/include/swift/Driver/Action.h +++ b/include/swift/Driver/Action.h @@ -47,7 +47,8 @@ class Action { ModuleWrapJob, AutolinkExtractJob, REPLJob, - LinkJob, + DynamicLinkJob, + StaticLinkJob, GenerateDSYMJob, VerifyDebugInfoJob, GeneratePCHJob, @@ -305,21 +306,35 @@ class GeneratePCHJobAction : public JobAction { } }; -class LinkJobAction : public JobAction { +class DynamicLinkJobAction : public JobAction { virtual void anchor(); LinkKind Kind; public: - LinkJobAction(ArrayRef Inputs, LinkKind K) - : JobAction(Action::Kind::LinkJob, Inputs, file_types::TY_Image), + DynamicLinkJobAction(ArrayRef Inputs, LinkKind K) + : JobAction(Action::Kind::DynamicLinkJob, Inputs, file_types::TY_Image), Kind(K) { - assert(Kind != LinkKind::None); + assert(Kind != LinkKind::None && Kind != LinkKind::StaticLibrary); } LinkKind getKind() const { return Kind; } static bool classof(const Action *A) { - return A->getKind() == Action::Kind::LinkJob; + return A->getKind() == Action::Kind::DynamicLinkJob; + } +}; + +class StaticLinkJobAction : public JobAction { + virtual void anchor(); + +public: + StaticLinkJobAction(ArrayRef Inputs, LinkKind K) + : JobAction(Action::Kind::StaticLinkJob, Inputs, file_types::TY_Image) { + assert(K == LinkKind::StaticLibrary); + } + + static bool classof(const Action *A) { + return A->getKind() == Action::Kind::StaticLinkJob; } }; diff --git a/include/swift/Driver/ToolChain.h b/include/swift/Driver/ToolChain.h index c8b28c02d72e0..f85e0a0b821fa 100644 --- a/include/swift/Driver/ToolChain.h +++ b/include/swift/Driver/ToolChain.h @@ -158,7 +158,10 @@ class ToolChain { virtual InvocationInfo constructInvocation(const AutolinkExtractJobAction &job, const JobContext &context) const; - virtual InvocationInfo constructInvocation(const LinkJobAction &job, + virtual InvocationInfo constructInvocation(const DynamicLinkJobAction &job, + const JobContext &context) const; + + virtual InvocationInfo constructInvocation(const StaticLinkJobAction &job, const JobContext &context) const; /// Searches for the given executable in appropriate paths relative to the diff --git a/include/swift/Driver/Util.h b/include/swift/Driver/Util.h index 9859f0a8387af..8f9fd30357fe1 100644 --- a/include/swift/Driver/Util.h +++ b/include/swift/Driver/Util.h @@ -34,7 +34,8 @@ namespace driver { enum class LinkKind { None, Executable, - DynamicLibrary + DynamicLibrary, + StaticLibrary }; /// Used by a Job to request a "filelist": a file containing a list of all diff --git a/include/swift/Option/Options.td b/include/swift/Option/Options.td index d9b58a0ba6ac6..656eabb124c71 100644 --- a/include/swift/Option/Options.td +++ b/include/swift/Option/Options.td @@ -368,6 +368,10 @@ def emit_objc_header_path : Separate<["-"], "emit-objc-header-path">, ArgumentIsPath]>, MetaVarName<"">, HelpText<"Emit an Objective-C header file to ">; +def static : Flag<["-"], "static">, + Flags<[FrontendOption, ModuleInterfaceOption, NoInteractiveOption]>, + HelpText<"Make this module statically linkable and make the output of -emit-library a static library.">; + def import_cf_types : Flag<["-"], "import-cf-types">, Flags<[FrontendOption, HelpHidden]>, HelpText<"Recognize and import CF types as class types">; diff --git a/lib/Driver/Action.cpp b/lib/Driver/Action.cpp index 95df884e3530c..0dcde774e73f8 100644 --- a/lib/Driver/Action.cpp +++ b/lib/Driver/Action.cpp @@ -28,7 +28,8 @@ const char *Action::getClassName(Kind AC) { case Kind::ModuleWrapJob: return "modulewrap"; case Kind::AutolinkExtractJob: return "swift-autolink-extract"; case Kind::REPLJob: return "repl"; - case Kind::LinkJob: return "link"; + case Kind::DynamicLinkJob: return "link"; + case Kind::StaticLinkJob: return "static-link"; case Kind::GenerateDSYMJob: return "generate-dSYM"; case Kind::VerifyDebugInfoJob: return "verify-debug-info"; case Kind::GeneratePCHJob: return "generate-pch"; @@ -55,7 +56,9 @@ void AutolinkExtractJobAction::anchor() {} void REPLJobAction::anchor() {} -void LinkJobAction::anchor() {} +void DynamicLinkJobAction::anchor() {} + +void StaticLinkJobAction::anchor() {} void GenerateDSYMJobAction::anchor() {} diff --git a/lib/Driver/DarwinToolChains.cpp b/lib/Driver/DarwinToolChains.cpp index 2c10be0348c52..afa01c6b62b5e 100644 --- a/lib/Driver/DarwinToolChains.cpp +++ b/lib/Driver/DarwinToolChains.cpp @@ -223,9 +223,8 @@ static bool wantsObjCRuntime(const llvm::Triple &triple) { } ToolChain::InvocationInfo -toolchains::Darwin::constructInvocation(const LinkJobAction &job, - const JobContext &context) const -{ +toolchains::Darwin::constructInvocation(const DynamicLinkJobAction &job, + const JobContext &context) const { assert(context.Output.getPrimaryOutputType() == file_types::TY_Image && "Invalid linker output type."); @@ -286,6 +285,8 @@ toolchains::Darwin::constructInvocation(const LinkJobAction &job, case LinkKind::DynamicLibrary: Arguments.push_back("-dylib"); break; + case LinkKind::StaticLibrary: + llvm_unreachable("the dynamic linker cannot build static libraries"); } assert(Triple.isOSDarwin()); @@ -527,6 +528,41 @@ toolchains::Darwin::constructInvocation(const LinkJobAction &job, return II; } + +ToolChain::InvocationInfo +toolchains::Darwin::constructInvocation(const StaticLinkJobAction &job, + const JobContext &context) const { + assert(context.Output.getPrimaryOutputType() == file_types::TY_Image && + "Invalid linker output type."); + + // Configure the toolchain. + const char *LibTool = "libtool"; + + InvocationInfo II = {LibTool}; + ArgStringList &Arguments = II.Arguments; + + Arguments.push_back("-static"); + + 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); + + Arguments.push_back("-o"); + + Arguments.push_back( + context.Args.MakeArgString(context.Output.getPrimaryOutputFilename())); + + return II; +} + bool toolchains::Darwin::shouldStoreInvocationInDebugInfo() const { // This matches the behavior in Clang (see // clang/lib/driver/ToolChains/Darwin.cpp). diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index 03ab3dfaff725..a5920f909e007 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -1255,6 +1255,8 @@ static bool maybeBuildingExecutable(const OutputInfo &OI, return true; case LinkKind::DynamicLibrary: return false; + case LinkKind::StaticLibrary: + return false; case LinkKind::None: break; } @@ -1366,15 +1368,24 @@ void Driver::buildOutputInfo(const ToolChain &TC, const DerivedArgList &Args, switch (OutputModeArg->getOption().getID()) { case options::OPT_emit_executable: + if (Args.hasArg(options::OPT_static)) + Diags.diagnose(SourceLoc(), + diag::error_static_emit_executable_disallowed); + OI.LinkAction = LinkKind::Executable; OI.CompilerOutputType = file_types::TY_Object; break; case options::OPT_emit_library: - OI.LinkAction = LinkKind::DynamicLibrary; + OI.LinkAction = Args.hasArg(options::OPT_static) ? + LinkKind::StaticLibrary : + LinkKind::DynamicLibrary; OI.CompilerOutputType = file_types::TY_Object; break; + case options::OPT_static: + break; + case options::OPT_emit_object: OI.CompilerOutputType = file_types::TY_Object; break; @@ -1550,7 +1561,8 @@ void Driver::buildOutputInfo(const ToolChain &TC, const DerivedArgList &Args, OI.ModuleName = "REPL"; } else if (const Arg *A = Args.getLastArg(options::OPT_o)) { OI.ModuleName = llvm::sys::path::stem(A->getValue()); - if (OI.LinkAction == LinkKind::DynamicLibrary && + if ((OI.LinkAction == LinkKind::DynamicLibrary || + OI.LinkAction == LinkKind::StaticLibrary) && !llvm::sys::path::extension(A->getValue()).empty() && StringRef(OI.ModuleName).startswith("lib")) { // Chop off a "lib" prefix if we're building a library. @@ -1949,8 +1961,15 @@ void Driver::buildActions(SmallVectorImpl &TopLevelActions, } if (OI.shouldLink() && !AllLinkerInputs.empty()) { - auto *LinkAction = C.createAction(AllLinkerInputs, - OI.LinkAction); + JobAction *LinkAction = nullptr; + + if (OI.LinkAction == LinkKind::StaticLibrary) { + LinkAction = C.createAction(AllLinkerInputs, + OI.LinkAction); + } else { + LinkAction = C.createAction(AllLinkerInputs, + OI.LinkAction); + } // On ELF platforms there's no built in autolinking mechanism, so we // pull the info we need from the .o files directly and pass them as an @@ -2177,7 +2196,15 @@ static StringRef baseNameForImage(const JobAction *JA, const OutputInfo &OI, StringRef BaseInput, StringRef BaseName) { if (JA->size() == 1 && OI.ModuleNameIsFallback && BaseInput != "-") return llvm::sys::path::stem(BaseInput); - auto link = dyn_cast(JA); + + if (auto link = dyn_cast(JA)) { + Buffer = "lib"; + Buffer.append(BaseName); + Buffer.append(Triple.isOSWindows() ? ".lib" : ".a"); + return Buffer.str(); + } + + auto link = dyn_cast(JA); if (!link) return BaseName; if (link->getKind() != LinkKind::DynamicLibrary) diff --git a/lib/Driver/ToolChain.cpp b/lib/Driver/ToolChain.cpp index 321d9aef16b55..13fac45ff0c60 100644 --- a/lib/Driver/ToolChain.cpp +++ b/lib/Driver/ToolChain.cpp @@ -99,7 +99,8 @@ std::unique_ptr ToolChain::constructJob( CASE(BackendJob) CASE(MergeModuleJob) CASE(ModuleWrapJob) - CASE(LinkJob) + CASE(DynamicLinkJob) + CASE(StaticLinkJob) CASE(GenerateDSYMJob) CASE(VerifyDebugInfoJob) CASE(GeneratePCHJob) diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index 27529cf24bd4b..a6de0fbe5acf8 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -208,6 +208,7 @@ static void addCommonFrontendArgs(const ToolChain &TC, const OutputInfo &OI, inputArgs.AddLastArg(arguments, options::OPT_warnings_as_errors); inputArgs.AddLastArg(arguments, options::OPT_sanitize_EQ); inputArgs.AddLastArg(arguments, options::OPT_sanitize_coverage_EQ); + inputArgs.AddLastArg(arguments, options::OPT_static); inputArgs.AddLastArg(arguments, options::OPT_swift_version); inputArgs.AddLastArg(arguments, options::OPT_enforce_exclusivity_EQ); inputArgs.AddLastArg(arguments, options::OPT_stats_output_dir); @@ -1086,11 +1087,17 @@ ToolChain::constructInvocation(const AutolinkExtractJobAction &job, } ToolChain::InvocationInfo -ToolChain::constructInvocation(const LinkJobAction &job, +ToolChain::constructInvocation(const DynamicLinkJobAction &job, const JobContext &context) const { llvm_unreachable("linking not implemented for this toolchain"); } +ToolChain::InvocationInfo +ToolChain::constructInvocation(const StaticLinkJobAction &job, + const JobContext &context) const { + llvm_unreachable("archiving not implemented for this toolchain"); +} + void ToolChain::addPathEnvironmentVariableIfNeeded( Job::EnvironmentVector &env, const char *name, const char *separator, options::ID optionID, const ArgList &args, StringRef extraEntry) const { diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h index 78dfda881b99e..efdb6638c7815 100644 --- a/lib/Driver/ToolChains.h +++ b/lib/Driver/ToolChains.h @@ -25,7 +25,9 @@ class LLVM_LIBRARY_VISIBILITY Darwin : public ToolChain { protected: InvocationInfo constructInvocation(const InterpretJobAction &job, const JobContext &context) const override; - InvocationInfo constructInvocation(const LinkJobAction &job, + InvocationInfo constructInvocation(const DynamicLinkJobAction &job, + const JobContext &context) const override; + InvocationInfo constructInvocation(const StaticLinkJobAction &job, const JobContext &context) const override; std::string findProgramRelativeToSwiftImpl(StringRef name) const override; @@ -41,7 +43,9 @@ class LLVM_LIBRARY_VISIBILITY Darwin : public ToolChain { class LLVM_LIBRARY_VISIBILITY Windows : public ToolChain { protected: - InvocationInfo constructInvocation(const LinkJobAction &job, + InvocationInfo constructInvocation(const DynamicLinkJobAction &job, + const JobContext &context) const override; + InvocationInfo constructInvocation(const StaticLinkJobAction &job, const JobContext &context) const override; public: @@ -79,7 +83,9 @@ class LLVM_LIBRARY_VISIBILITY GenericUnix : public ToolChain { /// default is to return true (and so specify an -rpath). virtual bool shouldProvideRPathToLinker() const; - InvocationInfo constructInvocation(const LinkJobAction &job, + InvocationInfo constructInvocation(const DynamicLinkJobAction &job, + const JobContext &context) const override; + InvocationInfo constructInvocation(const StaticLinkJobAction &job, const JobContext &context) const override; public: diff --git a/lib/Driver/UnixToolChains.cpp b/lib/Driver/UnixToolChains.cpp index fb3c8aa910c9e..e1afb709a5afb 100644 --- a/lib/Driver/UnixToolChains.cpp +++ b/lib/Driver/UnixToolChains.cpp @@ -114,7 +114,7 @@ bool toolchains::GenericUnix::shouldProvideRPathToLinker() const { } ToolChain::InvocationInfo -toolchains::GenericUnix::constructInvocation(const LinkJobAction &job, +toolchains::GenericUnix::constructInvocation(const DynamicLinkJobAction &job, const JobContext &context) const { assert(context.Output.getPrimaryOutputType() == file_types::TY_Image && "Invalid linker output type."); @@ -130,6 +130,8 @@ toolchains::GenericUnix::constructInvocation(const LinkJobAction &job, case LinkKind::DynamicLibrary: Arguments.push_back("-shared"); break; + case LinkKind::StaticLibrary: + llvm_unreachable("the dynamic linker cannot build static libraries"); } // Select the linker to use. @@ -320,6 +322,31 @@ toolchains::GenericUnix::constructInvocation(const LinkJobAction &job, return II; } + +ToolChain::InvocationInfo +toolchains::GenericUnix::constructInvocation(const StaticLinkJobAction &job, + const JobContext &context) const { + assert(context.Output.getPrimaryOutputType() == file_types::TY_Image && + "Invalid linker output type."); + + ArgStringList Arguments; + + // Configure the toolchain. + const char *AR = "ar"; + Arguments.push_back("crs"); + + Arguments.push_back( + context.Args.MakeArgString(context.Output.getPrimaryOutputFilename())); + + addPrimaryInputsOfType(Arguments, context.Inputs, context.Args, + file_types::TY_Object); + addInputsOfType(Arguments, context.InputActions, file_types::TY_Object); + + InvocationInfo II{AR, Arguments}; + + return II; +} + std::string toolchains::Android::getTargetForLinker() const { const llvm::Triple &T = getTriple(); if (T.getArch() == llvm::Triple::arm && diff --git a/lib/Driver/WindowsToolChains.cpp b/lib/Driver/WindowsToolChains.cpp index 8a94f7e26540b..cb04e286a273b 100644 --- a/lib/Driver/WindowsToolChains.cpp +++ b/lib/Driver/WindowsToolChains.cpp @@ -45,7 +45,7 @@ std::string toolchains::Windows::sanitizerRuntimeLibName(StringRef Sanitizer, } ToolChain::InvocationInfo -toolchains::Windows::constructInvocation(const LinkJobAction &job, +toolchains::Windows::constructInvocation(const DynamicLinkJobAction &job, const JobContext &context) const { assert(context.Output.getPrimaryOutputType() == file_types::TY_Image && "Invalid linker output type."); @@ -61,6 +61,8 @@ toolchains::Windows::constructInvocation(const LinkJobAction &job, case LinkKind::DynamicLibrary: Arguments.push_back("-shared"); break; + case LinkKind::StaticLibrary: + llvm_unreachable("invalid link kind"); } // Select the linker to use. @@ -193,3 +195,29 @@ toolchains::Windows::constructInvocation(const LinkJobAction &job, return II; } + +ToolChain::InvocationInfo +toolchains::Windows::constructInvocation(const StaticLinkJobAction &job, + const JobContext &context) const { + assert(context.Output.getPrimaryOutputType() == file_types::TY_Image && + "Invalid linker output type."); + + ArgStringList Arguments; + + // Configure the toolchain. + const char *Link = "link"; + Arguments.push_back("-lib"); + + addPrimaryInputsOfType(Arguments, context.Inputs, context.Args, + file_types::TY_Object); + addInputsOfType(Arguments, context.InputActions, file_types::TY_Object); + + Arguments.push_back( + context.Args.MakeArgString(Twine("/OUT:") + + context.Output.getPrimaryOutputFilename())); + + InvocationInfo II{Link, Arguments}; + II.allowsResponseFiles = true; + + return II; +} diff --git a/test/Driver/static-archive.swift b/test/Driver/static-archive.swift new file mode 100644 index 0000000000000..15acfdb858893 --- /dev/null +++ b/test/Driver/static-archive.swift @@ -0,0 +1,41 @@ +// RUN: %swiftc_driver -driver-print-jobs -target x86_64-apple-macosx10.9 -emit-library %s -module-name ARCHIVER -static 2>&1 > %t.macos.txt + +// CHECK: swift +// CHECK: -o [[OBJECTFILE:.*]] + +// CHECK-NEXT: {{(bin/)?}}libtool{{"? }} -static +// CHECK-DAG: [[OBJECTFILE]] +// CHECK: -o {{[^ ]+}} + +// RUN: %swiftc_driver -driver-print-jobs -target x86_64-unknown-linux-gnu -emit-library %s -module-name ARCHIVER -static 2>&1 > %t.linux.txt + +// CHECK: swift +// CHECK: -o [[OBJECTFILE:.*]] + +// CHECK-NEXT: {{(bin/)?}}{{(llvm-)?}}ar{{"? }} crs +// CHECK-NEXT: {{[^ ]+}} + +// RUN: %swiftc_driver -driver-print-jobs -target x86_64-unknown-windows-msvc -emit-library %s -module-name ARCHIVER -static 2>&1 > %t.windows.txt + +// CHECK: swift +// CHECK: -o [[OBJECTFILE:.*]] + +// CHECK-NEXT: lib -link +// CHECK-DAG: [[OBJECTFILE]] +// CHECK: /OUT:{{[^ ]+}} + +// RUN: %swiftc_driver -driver-print-jobs -target x86_64-apple-macosx10.9 -emit-library %s -module-name ARCHIVER -static | %FileCheck -check-prefix INFERRED_NAME_DARWIN %s +// RUN: %swiftc_driver -driver-print-jobs -target x86_64-unknown-linux-gnu -emit-library %s -module-name ARCHIVER -static | %FileCheck -check-prefix INFERRED_NAME_LINUX %s +// RUN: %swiftc_driver -driver-print-jobs -target x86_64-unknown-windows-msvc -emit-library %s -module-name ARCHIVER -static | %FileCheck -check-prefix INFERRED_NAME_WINDOWS %s + +// INFERRED_NAME_DARWIN: bin{{/|\\\\}}swift{{c?(\.EXE)?}} +// INFERRED_NAME_DARWIN: -module-name ARCHIVER +// INFERRED_NAME_DARWIN: libtool -static +// INFERRED_NAME_DARWIN: -o libARCHIVER.a +// INFERRED_NAME_LINUX: libARCHIVER.a +// INFERRED_NAME_WINDOWS: -lib +// INFERRED_NAME_WINDOWS: libARCHIVER.lib + +// RUN: not %swiftc_driver -driver-print-jobs -module-name ARCHIVER %s -emit-executable -static 2>&1 | %FileCheck -check-prefix ERROR %s + +// ERROR: error: -static may not be used with -emit-executable