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