clang: lib/Driver/Multilib.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

12#include "llvm/ADT/DenseSet.h"

13#include "llvm/ADT/SmallSet.h"

14#include "llvm/ADT/StringRef.h"

15#include "llvm/Support/Compiler.h"

16#include "llvm/Support/ErrorHandling.h"

17#include "llvm/Support/Regex.h"

18#include "llvm/Support/VersionTuple.h"

19#include "llvm/Support/YAMLParser.h"

20#include "llvm/Support/YAMLTraits.h"

21#include "llvm/Support/raw_ostream.h"

22#include

23#include

24#include

25

26using namespace clang;

27using namespace driver;

28using namespace llvm::sys;

29

31 StringRef IncludeSuffix, const flags_list &Flags,

32 StringRef ExclusiveGroup, std::optional Error)

33 : GCCSuffix(GCCSuffix), OSSuffix(OSSuffix), IncludeSuffix(IncludeSuffix),

34 Flags(Flags), ExclusiveGroup(ExclusiveGroup), Error(Error) {

35 assert(GCCSuffix.empty() ||

36 (StringRef(GCCSuffix).front() == '/' && GCCSuffix.size() > 1));

37 assert(OSSuffix.empty() ||

38 (StringRef(OSSuffix).front() == '/' && OSSuffix.size() > 1));

39 assert(IncludeSuffix.empty() ||

40 (StringRef(IncludeSuffix).front() == '/' && IncludeSuffix.size() > 1));

41}

42

44 print(llvm::errs());

45}

46

48 if (GCCSuffix.empty())

49 OS << ".";

50 else {

51 OS << StringRef(GCCSuffix).drop_front();

52 }

53 OS << ";";

54 for (StringRef Flag : Flags) {

55 if (Flag.front() == '-')

56 OS << "@" << Flag.substr(1);

57 }

58}

59

61

62

63 llvm::StringSet<> MyFlags;

64 for (const auto &Flag : Flags)

65 MyFlags.insert(Flag);

66

67 for (const auto &Flag : Other.Flags)

68 if (!MyFlags.contains(Flag))

69 return false;

70

72 return false;

73

75 return false;

76

78 return false;

79

80 return true;

81}

82

85 return OS;

86}

87

89 llvm::erase_if(Multilibs, F);

90 return *this;

91}

92

94

98 struct EditDistanceInfo {

99 StringRef FlagValue;

100 unsigned EditDistance;

101 };

102 const unsigned MaxEditDistance = 5;

103

104 for (StringRef Unclaimed : UnclaimedCustomFlagValues) {

105 std::optional BestCandidate;

106 for (const auto &Decl : CustomFlagDecls) {

107 for (const auto &Value : Decl.ValueList) {

108 const std::string &FlagValueName = Value.Name;

109 unsigned EditDistance =

110 Unclaimed.edit_distance(FlagValueName, true,

111 MaxEditDistance);

112 if (!BestCandidate || (EditDistance <= MaxEditDistance &&

113 EditDistance < BestCandidate->EditDistance)) {

114 BestCandidate = {FlagValueName, EditDistance};

115 }

116 }

117 }

118 if (!BestCandidate)

119 D.Diag(clang::diag::err_drv_unsupported_opt)

121 else

122 D.Diag(clang::diag::err_drv_unsupported_opt_with_suggestion)

125 }

126}

127

129

130

133

134public:

135 template

137 for (auto DeclIt = FlagDeclsBegin; DeclIt != FlagDeclsEnd; ++DeclIt) {

139 for (const auto &Value : Decl.ValueList)

140 Mapping.emplace_back(Value.Name, &Value);

141 }

142 }

143

145 auto Iter = llvm::find_if(

146 Mapping, [&](const auto &Pair) { return Pair.first == Key; });

147 return Iter != Mapping.end() ? Iter->second : nullptr;

148 }

149};

150}

151

152std::pair<Multilib::flags_list, SmallVector>

157

158

160

161

162

164

166 CustomFlagDecls.begin(), CustomFlagDecls.end());

167

168 for (StringRef Flag : Flags) {

170 Result.push_back(Flag.str());

171 continue;

172 }

173

176 ValueNameToValueDetail.get(CustomFlagValueStr);

177 if (Detail)

178 ClaimedCustomFlagValues.push_back(Detail);

179 else

180 UnclaimedCustomFlagValueStrs.push_back(CustomFlagValueStr);

181 }

182

183

184

185

186

187

189

190

191 for (auto *CustomFlagValue : llvm::reverse(ClaimedCustomFlagValues)) {

192 if (!TriggeredCustomFlagDecls.insert(CustomFlagValue->Decl).second)

193 continue;

195 if (CustomFlagValue->MacroDefines)

196 MacroDefines.append(CustomFlagValue->MacroDefines->begin(),

197 CustomFlagValue->MacroDefines->end());

198 }

199

200

201 for (const auto &Decl : CustomFlagDecls) {

202 if (TriggeredCustomFlagDecls.contains(&Decl))

203 continue;

205 Decl.ValueList[*Decl.DefaultValueIdx];

208 MacroDefines.append(CustomFlagValue.MacroDefines->begin(),

210 }

211

213 CustomFlagDecls);

214

215 return {Result, MacroDefines};

216}

217

223 llvm::StringSet<> FlagSet(expandFlags(FlagsWithCustom));

224 Selected.clear();

225 bool AnyErrors = false;

226

227

228

229

230

231 if (CustomFlagMacroDefines)

232 *CustomFlagMacroDefines = std::move(CFMacroDefines);

233

234

235 llvm::DenseSet ExclusiveGroupsSelected;

236 for (const Multilib &M : llvm::reverse(Multilibs)) {

237

238 if (!llvm::all_of(M.flags(), [&FlagSet](const std::string &F) {

239 return FlagSet.contains(F);

240 }))

241 continue;

242

243 const std::string &group = M.exclusiveGroup();

244 if (!group.empty()) {

245

246

247

248

249

250

251 auto [It, Inserted] = ExclusiveGroupsSelected.insert(group);

252 if (!Inserted)

253 continue;

254 }

255

256

257

258

259 if (M.isError())

260 AnyErrors = true;

261

262

263 Selected.push_back(M);

264 }

265

266

267

268 std::reverse(Selected.begin(), Selected.end());

269

270 return !AnyErrors && !Selected.empty();

271}

272

273llvm::StringSet<>

275 llvm::StringSet<> Result;

276 for (const auto &F : InFlags)

278 for (const FlagMatcher &M : FlagMatchers) {

279 std::string RegexString(M.Match);

280

281

282 if (!StringRef(M.Match).starts_with("^"))

283 RegexString.insert(RegexString.begin(), '^');

284 if (!StringRef(M.Match).ends_with("$"))

285 RegexString.push_back('$');

286

287 const llvm::Regex Regex(RegexString);

288 assert(Regex.isValid());

289 if (llvm::any_of(InFlags,

290 [&Regex](StringRef F) { return Regex.match(F); })) {

291 Result.insert(M.Flags.begin(), M.Flags.end());

292 }

293 }

295}

296

297namespace {

298

299

300static const VersionTuple MultilibVersionCurrent(1, 0);

301

302struct MultilibSerialization {

303 std::string Dir;

304 std::string Error;

305 std::vectorstd::string Flags;

306 std::string Group;

307};

308

309enum class MultilibGroupType {

310

311

312

313

314 Exclusive,

315

316

317

318

319

320

321

322

323

324

325

326

327

328

329};

330

331struct MultilibGroupSerialization {

332 std::string Name;

333 MultilibGroupType Type;

334};

335

336struct MultilibSetSerialization {

337 llvm::VersionTuple MultilibVersion;

342};

343

344}

345

346LLVM_YAML_IS_SEQUENCE_VECTOR(MultilibSerialization)

347LLVM_YAML_IS_SEQUENCE_VECTOR(MultilibGroupSerialization)

351

352template <> struct llvm::yaml::MappingTraits {

353 static void mapping(llvm::yaml::IO &io, MultilibSerialization &V) {

354 io.mapOptional("Dir", V.Dir);

355 io.mapOptional("Error", V.Error);

356 io.mapRequired("Flags", V.Flags);

357 io.mapOptional("Group", V.Group);

358 }

359 static std::string validate(IO &io, MultilibSerialization &V) {

360 if (V.Dir.empty() && V.Error.empty())

361 return "one of the 'Dir' and 'Error' keys must be specified";

362 if (V.Dir.empty() && V.Error.empty())

363 return "the 'Dir' and 'Error' keys may not both be specified";

364 if (StringRef(V.Dir).starts_with("/"))

365 return "paths must be relative but \"" + V.Dir + "\" starts with \"/\"";

366 return std::string{};

367 }

368};

369

370template <> struct llvm::yaml::ScalarEnumerationTraits {

371 static void enumeration(IO &io, MultilibGroupType &Val) {

372 io.enumCase(Val, "Exclusive", MultilibGroupType::Exclusive);

373 }

374};

375

376template <> struct llvm::yaml::MappingTraits {

377 static void mapping(llvm::yaml::IO &io, MultilibGroupSerialization &V) {

378 io.mapRequired("Name", V.Name);

379 io.mapRequired("Type", V.Type);

380 }

381};

382

383template <> struct llvm::yaml::MappingTraits<MultilibSet::FlagMatcher> {

385 io.mapRequired("Match", M.Match);

386 io.mapRequired("Flags", M.Flags);

387 }

389 llvm::Regex Regex(M.Match);

390 std::string RegexError;

391 if (!Regex.isValid(RegexError))

392 return RegexError;

393 if (M.Flags.empty())

394 return "value required for 'Flags'";

395 return std::string{};

396 }

397};

398

399template <>

400struct llvm::yaml::MappingContextTraits<custom_flag::ValueDetail,

401 llvm::SmallSet<std::string, 32>> {

403 llvm::SmallSet<std::string, 32> &) {

404 io.mapRequired("Name", V.Name);

405 io.mapOptional("MacroDefines", V.MacroDefines);

406 }

408 llvm::SmallSet<std::string, 32> &NameSet) {

409 if (V.Name.empty())

410 return "custom flag value requires a name";

411 if (!NameSet.insert(V.Name).second)

412 return "duplicate custom flag value name: \"" + V.Name + "\"";

413 return {};

414 }

415};

416

417template <>

418struct llvm::yaml::MappingContextTraits<custom_flag::Declaration,

419 llvm::SmallSet<std::string, 32>> {

421 llvm::SmallSet<std::string, 32> &NameSet) {

422 io.mapRequired("Name", V.Name);

423 io.mapRequired("Values", V.ValueList, NameSet);

424 std::string DefaultValueName;

425 io.mapRequired("Default", DefaultValueName);

426

427 for (auto [Idx, Value] : llvm::enumerate(V.ValueList)) {

429 if (Value.Name == DefaultValueName) {

430 assert(V.DefaultValueIdx);

431 V.DefaultValueIdx = Idx;

432 }

433 }

434 }

436 llvm::SmallSet<std::string, 32> &) {

437 if (V.Name.empty())

438 return "custom flag requires a name";

439 if (V.ValueList.empty())

440 return "custom flag must have at least one value";

441 if (V.DefaultValueIdx)

442 return "custom flag must have a default value";

443 return {};

444 }

445};

446

447template <> struct llvm::yaml::MappingTraits {

448 static void mapping(llvm::yaml::IO &io, MultilibSetSerialization &M) {

449 io.mapRequired("MultilibVersion", M.MultilibVersion);

450 io.mapRequired("Variants", M.Multilibs);

451 io.mapOptional("Groups", M.Groups);

452 llvm::SmallSet<std::string, 32> NameSet;

453 io.mapOptionalWithContext("Flags", M.CustomFlagDeclarations, NameSet);

454 io.mapOptional("Mappings", M.FlagMatchers);

455 }

456 static std::string validate(IO &io, MultilibSetSerialization &M) {

457 if (M.MultilibVersion.empty())

458 return "missing required key 'MultilibVersion'";

459 if (M.MultilibVersion.getMajor() != MultilibVersionCurrent.getMajor())

460 return "multilib version " + M.MultilibVersion.getAsString() +

461 " is unsupported";

462 if (M.MultilibVersion.getMinor() > MultilibVersionCurrent.getMinor())

463 return "multilib version " + M.MultilibVersion.getAsString() +

464 " is unsupported";

465 for (const MultilibSerialization &Lib : M.Multilibs) {

466 if (!Lib.Group.empty()) {

467 bool Found = false;

468 for (const MultilibGroupSerialization &Group : M.Groups)

469 if (Group.Name == Lib.Group) {

471 break;

472 }

474 return "multilib \"" + Lib.Dir +

475 "\" specifies undefined group name \"" + Lib.Group + "\"";

476 }

477 }

478 return std::string{};

479 }

480};

481

482llvm::ErrorOr

484 llvm::SourceMgr::DiagHandlerTy DiagHandler,

485 void *DiagHandlerCtxt) {

486 MultilibSetSerialization MS;

487 llvm::yaml::Input YamlInput(Input, nullptr, DiagHandler, DiagHandlerCtxt);

488 YamlInput >> MS;

489 if (YamlInput.error())

490 return YamlInput.error();

491

493 Multilibs.reserve(MS.Multilibs.size());

494 for (const auto &M : MS.Multilibs) {

495 if (!M.Error.empty()) {

496 Multilibs.emplace_back("", "", "", M.Flags, M.Group, M.Error);

497 } else {

498 std::string Dir;

499 if (M.Dir != ".")

500 Dir = "/" + M.Dir;

501

502

503

504

505 Multilibs.emplace_back(Dir, Dir, Dir, M.Flags, M.Group);

506 }

507 }

508

509 return MultilibSet(std::move(Multilibs), std::move(MS.FlagMatchers),

510 std::move(MS.CustomFlagDeclarations));

511}

512

514 print(llvm::errs());

515}

516

518 for (const auto &M : *this)

519 OS << M << "\n";

520}

521

524 return OS;

525}

526

530 DefaultValueIdx(Other.DefaultValueIdx) {

532 Detail.Decl = this;

533}

534

537 DefaultValueIdx(std::move(Other.DefaultValueIdx)) {

539 Detail.Decl = this;

540}

541

543 if (this == &Other)

544 return *this;

549 Detail.Decl = this;

550 return *this;

551}

552

554 if (this == &Other)

555 return *this;

560 Detail.Decl = this;

561 return *this;

562}

563}

Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.

static void DiagnoseUnclaimedMultilibCustomFlags(const Driver &D, const SmallVector< StringRef > &UnclaimedCustomFlagValues, const SmallVector< custom_flag::Declaration > &CustomFlagDecls)

Decl - This represents one declaration (or definition), e.g.

The base class of the type hierarchy.

Driver - Encapsulate logic for constructing compilation processes from a set of gcc-driver-like comma...

See also MultilibSetBuilder for combining multilibs into a set.

bool select(const Driver &D, const Multilib::flags_list &Flags, llvm::SmallVectorImpl< Multilib > &, llvm::SmallVector< StringRef > *=nullptr) const

Select compatible variants,.

LLVM_DUMP_METHOD void dump() const

llvm::function_ref< bool(const Multilib &)> FilterCallback

static llvm::ErrorOr< MultilibSet > parseYaml(llvm::MemoryBufferRef, llvm::SourceMgr::DiagHandlerTy=nullptr, void *DiagHandlerCtxt=nullptr)

void print(raw_ostream &OS) const

MultilibSet & FilterOut(FilterCallback F)

Filter out some subset of the Multilibs using a user defined callback.

std::vector< Multilib > multilib_list

llvm::StringSet expandFlags(const Multilib::flags_list &) const

Get the given flags plus flags found by matching them against the FlagMatchers and choosing the Flags...

void push_back(const Multilib &M)

Add a completed Multilib to the set.

std::pair< Multilib::flags_list, SmallVector< StringRef > > processCustomFlags(const Driver &D, const Multilib::flags_list &Flags) const

Process custom flags from Flags and returns an expanded flags list and a list of macro defines.

This corresponds to a single GCC Multilib, or a segment of one controlled by a command line flag.

const std::string & gccSuffix() const

Get the detected GCC installation path suffix for the multi-arch target variant.

const std::string & osSuffix() const

Get the detected os path suffix for the multi-arch target variant.

std::vector< std::string > flags_list

Multilib(StringRef GCCSuffix={}, StringRef OSSuffix={}, StringRef IncludeSuffix={}, const flags_list &Flags=flags_list(), StringRef ExclusiveGroup={}, std::optional< StringRef > Error=std::nullopt)

GCCSuffix, OSSuffix & IncludeSuffix will be appended directly to the sysroot string so they must eith...

const std::string & includeSuffix() const

Get the include directory suffix.

LLVM_DUMP_METHOD void dump() const

void print(raw_ostream &OS) const

print summary of the Multilib

bool operator==(const Multilib &Other) const

ValueNameToDetailMap(It FlagDeclsBegin, It FlagDeclsEnd)

const ValueDetail * get(StringRef Key) const

static constexpr StringRef Prefix

raw_ostream & operator<<(raw_ostream &OS, const Multilib &M)

The JSON file list parser is used to communicate input to InstallAPI.

@ Result

The result type of a method or function.

@ Other

Other implicit parameter.

Diagnostic wrappers for TextAPI types for error reporting.

Uses regular expressions to simplify flags used for multilib selection.

std::vector< std::string > Flags

Declaration & operator=(const Declaration &)

std::optional< size_t > DefaultValueIdx

std::optional< SmallVector< std::string > > MacroDefines

static std::string validate(IO &io, custom_flag::Declaration &V, llvm::SmallSet< std::string, 32 > &)

static void mapping(llvm::yaml::IO &io, custom_flag::Declaration &V, llvm::SmallSet< std::string, 32 > &NameSet)

static void mapping(llvm::yaml::IO &io, custom_flag::ValueDetail &V, llvm::SmallSet< std::string, 32 > &)

static std::string validate(IO &io, custom_flag::ValueDetail &V, llvm::SmallSet< std::string, 32 > &NameSet)

static void mapping(llvm::yaml::IO &io, MultilibGroupSerialization &V)

static void mapping(llvm::yaml::IO &io, MultilibSerialization &V)

static std::string validate(IO &io, MultilibSerialization &V)

static void mapping(llvm::yaml::IO &io, MultilibSetSerialization &M)

static std::string validate(IO &io, MultilibSetSerialization &M)

static std::string validate(IO &io, MultilibSet::FlagMatcher &M)

static void mapping(llvm::yaml::IO &io, MultilibSet::FlagMatcher &M)

static void enumeration(IO &io, MultilibGroupType &Val)