diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 312fa822bf5cc..a352e20f1f9a0 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -3720,6 +3720,12 @@ def meabi : Separate<["-"], "meabi">, Group, Flags<[CC1Option]>, NormalizedValues<["Default", "EABI4", "EABI5", "GNU"]>; def mtargetos_EQ : Joined<["-"], "mtargetos=">, Group, HelpText<"Set the deployment target to be the specified OS and OS version">; +def mzos_hlq_le_EQ : Joined<["-"], "mzos-hlq-le=">, MetaVarName<"">, + HelpText<"High level qualifier for z/OS Language Environment datasets">; +def mzos_hlq_clang_EQ : Joined<["-"], "mzos-hlq-clang=">, MetaVarName<"">, + HelpText<"High level qualifier for z/OS C++RT side deck datasets">; +def mzos_hlq_csslib_EQ : Joined<["-"], "mzos-hlq-csslib=">, MetaVarName<"">, + HelpText<"High level qualifier for z/OS CSSLIB dataset">; def mno_constant_cfstrings : Flag<["-"], "mno-constant-cfstrings">, Group; def mno_global_merge : Flag<["-"], "mno-global-merge">, Group, Flags<[CC1Option]>, diff --git a/clang/lib/Driver/ToolChains/ZOS.cpp b/clang/lib/Driver/ToolChains/ZOS.cpp index f921227076a5e..c5100a3864858 100644 --- a/clang/lib/Driver/ToolChains/ZOS.cpp +++ b/clang/lib/Driver/ToolChains/ZOS.cpp @@ -11,8 +11,10 @@ #include "clang/Driver/Compilation.h" #include "clang/Driver/Options.h" #include "llvm/Option/ArgList.h" +#include "llvm/Support/VirtualFileSystem.h" using namespace clang::driver; +using namespace clang::driver::tools; using namespace clang::driver::toolchains; using namespace llvm::opt; using namespace clang; @@ -31,3 +33,211 @@ void ZOS::addClangTargetOptions(const ArgList &DriverArgs, options::OPT_fno_aligned_allocation)) CC1Args.push_back("-faligned-alloc-unavailable"); } + +void zos::Assembler::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + ArgStringList CmdArgs; + + Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); + + // Specify assembler output file. + assert((Output.isFilename() || Output.isNothing()) && "Invalid output."); + if (Output.isFilename()) { + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + } + + // Specify assembler input file. + // The system assembler on z/OS takes exactly one input file. The driver is + // expected to invoke as(1) separately for each assembler source input file. + if (Inputs.size() != 1) + llvm_unreachable("Invalid number of input files."); + const InputInfo &II = Inputs[0]; + assert((II.isFilename() || II.isNothing()) && "Invalid input."); + if (II.isFilename()) + CmdArgs.push_back(II.getFilename()); + + const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); + C.addCommand(std::make_unique(JA, *this, ResponseFileSupport::None(), + Exec, CmdArgs, Inputs)); +} + +static std::string getLEHLQ(const ArgList &Args) { + if (Args.hasArg(options::OPT_mzos_hlq_le_EQ)) { + Arg *LEHLQArg = Args.getLastArg(options::OPT_mzos_hlq_le_EQ); + StringRef HLQ = LEHLQArg->getValue(); + if (!HLQ.empty()) + return HLQ.str(); + } + return "CEE"; +} + +static std::string getClangHLQ(const ArgList &Args) { + if (Args.hasArg(options::OPT_mzos_hlq_clang_EQ)) { + Arg *ClangHLQArg = Args.getLastArg(options::OPT_mzos_hlq_clang_EQ); + StringRef HLQ = ClangHLQArg->getValue(); + if (!HLQ.empty()) + return HLQ.str(); + } + return getLEHLQ(Args); +} + +static std::string getCSSHLQ(const ArgList &Args) { + if (Args.hasArg(options::OPT_mzos_hlq_csslib_EQ)) { + Arg *CsslibHLQArg = Args.getLastArg(options::OPT_mzos_hlq_csslib_EQ); + StringRef HLQ = CsslibHLQArg->getValue(); + if (!HLQ.empty()) + return HLQ.str(); + } + return "SYS1"; +} + +void zos::Linker::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, const ArgList &Args, + const char *LinkingOutput) const { + const ZOS &ToolChain = static_cast(getToolChain()); + ArgStringList CmdArgs; + + const bool IsSharedLib = + Args.hasFlag(options::OPT_shared, options::OPT_static, false); + + assert((Output.isFilename() || Output.isNothing()) && "Invalid output."); + if (Output.isFilename()) { + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + } + + SmallString<128> LinkerOptions; + LinkerOptions = "AMODE="; + LinkerOptions += "64"; + LinkerOptions += ",LIST"; + LinkerOptions += ",DYNAM=DLL"; + LinkerOptions += ",MSGLEVEL=4"; + LinkerOptions += ",CASE=MIXED"; + LinkerOptions += ",REUS=RENT"; + + CmdArgs.push_back("-b"); + CmdArgs.push_back(Args.MakeArgString(LinkerOptions)); + + if (!IsSharedLib) { + CmdArgs.push_back("-e"); + CmdArgs.push_back("CELQSTRT"); + + CmdArgs.push_back("-O"); + CmdArgs.push_back("CELQSTRT"); + + CmdArgs.push_back("-u"); + CmdArgs.push_back("CELQMAIN"); + } + + // Generate side file if -shared option is present. + if (IsSharedLib) { + StringRef OutputName = Output.getFilename(); + // Strip away the last file suffix in presence from output name and add + // a new .x suffix. + size_t Suffix = OutputName.find_last_of("."); + const char *SideDeckName = + Args.MakeArgString(OutputName.substr(0, Suffix) + ".x"); + CmdArgs.push_back("-x"); + CmdArgs.push_back(SideDeckName); + } else { + // We need to direct side file to /dev/null to suppress linker warning when + // the object file contains exported symbols, and -shared or + // -Wl,-x.x is not specified. + CmdArgs.push_back("-x"); + CmdArgs.push_back("/dev/null"); + } + + Args.AddAllArgs(CmdArgs, options::OPT_u); + + // Add archive library search paths. + Args.AddAllArgs(CmdArgs, options::OPT_L); + ToolChain.AddFilePathLibArgs(Args, CmdArgs); + + // Specify linker input file(s) + AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); + + // z/OS tool chain depends on LE data sets and the CSSLIB data set. + // These data sets can have different high level qualifiers (HLQs) + // as each installation can define them differently. + + std::string LEHLQ = getLEHLQ(Args); + std::string CsslibHLQ = getCSSHLQ(Args); + + StringRef ld_env_var = StringRef(getenv("_LD_SYSLIB")).trim(); + if (ld_env_var.empty()) { + CmdArgs.push_back("-S"); + CmdArgs.push_back(Args.MakeArgString("//'" + LEHLQ + ".SCEEBND2'")); + CmdArgs.push_back("-S"); + CmdArgs.push_back(Args.MakeArgString("//'" + CsslibHLQ + ".CSSLIB'")); + } + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { + ld_env_var = StringRef(getenv("_LD_SIDE_DECKS")).trim(); + if (ld_env_var.empty()) { + CmdArgs.push_back( + Args.MakeArgString("//'" + LEHLQ + ".SCEELIB(CELQS001)'")); + CmdArgs.push_back( + Args.MakeArgString("//'" + LEHLQ + ".SCEELIB(CELQS003)'")); + } else { + char *ld_side_deck = strdup(ld_env_var.str().c_str()); + ld_side_deck = strtok(ld_side_deck, ":"); + while (ld_side_deck != nullptr) { + CmdArgs.push_back(ld_side_deck); + ld_side_deck = strtok(nullptr, ":"); + } + } + } + // Link libc++ library + if (ToolChain.ShouldLinkCXXStdlib(Args)) { + ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); + } + + // Specify compiler-rt library path for linker + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) + AddRunTimeLibs(ToolChain, ToolChain.getDriver(), CmdArgs, Args); + + const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); + C.addCommand(std::make_unique(JA, *this, ResponseFileSupport::None(), + Exec, CmdArgs, Inputs)); +} + +ToolChain::RuntimeLibType ZOS::GetDefaultRuntimeLibType() const { + return ToolChain::RLT_CompilerRT; +} + +ToolChain::CXXStdlibType ZOS::GetDefaultCXXStdlibType() const { + return ToolChain::CST_Libcxx; +} + +void ZOS::AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const { + switch (GetCXXStdlibType(Args)) { + case ToolChain::CST_Libstdcxx: + llvm::report_fatal_error("linking libstdc++ is unimplemented on z/OS"); + break; + case ToolChain::CST_Libcxx: { + std::string ClangHLQ = getClangHLQ(Args); + CmdArgs.push_back( + Args.MakeArgString("//'" + ClangHLQ + ".SCEELIB(CRTDQCXE)'")); + CmdArgs.push_back( + Args.MakeArgString("//'" + ClangHLQ + ".SCEELIB(CRTDQCXS)'")); + CmdArgs.push_back( + Args.MakeArgString("//'" + ClangHLQ + ".SCEELIB(CRTDQCXP)'")); + CmdArgs.push_back( + Args.MakeArgString("//'" + ClangHLQ + ".SCEELIB(CRTDQCXA)'")); + CmdArgs.push_back( + Args.MakeArgString("//'" + ClangHLQ + ".SCEELIB(CRTDQXLA)'")); + CmdArgs.push_back( + Args.MakeArgString("//'" + ClangHLQ + ".SCEELIB(CRTDQUNW)'")); + } break; + } +} + +auto ZOS::buildAssembler() const -> Tool * { return new zos::Assembler(*this); } + +auto ZOS::buildLinker() const -> Tool * { return new zos::Linker(*this); } diff --git a/clang/lib/Driver/ToolChains/ZOS.h b/clang/lib/Driver/ToolChains/ZOS.h index 53138306fd410..117a3abee5037 100644 --- a/clang/lib/Driver/ToolChains/ZOS.h +++ b/clang/lib/Driver/ToolChains/ZOS.h @@ -14,6 +14,39 @@ namespace clang { namespace driver { +namespace tools { + +/// zos -- Directly call system default assembler and linker. +namespace zos { + +class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { +public: + Assembler(const ToolChain &TC) : Tool("zos::Assembler", "assembler", TC) {} + + bool hasIntegratedCPP() const override { return false; } + + 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 Linker : public Tool { +public: + Linker(const ToolChain &TC) : Tool("zos::Linker", "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; +}; + +} // end namespace zos +} // end namespace tools + namespace toolchains { class LLVM_LIBRARY_VISIBILITY ZOS : public ToolChain { @@ -32,9 +65,22 @@ class LLVM_LIBRARY_VISIBILITY ZOS : public ToolChain { unsigned GetDefaultDwarfVersion() const override { return 4; } + void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const override; + + CXXStdlibType GetDefaultCXXStdlibType() const override; + + RuntimeLibType GetDefaultRuntimeLibType() const override; + void addClangTargetOptions( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, Action::OffloadKind DeviceOffloadingKind) const override; + + const char *getDefaultLinker() const override { return "/bin/ld"; } + +protected: + Tool *buildAssembler() const override; + Tool *buildLinker() const override; }; } // end namespace toolchains diff --git a/clang/test/Driver/zos-ld.c b/clang/test/Driver/zos-ld.c new file mode 100644 index 0000000000000..4d4decdd0e65b --- /dev/null +++ b/clang/test/Driver/zos-ld.c @@ -0,0 +1,123 @@ +// General tests that ld invocations for z/OS are valid. + +// 1. General C link for executable +// RUN: %clang -### --target=s390x-ibm-zos %s 2>&1 \ +// RUN: | FileCheck --check-prefix=C-LD %s + +// C-LD: "-resource-dir" "[[RESOURCE_DIR:[^"]+]]" +// C-LD: "AMODE=64,LIST,DYNAM=DLL,MSGLEVEL=4,CASE=MIXED,REUS=RENT" +// C-LD-SAME: "-e" "CELQSTRT" +// C-LD-SAME: "-O" "CELQSTRT" +// C-LD-SAME: "-u" "CELQMAIN" +// C-LD-SAME: "-x" "/dev/null" +// C-LD-SAME: "-S" "//'CEE.SCEEBND2'" +// C-LD-SAME: "-S" "//'SYS1.CSSLIB'" +// C-LD-SAME: "//'CEE.SCEELIB(CELQS001)'" +// C-LD-SAME: "//'CEE.SCEELIB(CELQS003)'" +// C-LD-SAME: "[[RESOURCE_DIR]]{{/|\\\\}}lib{{/|\\\\}}zos{{/|\\\\}}libclang_rt.builtins-s390x.a" + +// 2. General C link for dll +// RUN: %clang -### --shared --target=s390x-ibm-zos %s 2>&1 \ +// RUN: | FileCheck --check-prefix=C-LD-DLL %s + +// C-LD-DLL: "-resource-dir" "[[RESOURCE_DIR:[^"]+]]" +// C-LD-DLL: "AMODE=64,LIST,DYNAM=DLL,MSGLEVEL=4,CASE=MIXED,REUS=RENT" +// C-LD-DLL-NOT: "-e" "CELQSTRT" +// C-LD-DLL-NOT: "-O" "CELQSTRT" +// C-LD-DLL-NOT: "-u" "CELQMAIN" +// C-LD-DLL-SAME: "-x" "{{.*}}.x" +// C-LD-DLL-SAME: "-S" "//'CEE.SCEEBND2'" +// C-LD-DLL-SAME: "-S" "//'SYS1.CSSLIB'" +// C-LD-DLL-SAME: "//'CEE.SCEELIB(CELQS001)'" +// C-LD-DLL-SAME: "//'CEE.SCEELIB(CELQS003)'" +// C-LD-DLL-SAME: "[[RESOURCE_DIR]]{{/|\\\\}}lib{{/|\\\\}}zos{{/|\\\\}}libclang_rt.builtins-s390x.a" + +// 3. General C++ link for executable +// RUN: %clangxx -### --target=s390x-ibm-zos %s 2>&1 \ +// RUN: | FileCheck --check-prefix=CXX-LD %s + +// CXX-LD: "-resource-dir" "[[RESOURCE_DIR:[^"]+]]" +// CXX-LD: "AMODE=64,LIST,DYNAM=DLL,MSGLEVEL=4,CASE=MIXED,REUS=RENT" +// CXX-LD-SAME: "-e" "CELQSTRT" +// CXX-LD-SAME: "-O" "CELQSTRT" +// CXX-LD-SAME: "-u" "CELQMAIN" +// CXX-LD-SAME: "-x" "/dev/null" +// CXX-LD-SAME: "-S" "//'CEE.SCEEBND2'" +// CXX-LD-SAME: "-S" "//'SYS1.CSSLIB'" +// CXX-LD-SAME: "//'CEE.SCEELIB(CELQS001)'" +// CXX-LD-SAME: "//'CEE.SCEELIB(CELQS003)'" +// CXX-LD-SAME: "//'CEE.SCEELIB(CRTDQCXE)'" +// CXX-LD-SAME: "//'CEE.SCEELIB(CRTDQCXS)'" +// CXX-LD-SAME: "//'CEE.SCEELIB(CRTDQCXP)'" +// CXX-LD-SAME: "//'CEE.SCEELIB(CRTDQCXA)'" +// CXX-LD-SAME: "//'CEE.SCEELIB(CRTDQXLA)'" +// CXX-LD-SAME: "//'CEE.SCEELIB(CRTDQUNW)'" +// CXX-LD-SAME: "[[RESOURCE_DIR]]{{/|\\\\}}lib{{/|\\\\}}zos{{/|\\\\}}libclang_rt.builtins-s390x.a" + +// 4. General C++ link for dll +// RUN: %clangxx -### --shared --target=s390x-ibm-zos %s 2>&1 \ +// RUN: | FileCheck --check-prefix=CXX-LD-DLL %s + +// CXX-LD-DLL: "-resource-dir" "[[RESOURCE_DIR:[^"]+]]" +// CXX-LD-DLL: "AMODE=64,LIST,DYNAM=DLL,MSGLEVEL=4,CASE=MIXED,REUS=RENT" +// CXX-LD-DLL-NOT: "-e" "CELQSTRT" +// CXX-LD-DLL-NOT: "-O" "CELQSTRT" +// CXX-LD-DLL-NOT: "-u" "CELQMAIN" +// CXX-LD-DLL-SAME: "-x" "{{.*}}.x" +// CXX-LD-DLL-SAME: "-S" "//'CEE.SCEEBND2'" +// CXX-LD-DLL-SAME: "-S" "//'SYS1.CSSLIB'" +// CXX-LD-DLL-SAME: "//'CEE.SCEELIB(CELQS001)'" +// CXX-LD-DLL-SAME: "//'CEE.SCEELIB(CELQS003)'" +// CXX-LD-DLL-SAME: "//'CEE.SCEELIB(CRTDQCXE)'" +// CXX-LD-DLL-SAME: "//'CEE.SCEELIB(CRTDQCXS)'" +// CXX-LD-DLL-SAME: "//'CEE.SCEELIB(CRTDQCXP)'" +// CXX-LD-DLL-SAME: "//'CEE.SCEELIB(CRTDQCXA)'" +// CXX-LD-DLL-SAME: "//'CEE.SCEELIB(CRTDQXLA)'" +// CXX-LD-DLL-SAME: "//'CEE.SCEELIB(CRTDQUNW)'" +// CXX-LD-DLL-SAME: "[[RESOURCE_DIR]]{{/|\\\\}}lib{{/|\\\\}}zos{{/|\\\\}}libclang_rt.builtins-s390x.a" + +// 5. C++ link for executable w/ -mzos-hlq-le=, -mzos-hlq-csslib= +// RUN: %clangxx -### --target=s390x-ibm-zos %s 2>&1 \ +// RUN: -mzos-hlq-le=AAAA -mzos-hlq-csslib=BBBB \ +// RUN: | FileCheck --check-prefix=CXX-LD5 %s + +// CXX-LD5: "-resource-dir" "[[RESOURCE_DIR:[^"]+]]" +// CXX-LD5: "AMODE=64,LIST,DYNAM=DLL,MSGLEVEL=4,CASE=MIXED,REUS=RENT" +// CXX-LD5-SAME: "-e" "CELQSTRT" +// CXX-LD5-SAME: "-O" "CELQSTRT" +// CXX-LD5-SAME: "-u" "CELQMAIN" +// CXX-LD5-SAME: "-x" "/dev/null" +// CXX-LD5-SAME: "-S" "//'AAAA.SCEEBND2'" +// CXX-LD5-SAME: "-S" "//'BBBB.CSSLIB'" +// CXX-LD5-SAME: "//'AAAA.SCEELIB(CELQS001)'" +// CXX-LD5-SAME: "//'AAAA.SCEELIB(CELQS003)'" +// CXX-LD5-SAME: "//'AAAA.SCEELIB(CRTDQCXE)'" +// CXX-LD5-SAME: "//'AAAA.SCEELIB(CRTDQCXS)'" +// CXX-LD5-SAME: "//'AAAA.SCEELIB(CRTDQCXP)'" +// CXX-LD5-SAME: "//'AAAA.SCEELIB(CRTDQCXA)'" +// CXX-LD5-SAME: "//'AAAA.SCEELIB(CRTDQXLA)'" +// CXX-LD5-SAME: "//'AAAA.SCEELIB(CRTDQUNW)'" +// CXX-LD5-SAME: "[[RESOURCE_DIR]]{{/|\\\\}}lib{{/|\\\\}}zos{{/|\\\\}}libclang_rt.builtins-s390x.a" + +// 6. C++ link for executable w/ -mzos-hlq-clang= +// RUN: %clangxx -### --target=s390x-ibm-zos %s 2>&1 \ +// RUN: -mzos-hlq-clang=AAAA \ +// RUN: | FileCheck --check-prefix=CXX-LD6 %s + +// CXX-LD6: "-resource-dir" "[[RESOURCE_DIR:[^"]+]]" +// CXX-LD6: "AMODE=64,LIST,DYNAM=DLL,MSGLEVEL=4,CASE=MIXED,REUS=RENT" +// CXX-LD6-SAME: "-e" "CELQSTRT" +// CXX-LD6-SAME: "-O" "CELQSTRT" +// CXX-LD6-SAME: "-u" "CELQMAIN" +// CXX-LD6-SAME: "-x" "/dev/null" +// CXX-LD6-SAME: "-S" "//'CEE.SCEEBND2'" +// CXX-LD6-SAME: "-S" "//'SYS1.CSSLIB'" +// CXX-LD6-SAME: "//'CEE.SCEELIB(CELQS001)'" +// CXX-LD6-SAME: "//'CEE.SCEELIB(CELQS003)'" +// CXX-LD6-SAME: "//'AAAA.SCEELIB(CRTDQCXE)'" +// CXX-LD6-SAME: "//'AAAA.SCEELIB(CRTDQCXS)'" +// CXX-LD6-SAME: "//'AAAA.SCEELIB(CRTDQCXP)'" +// CXX-LD6-SAME: "//'AAAA.SCEELIB(CRTDQCXA)'" +// CXX-LD6-SAME: "//'AAAA.SCEELIB(CRTDQXLA)'" +// CXX-LD6-SAME: "//'AAAA.SCEELIB(CRTDQUNW)'" +// CXX-LD6-SAME: "[[RESOURCE_DIR]]{{/|\\\\}}lib{{/|\\\\}}zos{{/|\\\\}}libclang_rt.builtins-s390x.a"