347 lines · cpp
1//===--- ZOS.cpp - z/OS ToolChain Implementations ---------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "ZOS.h"10#include "clang/Driver/CommonArgs.h"11#include "clang/Driver/Compilation.h"12#include "clang/Options/Options.h"13#include "llvm/Option/ArgList.h"14#include "llvm/Support/VirtualFileSystem.h"15#include "llvm/Support/WithColor.h"16 17using namespace clang;18using namespace clang::driver;19using namespace clang::driver::tools;20using namespace clang::driver::toolchains;21using namespace llvm;22using namespace llvm::opt;23using namespace llvm::sys;24 25ZOS::ZOS(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)26 : ToolChain(D, Triple, Args) {}27 28ZOS::~ZOS() {}29 30void ZOS::addClangTargetOptions(const ArgList &DriverArgs,31 ArgStringList &CC1Args,32 Action::OffloadKind DeviceOffloadKind) const {33 // Pass "-faligned-alloc-unavailable" only when the user hasn't manually34 // enabled or disabled aligned allocations.35 if (!DriverArgs.hasArgNoClaim(options::OPT_faligned_allocation,36 options::OPT_fno_aligned_allocation))37 CC1Args.push_back("-faligned-alloc-unavailable");38 39 if (DriverArgs.hasFlag(options::OPT_fxl_pragma_pack,40 options::OPT_fno_xl_pragma_pack, true))41 CC1Args.push_back("-fxl-pragma-pack");42 43 // Pass "-fno-sized-deallocation" only when the user hasn't manually enabled44 // or disabled sized deallocations.45 if (!DriverArgs.hasArgNoClaim(options::OPT_fsized_deallocation,46 options::OPT_fno_sized_deallocation))47 CC1Args.push_back("-fno-sized-deallocation");48}49 50void zos::Assembler::ConstructJob(Compilation &C, const JobAction &JA,51 const InputInfo &Output,52 const InputInfoList &Inputs,53 const ArgList &Args,54 const char *LinkingOutput) const {55 ArgStringList CmdArgs;56 57 Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);58 59 // Specify assembler output file.60 assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");61 if (Output.isFilename()) {62 CmdArgs.push_back("-o");63 CmdArgs.push_back(Output.getFilename());64 }65 66 // Specify assembler input file.67 // The system assembler on z/OS takes exactly one input file. The driver is68 // expected to invoke as(1) separately for each assembler source input file.69 if (Inputs.size() != 1)70 llvm_unreachable("Invalid number of input files.");71 const InputInfo &II = Inputs[0];72 assert((II.isFilename() || II.isNothing()) && "Invalid input.");73 if (II.isFilename())74 CmdArgs.push_back(II.getFilename());75 76 const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));77 C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),78 Exec, CmdArgs, Inputs, Output));79}80 81static std::string getLEHLQ(const ArgList &Args) {82 if (Args.hasArg(options::OPT_mzos_hlq_le_EQ)) {83 Arg *LEHLQArg = Args.getLastArg(options::OPT_mzos_hlq_le_EQ);84 StringRef HLQ = LEHLQArg->getValue();85 if (!HLQ.empty())86 return HLQ.str();87 }88 return "CEE";89}90 91static std::string getClangHLQ(const ArgList &Args) {92 if (Args.hasArg(options::OPT_mzos_hlq_clang_EQ)) {93 Arg *ClangHLQArg = Args.getLastArg(options::OPT_mzos_hlq_clang_EQ);94 StringRef HLQ = ClangHLQArg->getValue();95 if (!HLQ.empty())96 return HLQ.str();97 }98 return getLEHLQ(Args);99}100 101static std::string getCSSHLQ(const ArgList &Args) {102 if (Args.hasArg(options::OPT_mzos_hlq_csslib_EQ)) {103 Arg *CsslibHLQArg = Args.getLastArg(options::OPT_mzos_hlq_csslib_EQ);104 StringRef HLQ = CsslibHLQArg->getValue();105 if (!HLQ.empty())106 return HLQ.str();107 }108 return "SYS1";109}110 111void zos::Linker::ConstructJob(Compilation &C, const JobAction &JA,112 const InputInfo &Output,113 const InputInfoList &Inputs, const ArgList &Args,114 const char *LinkingOutput) const {115 const ZOS &ToolChain = static_cast<const ZOS &>(getToolChain());116 ArgStringList CmdArgs;117 118 const bool IsSharedLib =119 Args.hasFlag(options::OPT_shared, options::OPT_static, false);120 121 assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");122 if (Output.isFilename()) {123 CmdArgs.push_back("-o");124 CmdArgs.push_back(Output.getFilename());125 }126 127 SmallString<128> LinkerOptions;128 LinkerOptions = "AMODE=";129 LinkerOptions += "64";130 LinkerOptions += ",LIST";131 LinkerOptions += ",DYNAM=DLL";132 LinkerOptions += ",MSGLEVEL=4";133 LinkerOptions += ",CASE=MIXED";134 LinkerOptions += ",REUS=RENT";135 136 CmdArgs.push_back("-b");137 CmdArgs.push_back(Args.MakeArgString(LinkerOptions));138 139 if (!IsSharedLib) {140 CmdArgs.push_back("-e");141 CmdArgs.push_back("CELQSTRT");142 143 CmdArgs.push_back("-O");144 CmdArgs.push_back("CELQSTRT");145 146 CmdArgs.push_back("-u");147 CmdArgs.push_back("CELQMAIN");148 }149 150 // Generate side file if -shared option is present.151 if (IsSharedLib) {152 StringRef OutputName = Output.getFilename();153 // Strip away the last file suffix in presence from output name and add154 // a new .x suffix.155 SmallString<128> SideDeckName = OutputName;156 llvm::sys::path::replace_extension(SideDeckName, "x");157 CmdArgs.push_back("-x");158 CmdArgs.push_back(Args.MakeArgString(SideDeckName));159 } else {160 // We need to direct side file to /dev/null to suppress linker warning when161 // the object file contains exported symbols, and -shared or162 // -Wl,-x<sidedeck>.x is not specified.163 CmdArgs.push_back("-x");164 CmdArgs.push_back("/dev/null");165 }166 167 // Add archive library search paths.168 Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_u});169 170 ToolChain.AddFilePathLibArgs(Args, CmdArgs);171 172 // Specify linker input file(s)173 AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);174 175 // z/OS tool chain depends on LE data sets and the CSSLIB data set.176 // These data sets can have different high level qualifiers (HLQs)177 // as each installation can define them differently.178 179 std::string LEHLQ = getLEHLQ(Args);180 std::string CsslibHLQ = getCSSHLQ(Args);181 182 StringRef ld_env_var = StringRef(getenv("_LD_SYSLIB")).trim();183 if (ld_env_var.empty()) {184 CmdArgs.push_back("-S");185 CmdArgs.push_back(Args.MakeArgString("//'" + LEHLQ + ".SCEEBND2'"));186 CmdArgs.push_back("-S");187 CmdArgs.push_back(Args.MakeArgString("//'" + CsslibHLQ + ".CSSLIB'"));188 }189 190 if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {191 ld_env_var = StringRef(getenv("_LD_SIDE_DECKS")).trim();192 if (ld_env_var.empty()) {193 CmdArgs.push_back(194 Args.MakeArgString("//'" + LEHLQ + ".SCEELIB(CELQS001)'"));195 CmdArgs.push_back(196 Args.MakeArgString("//'" + LEHLQ + ".SCEELIB(CELQS003)'"));197 } else {198 SmallVector<StringRef> ld_side_deck;199 ld_env_var.split(ld_side_deck, ":");200 for (StringRef ld_loc : ld_side_deck) {201 CmdArgs.push_back((ld_loc.str()).c_str());202 }203 }204 }205 // Link libc++ library206 if (ToolChain.ShouldLinkCXXStdlib(Args)) {207 ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);208 }209 210 // Specify compiler-rt library path for linker211 if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs))212 AddRunTimeLibs(ToolChain, ToolChain.getDriver(), CmdArgs, Args);213 214 const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());215 C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),216 Exec, CmdArgs, Inputs, Output));217}218 219ToolChain::RuntimeLibType ZOS::GetDefaultRuntimeLibType() const {220 return ToolChain::RLT_CompilerRT;221}222 223ToolChain::CXXStdlibType ZOS::GetDefaultCXXStdlibType() const {224 return ToolChain::CST_Libcxx;225}226 227void ZOS::AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,228 llvm::opt::ArgStringList &CmdArgs) const {229 switch (GetCXXStdlibType(Args)) {230 case ToolChain::CST_Libstdcxx:231 llvm::report_fatal_error("linking libstdc++ is unimplemented on z/OS");232 break;233 case ToolChain::CST_Libcxx: {234 std::string ClangHLQ = getClangHLQ(Args);235 CmdArgs.push_back(236 Args.MakeArgString("//'" + ClangHLQ + ".SCEELIB(CRTDQCXE)'"));237 CmdArgs.push_back(238 Args.MakeArgString("//'" + ClangHLQ + ".SCEELIB(CRTDQCXS)'"));239 CmdArgs.push_back(240 Args.MakeArgString("//'" + ClangHLQ + ".SCEELIB(CRTDQCXP)'"));241 CmdArgs.push_back(242 Args.MakeArgString("//'" + ClangHLQ + ".SCEELIB(CRTDQCXA)'"));243 CmdArgs.push_back(244 Args.MakeArgString("//'" + ClangHLQ + ".SCEELIB(CRTDQXLA)'"));245 CmdArgs.push_back(246 Args.MakeArgString("//'" + ClangHLQ + ".SCEELIB(CRTDQUNW)'"));247 } break;248 }249}250 251auto ZOS::buildAssembler() const -> Tool * { return new zos::Assembler(*this); }252 253auto ZOS::buildLinker() const -> Tool * { return new zos::Linker(*this); }254 255void ZOS::AddClangSystemIncludeArgs(const ArgList &DriverArgs,256 ArgStringList &CC1Args) const {257 if (DriverArgs.hasArg(options::OPT_nostdinc))258 return;259 260 const Driver &D = getDriver();261 262 // resolve ResourceDir263 std::string ResourceDir(D.ResourceDir);264 265 // zos_wrappers must take highest precedence266 267 // - <clang>/lib/clang/<ver>/include/zos_wrappers268 if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {269 SmallString<128> P(ResourceDir);270 path::append(P, "include", "zos_wrappers");271 addSystemInclude(DriverArgs, CC1Args, P.str());272 273 // - <clang>/lib/clang/<ver>/include274 SmallString<128> P2(ResourceDir);275 path::append(P2, "include");276 addSystemInclude(DriverArgs, CC1Args, P2.str());277 }278 279 // - /usr/include280 if (Arg *SysIncludeArg =281 DriverArgs.getLastArg(options::OPT_mzos_sys_include_EQ)) {282 StringRef SysInclude = SysIncludeArg->getValue();283 284 // fall back to the default include path285 if (!SysInclude.empty()) {286 287 // -mzos-sys-include opton can have colon separated288 // list of paths, so we need to parse the value.289 StringRef PathLE(SysInclude);290 size_t Colon = PathLE.find(':');291 if (Colon == StringRef::npos) {292 addSystemInclude(DriverArgs, CC1Args, PathLE.str());293 return;294 }295 296 while (Colon != StringRef::npos) {297 SmallString<128> P = PathLE.substr(0, Colon);298 addSystemInclude(DriverArgs, CC1Args, P.str());299 PathLE = PathLE.substr(Colon + 1);300 Colon = PathLE.find(':');301 }302 if (PathLE.size())303 addSystemInclude(DriverArgs, CC1Args, PathLE.str());304 305 return;306 }307 }308 309 addSystemInclude(DriverArgs, CC1Args, "/usr/include");310}311 312void ZOS::TryAddIncludeFromPath(llvm::SmallString<128> Path,313 const llvm::opt::ArgList &DriverArgs,314 llvm::opt::ArgStringList &CC1Args) const {315 if (!getVFS().exists(Path)) {316 if (DriverArgs.hasArg(options::OPT_v))317 WithColor::warning(errs(), "Clang")318 << "ignoring nonexistent directory \"" << Path << "\"\n";319 if (!DriverArgs.hasArg(options::OPT__HASH_HASH_HASH))320 return;321 }322 addSystemInclude(DriverArgs, CC1Args, Path);323}324 325void ZOS::AddClangCXXStdlibIncludeArgs(326 const llvm::opt::ArgList &DriverArgs,327 llvm::opt::ArgStringList &CC1Args) const {328 if (DriverArgs.hasArg(options::OPT_nostdinc) ||329 DriverArgs.hasArg(options::OPT_nostdincxx) ||330 DriverArgs.hasArg(options::OPT_nostdlibinc))331 return;332 333 switch (GetCXXStdlibType(DriverArgs)) {334 case ToolChain::CST_Libcxx: {335 // <install>/bin/../include/c++/v1336 llvm::SmallString<128> InstallBin(getDriver().Dir);337 llvm::sys::path::append(InstallBin, "..", "include", "c++", "v1");338 TryAddIncludeFromPath(InstallBin, DriverArgs, CC1Args);339 break;340 }341 case ToolChain::CST_Libstdcxx:342 llvm::report_fatal_error(343 "picking up libstdc++ headers is unimplemented on z/OS");344 break;345 }346}347