1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
|
//===- lib/Driver/UniversalDriver.cpp -------------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
///
/// Concrete instance of the Driver for darwin's ld.
///
//===----------------------------------------------------------------------===//
#include "lld/Driver/Driver.h"
#include "lld/Core/LLVM.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
using namespace lld;
namespace {
enum class Flavor {
invalid,
gnu_ld, // -flavor gnu
win_link, // -flavor link
darwin_ld, // -flavor darwin
core // -flavor core OR -core
};
Flavor strToFlavor(StringRef str) {
return llvm::StringSwitch<Flavor>(str)
.Case("gnu", Flavor::gnu_ld)
.Case("link", Flavor::win_link)
.Case("darwin", Flavor::darwin_ld)
.Case("core", Flavor::core)
.Case("ld", Flavor::gnu_ld) // deprecated
.Default(Flavor::invalid);
}
struct ProgramNameParts {
StringRef _target;
StringRef _flavor;
};
ProgramNameParts parseProgramName(StringRef programName) {
SmallVector<StringRef, 3> components;
llvm::SplitString(programName, components, "-");
ProgramNameParts ret;
using std::begin;
using std::end;
// Erase any lld components.
components.erase(std::remove(components.begin(), components.end(), "lld"),
components.end());
// Find the flavor component.
auto flIter = std::find_if(components.begin(), components.end(),
[](StringRef str)->bool {
return strToFlavor(str) != Flavor::invalid;
});
if (flIter != components.end()) {
ret._flavor = *flIter;
components.erase(flIter);
}
// Any remaining component must be the target.
if (components.size() == 1)
ret._target = components[0];
return ret;
}
Flavor selectFlavor(std::vector<const char *> &args, raw_ostream &diag) {
// -core as first arg is shorthand for -flavor core.
if (args.size() > 1 && StringRef(args[1]) == "-core") {
args.erase(args.begin() + 1);
return Flavor::core;
}
// Handle -flavor as first arg.
if (args.size() > 2 && StringRef(args[1]) == "-flavor") {
Flavor flavor = strToFlavor(args[2]);
args.erase(args.begin() + 1);
args.erase(args.begin() + 1);
if (flavor == Flavor::invalid)
diag << "error: '" << args[2] << "' invalid value for -flavor.\n";
return flavor;
}
Flavor flavor =
strToFlavor(parseProgramName(llvm::sys::path::stem(args[0]))._flavor);
// If flavor still undetermined, then error out.
if (flavor == Flavor::invalid)
diag << "error: failed to determine driver flavor from program name"
" '" << args[0] << "'.\n";
return flavor;
}
}
namespace lld {
bool UniversalDriver::link(int argc, const char *argv[],
raw_ostream &diagnostics) {
// Convert argv[] C-array to vector.
std::vector<const char *> args(argv, argv + argc);
// Determine flavor of link based on command name or -flavor argument.
// Note: 'args' is modified to remove -flavor option.
Flavor flavor = selectFlavor(args, diagnostics);
// Switch to appropriate driver.
switch (flavor) {
case Flavor::gnu_ld:
return GnuLdDriver::linkELF(args.size(), args.data(), diagnostics);
case Flavor::darwin_ld:
return DarwinLdDriver::linkMachO(args.size(), args.data(), diagnostics);
case Flavor::core:
return CoreDriver::link(args.size(), args.data(), diagnostics);
case Flavor::win_link:
llvm_unreachable("Unsupported flavor");
case Flavor::invalid:
return true;
}
llvm_unreachable("Unrecognised flavor");
}
} // end namespace lld
|