diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp --- a/clang/lib/Driver/ToolChain.cpp +++ b/clang/lib/Driver/ToolChain.cpp @@ -618,6 +618,8 @@ std::string ToolChain::GetStaticLibToolPath() const { // TODO: Add support for static lib archiving on Windows + if (Triple.isOSDarwin()) + return GetProgramPath("libtool"); return GetProgramPath("llvm-ar"); } diff --git a/clang/lib/Driver/ToolChains/Darwin.h b/clang/lib/Driver/ToolChains/Darwin.h --- a/clang/lib/Driver/ToolChains/Darwin.h +++ b/clang/lib/Driver/ToolChains/Darwin.h @@ -78,6 +78,20 @@ const char *LinkingOutput) const override; }; +class LLVM_LIBRARY_VISIBILITY StaticLibTool : public MachOTool { +public: + StaticLibTool(const ToolChain &TC) + : MachOTool("darwin::StaticLibTool", "static-lib-linker", TC) {} + + bool hasIntegratedCPP() const override { return false; } + bool isLinkJob() const override { return true; } + + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; + class LLVM_LIBRARY_VISIBILITY Lipo : public MachOTool { public: Lipo(const ToolChain &TC) : MachOTool("darwin::Lipo", "lipo", TC) {} @@ -125,6 +139,7 @@ protected: Tool *buildAssembler() const override; Tool *buildLinker() const override; + Tool *buildStaticLibTool() const override; Tool *getTool(Action::ActionClass AC) const override; private: diff --git a/clang/lib/Driver/ToolChains/Darwin.cpp b/clang/lib/Driver/ToolChains/Darwin.cpp --- a/clang/lib/Driver/ToolChains/Darwin.cpp +++ b/clang/lib/Driver/ToolChains/Darwin.cpp @@ -196,8 +196,8 @@ return true; if (A->getOption().matches(options::OPT_O)) return llvm::StringSwitch(A->getValue()) - .Case("1", true) - .Default(false); + .Case("1", true) + .Default(false); return false; // OPT_Ofast & OPT_O4 } @@ -296,8 +296,8 @@ if ((A = Args.getLastArg(options::OPT_compatibility__version)) || (A = Args.getLastArg(options::OPT_current__version)) || (A = Args.getLastArg(options::OPT_install__name))) - D.Diag(diag::err_drv_argument_only_allowed_with) << A->getAsString(Args) - << "-dynamiclib"; + D.Diag(diag::err_drv_argument_only_allowed_with) + << A->getAsString(Args) << "-dynamiclib"; Args.AddLastArg(CmdArgs, options::OPT_force__flat__namespace); Args.AddLastArg(CmdArgs, options::OPT_keep__private__externs); @@ -312,8 +312,8 @@ (A = Args.getLastArg(options::OPT_force__flat__namespace)) || (A = Args.getLastArg(options::OPT_keep__private__externs)) || (A = Args.getLastArg(options::OPT_private__bundle))) - D.Diag(diag::err_drv_argument_not_allowed_with) << A->getAsString(Args) - << "-dynamiclib"; + D.Diag(diag::err_drv_argument_not_allowed_with) + << A->getAsString(Args) << "-dynamiclib"; Args.AddAllArgsTranslated(CmdArgs, options::OPT_compatibility__version, "-dylib_compatibility_version"); @@ -729,6 +729,54 @@ C.addCommand(std::move(Cmd)); } +void darwin::StaticLibTool::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + const Driver &D = getToolChain().getDriver(); + + // 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); + // Silence warnings when linking C code with a C++ '-stdlib' argument. + Args.ClaimAllArgs(options::OPT_stdlib_EQ); + + // libtool + ArgStringList CmdArgs; + // Create and insert file members with a deterministic index. + CmdArgs.push_back("-static"); + CmdArgs.push_back("-D"); + CmdArgs.push_back("-no_warning_for_no_symbols"); + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + + for (const auto &II : Inputs) { + if (II.isFilename()) { + CmdArgs.push_back(II.getFilename()); + } + } + + // Delete old output archive file if it already exists before generating a new + // archive file. + const auto *OutputFileName = Output.getFilename(); + if (Output.isFilename() && llvm::sys::fs::exists(OutputFileName)) { + if (std::error_code EC = llvm::sys::fs::remove(OutputFileName)) { + D.Diag(diag::err_drv_unable_to_remove_file) << EC.message(); + return; + } + } + + const char *Exec = Args.MakeArgString(getToolChain().GetStaticLibToolPath()); + C.addCommand(std::make_unique(JA, *this, + ResponseFileSupport::AtFileUTF8(), + Exec, CmdArgs, Inputs, Output)); +} + void darwin::Lipo::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, @@ -982,6 +1030,10 @@ Tool *MachO::buildLinker() const { return new tools::darwin::Linker(*this); } +Tool *MachO::buildStaticLibTool() const { + return new tools::darwin::StaticLibTool(*this); +} + Tool *MachO::buildAssembler() const { return new tools::darwin::Assembler(*this); } @@ -1137,16 +1189,16 @@ StringRef Darwin::getPlatformFamily() const { switch (TargetPlatform) { - case DarwinPlatformKind::MacOS: + case DarwinPlatformKind::MacOS: + return "MacOSX"; + case DarwinPlatformKind::IPhoneOS: + if (TargetEnvironment == MacCatalyst) return "MacOSX"; - case DarwinPlatformKind::IPhoneOS: - if (TargetEnvironment == MacCatalyst) - return "MacOSX"; - return "iPhone"; - case DarwinPlatformKind::TvOS: - return "AppleTV"; - case DarwinPlatformKind::WatchOS: - return "Watch"; + return "iPhone"; + case DarwinPlatformKind::TvOS: + return "AppleTV"; + case DarwinPlatformKind::WatchOS: + return "Watch"; } llvm_unreachable("Unsupported platform"); } @@ -1269,9 +1321,9 @@ AddLinkRuntimeLib(Args, CmdArgs, Sanitizer, RLO, Shared); } -ToolChain::RuntimeLibType DarwinClang::GetRuntimeLibType( - const ArgList &Args) const { - if (Arg* A = Args.getLastArg(options::OPT_rtlib_EQ)) { +ToolChain::RuntimeLibType +DarwinClang::GetRuntimeLibType(const ArgList &Args) const { + if (Arg *A = Args.getLastArg(options::OPT_rtlib_EQ)) { StringRef Value = A->getValue(); if (Value != "compiler-rt") getDriver().Diag(clang::diag::err_drv_unsupported_rtlib_for_platform) @@ -1610,8 +1662,9 @@ if (iOSVersion || TvOSVersion || WatchOSVersion) { TheDriver.Diag(diag::err_drv_argument_not_allowed_with) << OSXVersion->getAsString(Args) - << (iOSVersion ? iOSVersion - : TvOSVersion ? TvOSVersion : WatchOSVersion) + << (iOSVersion ? iOSVersion + : TvOSVersion ? TvOSVersion + : WatchOSVersion) ->getAsString(Args); } return DarwinPlatform::createOSVersionArg(Darwin::MacOS, OSXVersion); @@ -2081,16 +2134,18 @@ // Returns the effective header sysroot path to use. This comes either from // -isysroot or --sysroot. -llvm::StringRef DarwinClang::GetHeaderSysroot(const llvm::opt::ArgList &DriverArgs) const { - if(DriverArgs.hasArg(options::OPT_isysroot)) +llvm::StringRef +DarwinClang::GetHeaderSysroot(const llvm::opt::ArgList &DriverArgs) const { + if (DriverArgs.hasArg(options::OPT_isysroot)) return DriverArgs.getLastArgValue(options::OPT_isysroot); if (!getDriver().SysRoot.empty()) return getDriver().SysRoot; return "/"; } -void DarwinClang::AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const { +void DarwinClang::AddClangSystemIncludeArgs( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { const Driver &D = getDriver(); llvm::StringRef Sysroot = GetHeaderSysroot(DriverArgs); @@ -2104,9 +2159,9 @@ // Add /usr/local/include if (!NoStdInc && !NoStdlibInc) { - SmallString<128> P(Sysroot); - llvm::sys::path::append(P, "usr", "local", "include"); - addSystemInclude(DriverArgs, CC1Args, P); + SmallString<128> P(Sysroot); + llvm::sys::path::append(P, "usr", "local", "include"); + addSystemInclude(DriverArgs, CC1Args, P); } // Add the Clang builtin headers (/include) @@ -2137,12 +2192,10 @@ } } -bool DarwinClang::AddGnuCPlusPlusIncludePaths(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args, - llvm::SmallString<128> Base, - llvm::StringRef Version, - llvm::StringRef ArchDir, - llvm::StringRef BitDir) const { +bool DarwinClang::AddGnuCPlusPlusIncludePaths( + const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, + llvm::SmallString<128> Base, llvm::StringRef Version, + llvm::StringRef ArchDir, llvm::StringRef BitDir) const { llvm::sys::path::append(Base, Version); // Add the base dir @@ -2232,47 +2285,43 @@ llvm::Triple::ArchType arch = getTriple().getArch(); bool IsBaseFound = true; switch (arch) { - default: break; + default: + break; case llvm::Triple::ppc: case llvm::Triple::ppc64: - IsBaseFound = AddGnuCPlusPlusIncludePaths(DriverArgs, CC1Args, UsrIncludeCxx, - "4.2.1", - "powerpc-apple-darwin10", - arch == llvm::Triple::ppc64 ? "ppc64" : ""); - IsBaseFound |= AddGnuCPlusPlusIncludePaths(DriverArgs, CC1Args, UsrIncludeCxx, - "4.0.0", "powerpc-apple-darwin10", - arch == llvm::Triple::ppc64 ? "ppc64" : ""); + IsBaseFound = AddGnuCPlusPlusIncludePaths( + DriverArgs, CC1Args, UsrIncludeCxx, "4.2.1", "powerpc-apple-darwin10", + arch == llvm::Triple::ppc64 ? "ppc64" : ""); + IsBaseFound |= AddGnuCPlusPlusIncludePaths( + DriverArgs, CC1Args, UsrIncludeCxx, "4.0.0", "powerpc-apple-darwin10", + arch == llvm::Triple::ppc64 ? "ppc64" : ""); break; case llvm::Triple::x86: case llvm::Triple::x86_64: - IsBaseFound = AddGnuCPlusPlusIncludePaths(DriverArgs, CC1Args, UsrIncludeCxx, - "4.2.1", - "i686-apple-darwin10", - arch == llvm::Triple::x86_64 ? "x86_64" : ""); - IsBaseFound |= AddGnuCPlusPlusIncludePaths(DriverArgs, CC1Args, UsrIncludeCxx, - "4.0.0", "i686-apple-darwin8", - ""); + IsBaseFound = AddGnuCPlusPlusIncludePaths( + DriverArgs, CC1Args, UsrIncludeCxx, "4.2.1", "i686-apple-darwin10", + arch == llvm::Triple::x86_64 ? "x86_64" : ""); + IsBaseFound |= + AddGnuCPlusPlusIncludePaths(DriverArgs, CC1Args, UsrIncludeCxx, + "4.0.0", "i686-apple-darwin8", ""); break; case llvm::Triple::arm: case llvm::Triple::thumb: - IsBaseFound = AddGnuCPlusPlusIncludePaths(DriverArgs, CC1Args, UsrIncludeCxx, - "4.2.1", - "arm-apple-darwin10", - "v7"); - IsBaseFound |= AddGnuCPlusPlusIncludePaths(DriverArgs, CC1Args, UsrIncludeCxx, - "4.2.1", - "arm-apple-darwin10", - "v6"); + IsBaseFound = + AddGnuCPlusPlusIncludePaths(DriverArgs, CC1Args, UsrIncludeCxx, + "4.2.1", "arm-apple-darwin10", "v7"); + IsBaseFound |= + AddGnuCPlusPlusIncludePaths(DriverArgs, CC1Args, UsrIncludeCxx, + "4.2.1", "arm-apple-darwin10", "v6"); break; case llvm::Triple::aarch64: - IsBaseFound = AddGnuCPlusPlusIncludePaths(DriverArgs, CC1Args, UsrIncludeCxx, - "4.2.1", - "arm64-apple-darwin10", - ""); + IsBaseFound = + AddGnuCPlusPlusIncludePaths(DriverArgs, CC1Args, UsrIncludeCxx, + "4.2.1", "arm64-apple-darwin10", ""); break; } @@ -2535,8 +2584,7 @@ return DAL; } -void MachO::AddLinkRuntimeLibArgs(const ArgList &Args, - ArgStringList &CmdArgs, +void MachO::AddLinkRuntimeLibArgs(const ArgList &Args, ArgStringList &CmdArgs, bool ForceLinkBuiltinRT) const { // Embedded targets are simple at the moment, not supporting sanitizers and // with different libraries for each member of the product { static, PIC } x @@ -2574,9 +2622,9 @@ return TargetVersion < alignedAllocMinVersion(OS); } -void Darwin::addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args, - Action::OffloadKind DeviceOffloadKind) const { +void Darwin::addClangTargetOptions( + const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadKind) const { // Pass "-faligned-alloc-unavailable" only when the user hasn't manually // enabled or disabled aligned allocations. if (!DriverArgs.hasArgNoClaim(options::OPT_faligned_allocation, @@ -2642,7 +2690,7 @@ // it is set here. if (isTargetWatchOSBased() || (isTargetIOSBased() && !isIPhoneOSVersionLT(6, 0))) { - for (ArgList::iterator it = DAL->begin(), ie = DAL->end(); it != ie; ) { + for (ArgList::iterator it = DAL->begin(), ie = DAL->end(); it != ie;) { Arg *A = *it; ++it; if (A->getOption().getID() != options::OPT_mkernel && diff --git a/clang/test/Driver/bindings.c b/clang/test/Driver/bindings.c --- a/clang/test/Driver/bindings.c +++ b/clang/test/Driver/bindings.c @@ -27,3 +27,7 @@ // GNU StaticLibTool binding // RUN: %clang -target x86_64-linux-gnu -ccc-print-bindings --emit-static-lib %s 2>&1 | FileCheck %s --check-prefix=CHECK15 // CHECK15: "x86_64-unknown-linux-gnu" - "GNU::StaticLibTool", inputs: ["{{.*}}.o"], output: "a.out" + +// Darwin StaticLibTool binding +// RUN: %clang -target i386-apple-darwin9 -ccc-print-bindings --emit-static-lib %s 2>&1 | FileCheck %s --check-prefix=CHECK16 +// CHECK16: "i386-apple-darwin9" - "darwin::StaticLibTool", inputs: ["{{.*}}.o"], output: "a.out" diff --git a/clang/test/Driver/darwin-static-lib.c b/clang/test/Driver/darwin-static-lib.c new file mode 100644 --- /dev/null +++ b/clang/test/Driver/darwin-static-lib.c @@ -0,0 +1,5 @@ +// RUN: %clang -target i386-apple-darwin9 %s -### --emit-static-lib 2>&1 | FileCheck %s +// CHECK: "{{.*}}libtool" "-static" "-D" "-no_warning_for_no_symbols" "-o" "a.out" "{{.*o}}" + +// RUN: %clang -target i386-apple-darwin9 %s -### --emit-static-lib -o libfoo.a 2>&1 | FileCheck %s --check-prefix=OUTPUT +// OUTPUT: "{{.*}}libtool" "-static" "-D" "-no_warning_for_no_symbols" "-o" "libfoo.a" "{{.*o}}"