Skip to content

Commit 79feafa

Browse files
committed
Add an internal bit to the XcodeSDK class.
For developing the OS itself there exists an "internal" variant of each SDK. This patch adds support for these SDK directories to the XcodeSDK class. Differential Revision: https://reviews.llvm.org/D78675
1 parent 35e6a9c commit 79feafa

File tree

5 files changed

+223
-68
lines changed

5 files changed

+223
-68
lines changed

lldb/include/lldb/Utility/XcodeSDK.h

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ class XcodeSDK {
2222

2323
public:
2424
XcodeSDK() = default;
25+
/// Initialize an XcodeSDK object with an SDK name. The SDK name is the last
26+
/// directory component of a path one would pass to clang's -isysroot
27+
/// parameter. For example, "MacOSX.10.14.sdk".
2528
XcodeSDK(std::string &&name) : m_name(std::move(name)) {}
2629
static XcodeSDK GetAnyMacOS() { return XcodeSDK("MacOSX.sdk"); }
2730

@@ -38,7 +41,6 @@ class XcodeSDK {
3841
numSDKTypes,
3942
unknown = -1
4043
};
41-
static llvm::StringRef GetNameForType(Type type);
4244

4345
/// The merge function follows a strict order to maintain monotonicity:
4446
/// 1. SDK with the higher SDKType wins.
@@ -49,15 +51,27 @@ class XcodeSDK {
4951
XcodeSDK(const XcodeSDK&) = default;
5052
bool operator==(XcodeSDK other);
5153

52-
/// Return parsed SDK number, and SDK version number.
53-
std::tuple<Type, llvm::VersionTuple> Parse() const;
54+
/// A parsed SDK directory name.
55+
struct Info {
56+
Type type = unknown;
57+
llvm::VersionTuple version;
58+
bool internal = false;
59+
60+
Info() = default;
61+
bool operator<(const Info &other) const;
62+
};
63+
64+
/// Return parsed SDK type and version number.
65+
Info Parse() const;
66+
bool IsAppleInternalSDK() const;
5467
llvm::VersionTuple GetVersion() const;
5568
Type GetType() const;
5669
llvm::StringRef GetString() const;
5770

5871
static bool SDKSupportsModules(Type type, llvm::VersionTuple version);
5972
static bool SDKSupportsModules(Type desired_type, const FileSpec &sdk_path);
60-
static llvm::StringRef GetSDKNameForType(Type type);
73+
/// Return the canonical SDK name, such as "macosx" for the macOS SDK.
74+
static std::string GetCanonicalName(Info info);
6175
};
6276

6377
} // namespace lldb_private

lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm

Lines changed: 58 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -298,37 +298,66 @@ static void ParseOSVersion(llvm::VersionTuple &version, NSString *Key) {
298298
}
299299

300300
std::string HostInfoMacOSX::GetXcodeSDK(XcodeSDK sdk) {
301-
std::string xcrun_cmd = "xcrun --show-sdk-path --sdk " +
302-
XcodeSDK::GetSDKNameForType(sdk.GetType()).str();
303-
llvm::VersionTuple version = sdk.GetVersion();
304-
if (!version.empty())
305-
xcrun_cmd += version.getAsString();
306-
307-
int status = 0;
308-
int signo = 0;
309-
std::string output_str;
310-
lldb_private::Status error =
311-
Host::RunShellCommand(xcrun_cmd.c_str(), FileSpec(), &status, &signo,
312-
&output_str, std::chrono::seconds(15));
313-
314-
// Check that xcrun return something useful.
315-
if (status != 0 || output_str.empty())
316-
return {};
317-
318-
// Convert to a StringRef so we can manipulate the string without modifying
319-
// the underlying data.
320-
llvm::StringRef output(output_str);
321-
322-
// Remove any trailing newline characters.
323-
output = output.rtrim();
301+
XcodeSDK::Info info = sdk.Parse();
302+
std::string sdk_name = XcodeSDK::GetCanonicalName(info);
303+
auto find_sdk = [](std::string sdk_name) -> std::string {
304+
std::string xcrun_cmd = "xcrun --show-sdk-path --sdk " + sdk_name;
305+
int status = 0;
306+
int signo = 0;
307+
std::string output_str;
308+
lldb_private::Status error =
309+
Host::RunShellCommand(xcrun_cmd.c_str(), FileSpec(), &status, &signo,
310+
&output_str, std::chrono::seconds(15));
311+
312+
// Check that xcrun return something useful.
313+
if (status != 0 || output_str.empty())
314+
return {};
315+
316+
// Convert to a StringRef so we can manipulate the string without modifying
317+
// the underlying data.
318+
llvm::StringRef output(output_str);
319+
320+
// Remove any trailing newline characters.
321+
output = output.rtrim();
322+
323+
// Strip any leading newline characters and everything before them.
324+
const size_t last_newline = output.rfind('\n');
325+
if (last_newline != llvm::StringRef::npos)
326+
output = output.substr(last_newline + 1);
327+
328+
return output.str();
329+
};
330+
331+
std::string path = find_sdk(sdk_name);
332+
while (path.empty()) {
333+
// Try an alternate spelling of the name ("macosx10.9internal").
334+
if (info.type == XcodeSDK::Type::MacOSX && !info.version.empty() &&
335+
info.internal) {
336+
llvm::StringRef fixed(sdk_name);
337+
if (fixed.consume_back(".internal"))
338+
sdk_name = fixed.str() + "internal";
339+
path = find_sdk(sdk_name);
340+
if (!path.empty())
341+
break;
342+
}
343+
Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
344+
LLDB_LOGF(log, "Couldn't find SDK %s on host", sdk_name.c_str());
345+
346+
// Try without the version.
347+
if (!info.version.empty()) {
348+
info.version = {};
349+
sdk_name = XcodeSDK::GetCanonicalName(info);
350+
path = find_sdk(sdk_name);
351+
if (!path.empty())
352+
break;
353+
}
324354

325-
// Strip any leading newline characters and everything before them.
326-
const size_t last_newline = output.rfind('\n');
327-
if (last_newline != llvm::StringRef::npos)
328-
output = output.substr(last_newline + 1);
355+
LLDB_LOGF(log, "Couldn't find any matching SDK on host");
356+
return {};
357+
}
329358

330359
// Whatever is left in output should be a valid path.
331-
if (!FileSystem::Instance().Exists(output))
360+
if (!FileSystem::Instance().Exists(path))
332361
return {};
333-
return output.str();
362+
return path;
334363
}

lldb/source/Utility/XcodeSDK.cpp

Lines changed: 61 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,24 @@ static llvm::VersionTuple ParseSDKVersion(llvm::StringRef &name) {
6464
return version;
6565
}
6666

67+
static bool ParseAppleInternalSDK(llvm::StringRef &name) {
68+
return name.consume_front("Internal.");
69+
}
70+
71+
XcodeSDK::Info XcodeSDK::Parse() const {
72+
XcodeSDK::Info info;
73+
llvm::StringRef input(m_name);
74+
info.type = ParseSDKName(input);
75+
info.version = ParseSDKVersion(input);
76+
info.internal = ParseAppleInternalSDK(input);
77+
return info;
78+
}
6779

68-
std::tuple<XcodeSDK::Type, llvm::VersionTuple> XcodeSDK::Parse() const {
80+
bool XcodeSDK::IsAppleInternalSDK() const {
6981
llvm::StringRef input(m_name);
70-
XcodeSDK::Type sdk = ParseSDKName(input);
71-
llvm::VersionTuple version = ParseSDKVersion(input);
72-
return std::make_tuple<XcodeSDK::Type, llvm::VersionTuple>(
73-
std::move(sdk), std::move(version));
82+
ParseSDKName(input);
83+
ParseSDKVersion(input);
84+
return ParseAppleInternalSDK(input);
7485
}
7586

7687
llvm::VersionTuple XcodeSDK::GetVersion() const {
@@ -86,37 +97,64 @@ XcodeSDK::Type XcodeSDK::GetType() const {
8697

8798
llvm::StringRef XcodeSDK::GetString() const { return m_name; }
8899

100+
bool XcodeSDK::Info::operator<(const Info &other) const {
101+
return std::tie(type, version, internal) <
102+
std::tie(other.type, other.version, other.internal);
103+
}
89104
void XcodeSDK::Merge(XcodeSDK other) {
90105
// The "bigger" SDK always wins.
91-
if (Parse() < other.Parse())
106+
auto l = Parse();
107+
auto r = other.Parse();
108+
if (l < r)
92109
*this = other;
110+
else {
111+
// The Internal flag always wins.
112+
if (llvm::StringRef(m_name).endswith(".sdk"))
113+
if (!l.internal && r.internal)
114+
m_name =
115+
m_name.substr(0, m_name.size() - 3) + std::string("Internal.sdk");
116+
}
93117
}
94118

95-
llvm::StringRef XcodeSDK::GetSDKNameForType(XcodeSDK::Type type) {
96-
switch (type) {
119+
std::string XcodeSDK::GetCanonicalName(XcodeSDK::Info info) {
120+
std::string name;
121+
switch (info.type) {
97122
case MacOSX:
98-
return "macosx";
123+
name = "macosx";
124+
break;
99125
case iPhoneSimulator:
100-
return "iphonesimulator";
126+
name = "iphonesimulator";
127+
break;
101128
case iPhoneOS:
102-
return "iphoneos";
129+
name = "iphoneos";
130+
break;
103131
case AppleTVSimulator:
104-
return "appletvsimulator";
132+
name = "appletvsimulator";
133+
break;
105134
case AppleTVOS:
106-
return "appletvos";
135+
name = "appletvos";
136+
break;
107137
case WatchSimulator:
108-
return "watchsimulator";
138+
name = "watchsimulator";
139+
break;
109140
case watchOS:
110-
return "watchos";
141+
name = "watchos";
142+
break;
111143
case bridgeOS:
112-
return "bridgeos";
144+
name = "bridgeos";
145+
break;
113146
case Linux:
114-
return "linux";
147+
name = "linux";
148+
break;
115149
case numSDKTypes:
116150
case unknown:
117-
return "";
151+
return {};
118152
}
119-
llvm_unreachable("unhandled switch case");
153+
if (!info.version.empty())
154+
name += info.version.getAsString();
155+
if (info.internal)
156+
name += ".internal";
157+
return name;
120158
}
121159

122160
bool XcodeSDK::SDKSupportsModules(XcodeSDK::Type sdk_type,
@@ -147,12 +185,15 @@ bool XcodeSDK::SDKSupportsModules(XcodeSDK::Type desired_type,
147185
const llvm::StringRef sdk_name = last_path_component.GetStringRef();
148186

149187
const std::string sdk_name_lower = sdk_name.lower();
150-
const llvm::StringRef sdk_string = GetSDKNameForType(desired_type);
188+
Info info;
189+
info.type = desired_type;
190+
const llvm::StringRef sdk_string = GetCanonicalName(info);
151191
if (!llvm::StringRef(sdk_name_lower).startswith(sdk_string))
152192
return false;
153193

154194
auto version_part = sdk_name.drop_front(sdk_string.size());
155195
version_part.consume_back(".sdk");
196+
version_part.consume_back(".Internal");
156197

157198
llvm::VersionTuple version;
158199
if (version.tryParse(version_part))

lldb/unittests/Host/HostInfoTest.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,13 @@ TEST_F(HostInfoTest, GetHostname) {
5050
std::string s("abc");
5151
EXPECT_TRUE(HostInfo::GetHostname(s));
5252
}
53+
54+
#if defined(__APPLE__)
55+
TEST_F(HostInfoTest, GetXcodeSDK) {
56+
EXPECT_FALSE(HostInfo::GetXcodeSDK(XcodeSDK("MacOSX.sdk")).empty());
57+
// These are expected to fall back to an available version.
58+
EXPECT_FALSE(HostInfo::GetXcodeSDK(XcodeSDK("MacOSX9999.sdk")).empty());
59+
// This is expected to fail.
60+
EXPECT_TRUE(HostInfo::GetXcodeSDK(XcodeSDK("CeciNestPasUnOS.sdk")).empty());
61+
}
62+
#endif

0 commit comments

Comments
 (0)