@@ -33,15 +33,41 @@ using v8::Value;
33
33
namespace node {
34
34
namespace sea {
35
35
36
+ namespace {
36
37
// A special number that will appear at the beginning of the single executable
37
38
// preparation blobs ready to be injected into the binary. We use this to check
38
39
// that the data given to us are intended for building single executable
39
40
// applications.
40
- static const uint32_t kMagic = 0x143da20 ;
41
+ const uint32_t kMagic = 0x143da20 ;
41
42
42
- std::string_view FindSingleExecutableCode () {
43
+ enum class SeaFlags : uint32_t {
44
+ kDefault = 0 ,
45
+ kDisableExperimentalSeaWarning = 1 << 0 ,
46
+ };
47
+
48
+ SeaFlags operator |(SeaFlags x, SeaFlags y) {
49
+ return static_cast <SeaFlags>(static_cast <uint32_t >(x) |
50
+ static_cast <uint32_t >(y));
51
+ }
52
+
53
+ SeaFlags operator &(SeaFlags x, SeaFlags y) {
54
+ return static_cast <SeaFlags>(static_cast <uint32_t >(x) &
55
+ static_cast <uint32_t >(y));
56
+ }
57
+
58
+ SeaFlags operator |=(/* NOLINT (runtime/references) */ SeaFlags& x, SeaFlags y) {
59
+ return x = x | y;
60
+ }
61
+
62
+ struct SeaResource {
63
+ SeaFlags flags = SeaFlags::kDefault ;
64
+ std::string_view code;
65
+ static constexpr size_t kHeaderSize = sizeof (kMagic ) + sizeof (SeaFlags);
66
+ };
67
+
68
+ SeaResource FindSingleExecutableResource () {
43
69
CHECK (IsSingleExecutable ());
44
- static const std::string_view sea_code = []() -> std::string_view {
70
+ static const SeaResource sea_resource = []() -> SeaResource {
45
71
size_t size;
46
72
#ifdef __APPLE__
47
73
postject_options options;
@@ -55,18 +81,40 @@ std::string_view FindSingleExecutableCode() {
55
81
#endif
56
82
uint32_t first_word = reinterpret_cast <const uint32_t *>(code)[0 ];
57
83
CHECK_EQ (first_word, kMagic );
84
+ SeaFlags flags{
85
+ reinterpret_cast <const SeaFlags*>(code + sizeof (first_word))[0 ]};
58
86
// TODO(joyeecheung): do more checks here e.g. matching the versions.
59
- return {code + sizeof (first_word), size - sizeof (first_word)};
87
+ return {
88
+ flags,
89
+ {
90
+ code + SeaResource::kHeaderSize ,
91
+ size - SeaResource::kHeaderSize ,
92
+ },
93
+ };
60
94
}();
61
- return sea_code;
95
+ return sea_resource;
96
+ }
97
+
98
+ } // namespace
99
+
100
+ std::string_view FindSingleExecutableCode () {
101
+ SeaResource sea_resource = FindSingleExecutableResource ();
102
+ return sea_resource.code ;
62
103
}
63
104
64
105
bool IsSingleExecutable () {
65
106
return postject_has_resource ();
66
107
}
67
108
68
- void IsSingleExecutable (const FunctionCallbackInfo<Value>& args) {
69
- args.GetReturnValue ().Set (IsSingleExecutable ());
109
+ void IsExperimentalSeaWarningNeeded (const FunctionCallbackInfo<Value>& args) {
110
+ if (!IsSingleExecutable ()) {
111
+ args.GetReturnValue ().Set (false );
112
+ return ;
113
+ }
114
+
115
+ SeaResource sea_resource = FindSingleExecutableResource ();
116
+ args.GetReturnValue ().Set (!static_cast <bool >(
117
+ sea_resource.flags & SeaFlags::kDisableExperimentalSeaWarning ));
70
118
}
71
119
72
120
std::tuple<int , char **> FixupArgsForSEA (int argc, char ** argv) {
@@ -90,6 +138,7 @@ namespace {
90
138
struct SeaConfig {
91
139
std::string main_path;
92
140
std::string output_path;
141
+ SeaFlags flags = SeaFlags::kDefault ;
93
142
};
94
143
95
144
std::optional<SeaConfig> ParseSingleExecutableConfig (
@@ -112,7 +161,8 @@ std::optional<SeaConfig> ParseSingleExecutableConfig(
112
161
return std::nullopt;
113
162
}
114
163
115
- result.main_path = parser.GetTopLevelField (" main" ).value_or (std::string ());
164
+ result.main_path =
165
+ parser.GetTopLevelStringField (" main" ).value_or (std::string ());
116
166
if (result.main_path .empty ()) {
117
167
FPrintF (stderr,
118
168
" \" main\" field of %s is not a non-empty string\n " ,
@@ -121,14 +171,26 @@ std::optional<SeaConfig> ParseSingleExecutableConfig(
121
171
}
122
172
123
173
result.output_path =
124
- parser.GetTopLevelField (" output" ).value_or (std::string ());
174
+ parser.GetTopLevelStringField (" output" ).value_or (std::string ());
125
175
if (result.output_path .empty ()) {
126
176
FPrintF (stderr,
127
177
" \" output\" field of %s is not a non-empty string\n " ,
128
178
config_path);
129
179
return std::nullopt;
130
180
}
131
181
182
+ std::optional<bool > disable_experimental_sea_warning =
183
+ parser.GetTopLevelBoolField (" disableExperimentalSEAWarning" );
184
+ if (!disable_experimental_sea_warning.has_value ()) {
185
+ FPrintF (stderr,
186
+ " \" disableExperimentalSEAWarning\" field of %s is not a Boolean\n " ,
187
+ config_path);
188
+ return std::nullopt;
189
+ }
190
+ if (disable_experimental_sea_warning.value ()) {
191
+ result.flags |= SeaFlags::kDisableExperimentalSeaWarning ;
192
+ }
193
+
132
194
return result;
133
195
}
134
196
@@ -144,9 +206,11 @@ bool GenerateSingleExecutableBlob(const SeaConfig& config) {
144
206
145
207
std::vector<char > sink;
146
208
// TODO(joyeecheung): reuse the SnapshotSerializerDeserializer for this.
147
- sink.reserve (sizeof ( kMagic ) + main_script.size ());
209
+ sink.reserve (SeaResource:: kHeaderSize + main_script.size ());
148
210
const char * pos = reinterpret_cast <const char *>(&kMagic );
149
211
sink.insert (sink.end (), pos, pos + sizeof (kMagic ));
212
+ pos = reinterpret_cast <const char *>(&(config.flags ));
213
+ sink.insert (sink.end (), pos, pos + sizeof (SeaFlags));
150
214
sink.insert (
151
215
sink.end (), main_script.data (), main_script.data () + main_script.size ());
152
216
@@ -181,11 +245,14 @@ void Initialize(Local<Object> target,
181
245
Local<Value> unused,
182
246
Local<Context> context,
183
247
void * priv) {
184
- SetMethod (context, target, " isSea" , IsSingleExecutable);
248
+ SetMethod (context,
249
+ target,
250
+ " isExperimentalSeaWarningNeeded" ,
251
+ IsExperimentalSeaWarningNeeded);
185
252
}
186
253
187
254
void RegisterExternalReferences (ExternalReferenceRegistry* registry) {
188
- registry->Register (IsSingleExecutable );
255
+ registry->Register (IsExperimentalSeaWarningNeeded );
189
256
}
190
257
191
258
} // namespace sea
0 commit comments