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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "ZOS.h" 10 #include "clang/Driver/CommonArgs.h" 11 #include "clang/Driver/Compilation.h" 12 #include "clang/Driver/Options.h" 13 #include "llvm/Option/ArgList.h" 14 #include "llvm/Support/VirtualFileSystem.h" 15 #include "llvm/Support/WithColor.h" 16 17 using namespace clang; 18 using namespace clang::driver; 19 using namespace clang::driver::tools; 20 using namespace clang::driver::toolchains; 21 using namespace llvm; 22 using namespace llvm::opt; 23 using namespace llvm::sys; 24 25 ZOS::ZOS(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) 26 : ToolChain(D, Triple, Args) {} 27 28 ZOS::~ZOS() {} 29 30 void ZOS::addClangTargetOptions(const ArgList &DriverArgs, 31 ArgStringList &CC1Args, 32 Action::OffloadKind DeviceOffloadKind) const { 33 // Pass "-faligned-alloc-unavailable" only when the user hasn't manually 34 // 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 enabled 44 // 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 50 void 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 is 68 // 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)); 79 } 80 81 static 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 91 static 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 101 static 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 111 void 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 add 154 // 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 when 161 // the object file contains exported symbols, and -shared or 162 // -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++ library 206 if (ToolChain.ShouldLinkCXXStdlib(Args)) { 207 ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); 208 } 209 210 // Specify compiler-rt library path for linker 211 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)); 217 } 218 219 ToolChain::RuntimeLibType ZOS::GetDefaultRuntimeLibType() const { 220 return ToolChain::RLT_CompilerRT; 221 } 222 223 ToolChain::CXXStdlibType ZOS::GetDefaultCXXStdlibType() const { 224 return ToolChain::CST_Libcxx; 225 } 226 227 void 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 251 auto ZOS::buildAssembler() const -> Tool * { return new zos::Assembler(*this); } 252 253 auto ZOS::buildLinker() const -> Tool * { return new zos::Linker(*this); } 254 255 void 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 ResourceDir 263 std::string ResourceDir(D.ResourceDir); 264 265 // zos_wrappers must take highest precedence 266 267 // - <clang>/lib/clang/<ver>/include/zos_wrappers 268 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>/include 274 SmallString<128> P2(ResourceDir); 275 path::append(P2, "include"); 276 addSystemInclude(DriverArgs, CC1Args, P2.str()); 277 } 278 279 // - /usr/include 280 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 path 285 if (!SysInclude.empty()) { 286 287 // -mzos-sys-include opton can have colon separated 288 // 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 312 void 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 325 void 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++/v1 336 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