Skip to content

Commit 7ae91f3

Browse files
committed
fixes
1 parent 650723f commit 7ae91f3

6 files changed

Lines changed: 267 additions & 35 deletions

File tree

NativeScript/ffi/ClassMember.mm

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -88,18 +88,19 @@ napi_value JS_NSObject_alloc(napi_env env, napi_callback_info cbinfo) {
8888
offset += sizeof(MDSectionOffset); // setterSignature
8989
}
9090

91-
if (memberMap.contains(name)) {
92-
memberMap.erase(name);
91+
auto updatedMember = ObjCClassMember(
92+
bridgeState, sel_registerName(getterSelector),
93+
!readonly ? sel_registerName(setterSelector) : nullptr,
94+
getterSignature + bridgeState->metadata->signaturesOffset,
95+
!readonly ? setterSignature + bridgeState->metadata->signaturesOffset : 0, flags);
96+
auto memberIt = memberMap.find(name);
97+
if (memberIt != memberMap.end()) {
98+
memberIt->second = updatedMember;
99+
} else {
100+
const auto& inserted = memberMap.emplace(name, updatedMember);
101+
memberIt = inserted.first;
93102
}
94103

95-
const auto& kv = memberMap.emplace(
96-
name,
97-
ObjCClassMember(bridgeState, sel_registerName(getterSelector),
98-
!readonly ? sel_registerName(setterSelector) : nullptr,
99-
getterSignature + bridgeState->metadata->signaturesOffset,
100-
!readonly ? setterSignature + bridgeState->metadata->signaturesOffset : 0,
101-
flags));
102-
103104
napi_property_descriptor property = {
104105
.utf8name = name,
105106
.name = nil,
@@ -108,7 +109,7 @@ napi_value JS_NSObject_alloc(napi_env env, napi_callback_info cbinfo) {
108109
.setter = readonly ? nil : jsSetter,
109110
.value = nil,
110111
.attributes = (napi_property_attributes)(napi_configurable | napi_enumerable),
111-
.data = &kv.first->second,
112+
.data = &memberIt->second,
112113
};
113114

114115
napi_define_properties(env, jsObject, 1, &property);

NativeScript/ffi/Variable.mm

Lines changed: 56 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,26 +5,63 @@
55

66
namespace nativescript {
77

8+
namespace {
9+
10+
const char* getValidatedConstantString(MDMetadataReader* metadata,
11+
MDSectionOffset stringOffsetRef) {
12+
if (metadata == nullptr || metadata->data == nullptr) {
13+
return nullptr;
14+
}
15+
16+
if (stringOffsetRef < metadata->constantsOffset ||
17+
stringOffsetRef + sizeof(MDSectionOffset) > metadata->enumsOffset) {
18+
return nullptr;
19+
}
20+
21+
const auto stringsStart = static_cast<const char*>(metadata->data) + metadata->stringsOffset;
22+
const auto stringsSize = metadata->constantsOffset - metadata->stringsOffset;
23+
if (stringsSize == 0) {
24+
return nullptr;
25+
}
26+
27+
const auto stringOffset = metadata->getOffset(stringOffsetRef);
28+
if (stringOffset >= stringsSize) {
29+
return nullptr;
30+
}
31+
32+
const char* value = stringsStart + stringOffset;
33+
const auto remaining = stringsSize - stringOffset;
34+
if (memchr(value, '\0', remaining) == nullptr) {
35+
return nullptr;
36+
}
37+
38+
return value;
39+
}
40+
41+
} // namespace
42+
843
void ObjCBridgeState::registerVarGlobals(napi_env env, napi_value global) {
944
auto offset = metadata->constantsOffset;
1045
while (offset < metadata->enumsOffset) {
1146
MDSectionOffset originalOffset = offset;
12-
auto name = metadata->getString(offset);
47+
auto name = getValidatedConstantString(metadata, offset);
1348
offset += sizeof(MDSectionOffset);
1449
auto evalKind = metadata->getVariableEvalKind(offset);
1550
offset += sizeof(MDVariableEvalKind);
1651

17-
napi_property_descriptor prop = {
18-
.utf8name = name,
19-
.method = nullptr,
20-
.getter = JS_variableGetter,
21-
.setter = nullptr,
22-
.value = nullptr,
23-
.attributes = (napi_property_attributes)(napi_enumerable | napi_configurable),
24-
.data = (void*)((size_t)originalOffset),
25-
};
26-
27-
napi_define_properties(env, global, 1, &prop);
52+
if (name != nullptr && name[0] != '\0') {
53+
napi_property_descriptor prop = {
54+
.utf8name = name,
55+
.method = nullptr,
56+
.getter = JS_variableGetter,
57+
.setter = nullptr,
58+
.value = nullptr,
59+
.attributes = (napi_property_attributes)(napi_enumerable | napi_configurable),
60+
.data = (void*)((size_t)originalOffset),
61+
};
62+
63+
napi_define_properties(env, global, 1, &prop);
64+
}
2865

2966
switch (evalKind) {
3067
case mdEvalDouble: {
@@ -61,16 +98,20 @@
6198
return get_ref_value(env, cached);
6299
}
63100

101+
napi_value result = nullptr;
102+
64103
// Name
65-
auto name = bridgeState->metadata->getString(offset);
104+
auto name = getValidatedConstantString(bridgeState->metadata, offset);
105+
if (name == nullptr || name[0] == '\0') {
106+
napi_get_null(env, &result);
107+
return result;
108+
}
66109
offset += sizeof(MDSectionOffset);
67110

68111
// Eval kind
69112
auto evalKind = bridgeState->metadata->getVariableEvalKind(offset);
70113
offset += sizeof(MDVariableEvalKind);
71114

72-
napi_value result = nullptr;
73-
74115
switch (evalKind) {
75116
case mdEvalDouble: {
76117
auto value = bridgeState->metadata->getDouble(offset);

build_nativescript.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ BUILD_CATALYST=$(to_bool ${BUILD_CATALYST:=false}) # disable by default for now
66
BUILD_IPHONE=$(to_bool ${BUILD_IPHONE:=true})
77
BUILD_SIMULATOR=$(to_bool ${BUILD_SIMULATOR:=true})
88
BUILD_VISION=$(to_bool ${BUILD_VISION:=false}) # disable by default for now
9-
BUILD_MACOS=$(to_bool ${BUILD_MACOS:=false}) # disable by default for now
9+
BUILD_MACOS=$(to_bool ${BUILD_MACOS:=true})
1010
VERBOSE=$(to_bool ${VERBOSE:=false})
1111
BUILD_MACOS_CLI=$(to_bool ${BUILD_MACOS_CLI:=false})
1212
BUILD_MACOS_NODE_API=$(to_bool ${BUILD_MACOS_NODE_API:=false})

metadata-generator/include/Util.h

Lines changed: 155 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,102 @@
33
#include <clang-c/Index.h>
44
#include <algorithm>
55
#include <cctype>
6+
#include <cstdlib>
67
#include <string>
78
#include <vector>
89

910
namespace metagen {
1011

12+
enum class AvailabilityPlatform {
13+
Unknown,
14+
IOS,
15+
MacOS,
16+
TvOS,
17+
WatchOS,
18+
XROS,
19+
};
20+
21+
inline AvailabilityPlatform gAvailabilityPlatform = AvailabilityPlatform::Unknown;
22+
inline int gAvailabilityTargetMajor = -1;
23+
inline int gAvailabilityTargetMinor = -1;
24+
25+
inline AvailabilityPlatform platformFromTargetTriple(const std::string& targetTriple) {
26+
if (targetTriple.find("macosx") != std::string::npos) return AvailabilityPlatform::MacOS;
27+
if (targetTriple.find("ios") != std::string::npos) return AvailabilityPlatform::IOS;
28+
if (targetTriple.find("tvos") != std::string::npos) return AvailabilityPlatform::TvOS;
29+
if (targetTriple.find("watchos") != std::string::npos) return AvailabilityPlatform::WatchOS;
30+
if (targetTriple.find("xros") != std::string::npos) return AvailabilityPlatform::XROS;
31+
return AvailabilityPlatform::Unknown;
32+
}
33+
34+
inline bool parsePlatformVersionFromTargetTriple(const std::string& targetTriple, int& major,
35+
int& minor) {
36+
size_t pos = std::string::npos;
37+
if ((pos = targetTriple.find("macosx")) != std::string::npos) {
38+
pos += 6;
39+
} else if ((pos = targetTriple.find("watchos")) != std::string::npos) {
40+
pos += 7;
41+
} else if ((pos = targetTriple.find("tvos")) != std::string::npos) {
42+
pos += 4;
43+
} else if ((pos = targetTriple.find("xros")) != std::string::npos) {
44+
pos += 4;
45+
} else if ((pos = targetTriple.find("ios")) != std::string::npos) {
46+
pos += 3;
47+
} else {
48+
return false;
49+
}
50+
51+
if (pos >= targetTriple.size() || !std::isdigit(targetTriple[pos])) {
52+
return false;
53+
}
54+
55+
size_t start = pos;
56+
while (pos < targetTriple.size() && std::isdigit(targetTriple[pos])) pos++;
57+
major = std::atoi(targetTriple.substr(start, pos - start).c_str());
58+
minor = 0;
59+
60+
if (pos < targetTriple.size() && targetTriple[pos] == '.') {
61+
pos++;
62+
size_t minorStart = pos;
63+
while (pos < targetTriple.size() && std::isdigit(targetTriple[pos])) pos++;
64+
if (minorStart < pos) {
65+
minor = std::atoi(targetTriple.substr(minorStart, pos - minorStart).c_str());
66+
}
67+
}
68+
69+
return true;
70+
}
71+
72+
inline void setAvailabilityTargetTriple(const std::string& targetTriple) {
73+
gAvailabilityPlatform = platformFromTargetTriple(targetTriple);
74+
gAvailabilityTargetMajor = -1;
75+
gAvailabilityTargetMinor = -1;
76+
77+
int major = -1;
78+
int minor = -1;
79+
if (parsePlatformVersionFromTargetTriple(targetTriple, major, minor)) {
80+
gAvailabilityTargetMajor = major;
81+
gAvailabilityTargetMinor = minor;
82+
}
83+
}
84+
85+
inline const char* platformNameForAvailability(AvailabilityPlatform platform) {
86+
switch (platform) {
87+
case AvailabilityPlatform::IOS:
88+
return "ios";
89+
case AvailabilityPlatform::MacOS:
90+
return "macos";
91+
case AvailabilityPlatform::TvOS:
92+
return "tvos";
93+
case AvailabilityPlatform::WatchOS:
94+
return "watchos";
95+
case AvailabilityPlatform::XROS:
96+
return "xros";
97+
default:
98+
return nullptr;
99+
}
100+
}
101+
11102
inline std::string jsifySelector(const std::string& selector) {
12103
std::string jsifiedSelector;
13104
jsifiedSelector.reserve(selector.size());
@@ -118,9 +209,70 @@ inline std::string getFrameworkName(CXCursor cursor) {
118209
}
119210

120211
inline bool isAvailable(CXCursor cursor) {
121-
// Keep all declarations in metadata, except those that clang marks as
122-
// inaccessible.
123-
return clang_getCursorAvailability(cursor) != CXAvailability_NotAccessible;
212+
auto availability = clang_getCursorAvailability(cursor);
213+
if (availability != CXAvailability_Available &&
214+
availability != CXAvailability_Deprecated) {
215+
return false;
216+
}
217+
218+
if (gAvailabilityPlatform == AvailabilityPlatform::Unknown ||
219+
gAvailabilityTargetMajor < 0) {
220+
return true;
221+
}
222+
223+
int alwaysDeprecated = 0;
224+
int alwaysUnavailable = 0;
225+
CXString deprecatedMessage;
226+
CXString unavailableMessage;
227+
int availabilityCount = clang_getCursorPlatformAvailability(
228+
cursor, &alwaysDeprecated, &deprecatedMessage, &alwaysUnavailable,
229+
&unavailableMessage, nullptr, 0);
230+
clang_disposeString(deprecatedMessage);
231+
clang_disposeString(unavailableMessage);
232+
if (alwaysUnavailable) {
233+
return false;
234+
}
235+
236+
if (availabilityCount <= 0) {
237+
return true;
238+
}
239+
240+
std::vector<CXPlatformAvailability> platformAvailability(
241+
static_cast<size_t>(availabilityCount));
242+
clang_getCursorPlatformAvailability(
243+
cursor, &alwaysDeprecated, &deprecatedMessage, &alwaysUnavailable,
244+
&unavailableMessage, platformAvailability.data(), availabilityCount);
245+
clang_disposeString(deprecatedMessage);
246+
clang_disposeString(unavailableMessage);
247+
248+
const char* wantedPlatform = platformNameForAvailability(gAvailabilityPlatform);
249+
bool isCursorAvailableForTarget = true;
250+
for (auto& item : platformAvailability) {
251+
const char* platform = clang_getCString(item.Platform);
252+
if (wantedPlatform != nullptr && platform != nullptr &&
253+
std::string(platform) == wantedPlatform) {
254+
if (item.Unavailable) {
255+
continue;
256+
}
257+
258+
const int introducedMajor = item.Introduced.Major;
259+
const int introducedMinor =
260+
item.Introduced.Minor >= 0 ? item.Introduced.Minor : 0;
261+
if (introducedMajor >= 0 &&
262+
(introducedMajor > gAvailabilityTargetMajor ||
263+
(introducedMajor == gAvailabilityTargetMajor &&
264+
introducedMinor > gAvailabilityTargetMinor))) {
265+
isCursorAvailableForTarget = false;
266+
break;
267+
}
268+
}
269+
}
270+
271+
for (auto& item : platformAvailability) {
272+
clang_disposeCXPlatformAvailability(&item);
273+
}
274+
275+
return isCursorAvailableForTarget;
124276
}
125277

126278
inline bool isSelectorOwned(const std::string& selectorName) {

metadata-generator/src/Umbrella.cpp

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,8 @@ static std::error_code CreateUmbrellaHeaderForAmbientModule(
104104
}
105105

106106
if (std::filesystem::exists(headerPath)) {
107-
std::cerr << "Adding modulemap header: " << headerPath.string() << std::endl;
107+
std::cerr << "Adding modulemap header: " << headerPath.string()
108+
<< std::endl;
108109
std::string headerPathStr = headerPath.string();
109110
addHeaderInclude(headerPathStr, umbrellaHeaders, umbrellaHeaderSet);
110111
}
@@ -147,6 +148,27 @@ static std::error_code CreateUmbrellaHeaderForAmbientModulesInner(
147148
return std::error_code();
148149
}
149150

151+
// On macOS SDKs, keep only objc runtime headers from usr/include so we keep
152+
// symbols like class_getName while avoiding broad private header parsing.
153+
if (dir.find("/MacOSX.platform/Developer/SDKs/") != std::string::npos &&
154+
dir.ends_with("/usr/include")) {
155+
std::filesystem::path objcHeadersPath = std::filesystem::path(dir) / "objc";
156+
if (std::filesystem::exists(objcHeadersPath)) {
157+
if (std::error_code code = CreateUmbrellaHeaderForAmbientModulesInner(
158+
objcHeadersPath.string(), false, umbrellaHeaders, includePaths,
159+
frameworks, umbrellaHeaderSet, includePathSet, frameworkSet)) {
160+
return code;
161+
}
162+
}
163+
return std::error_code();
164+
}
165+
166+
if (dir.find("/MacOSX.platform/Developer/SDKs/") != std::string::npos &&
167+
dir.find("/usr/include/") != std::string::npos &&
168+
dir.find("/usr/include/objc") == std::string::npos) {
169+
return std::error_code();
170+
}
171+
150172
addIncludePath(dir, includePaths, includePathSet);
151173

152174
std::filesystem::path moduleMapPath = dir + "/module.modulemap";
@@ -165,6 +187,12 @@ static std::error_code CreateUmbrellaHeaderForAmbientModulesInner(
165187
if (entry.is_directory()) {
166188
// TODO: .xcframework
167189
if (pathstring.ends_with(".framework") && isFrameworksDir) {
190+
// These frameworks currently introduce parser-only failures that are
191+
// not required for app/runtime test metadata generation.
192+
if (pathstring.ends_with("/DriverKit.framework") ||
193+
pathstring.ends_with("/Ruby.framework")) {
194+
continue;
195+
}
168196
std::cerr << "Found framework: " << pathstring << std::endl;
169197
std::filesystem::path moduleMapPath =
170198
entry.path() / "Modules" / "module.modulemap";
@@ -300,14 +328,16 @@ static std::error_code CreateUmbrellaHeaderForAmbientModules(
300328
std::string moduleMapFile = arg.substr(18);
301329
std::filesystem::path moduleMapPath(moduleMapFile);
302330
if (std::filesystem::exists(moduleMapPath)) {
303-
std::cerr << "Found module map arg: " << moduleMapPath.string() << std::endl;
331+
std::cerr << "Found module map arg: " << moduleMapPath.string()
332+
<< std::endl;
304333
if (std::error_code code = CreateUmbrellaHeaderForAmbientModule(
305334
moduleMapPath.parent_path(), false, moduleMapPath,
306335
umbrellaHeaders, includePaths, frameworks, umbrellaHeaderSet,
307336
includePathSet, frameworkSet)) {
308337
return code;
309338
}
310-
std::cerr << "Added module map headers from: " << moduleMapPath.string() << std::endl;
339+
std::cerr << "Added module map headers from: " << moduleMapPath.string()
340+
<< std::endl;
311341
}
312342
}
313343
}

0 commit comments

Comments
 (0)