77#include " node_errors.h"
88#include " node_external_reference.h"
99#include " node_internals.h"
10+ #include " node_options.h"
1011#include " node_snapshot_builder.h"
1112#include " node_union_bytes.h"
1213#include " node_v8_platform-inl.h"
@@ -86,6 +87,11 @@ size_t SeaSerializer::Write(const SeaResource& sea) {
8687 uint32_t flags = static_cast <uint32_t >(sea.flags );
8788 Debug (" Write SEA flags %x\n " , flags);
8889 written_total += WriteArithmetic<uint32_t >(flags);
90+
91+ Debug (" Write SEA resource exec argv extension %u\n " ,
92+ static_cast <uint8_t >(sea.exec_argv_extension ));
93+ written_total +=
94+ WriteArithmetic<uint8_t >(static_cast <uint8_t >(sea.exec_argv_extension ));
8995 DCHECK_EQ (written_total, SeaResource::kHeaderSize );
9096
9197 Debug (" Write SEA code path %p, size=%zu\n " ,
@@ -158,6 +164,11 @@ SeaResource SeaDeserializer::Read() {
158164 CHECK_EQ (magic, kMagic );
159165 SeaFlags flags (static_cast <SeaFlags>(ReadArithmetic<uint32_t >()));
160166 Debug (" Read SEA flags %x\n " , static_cast <uint32_t >(flags));
167+
168+ uint8_t extension_value = ReadArithmetic<uint8_t >();
169+ SeaExecArgvExtension exec_argv_extension =
170+ static_cast <SeaExecArgvExtension>(extension_value);
171+ Debug (" Read SEA resource exec argv extension %u\n " , extension_value);
161172 CHECK_EQ (read_total, SeaResource::kHeaderSize );
162173
163174 std::string_view code_path =
@@ -212,7 +223,13 @@ SeaResource SeaDeserializer::Read() {
212223 exec_argv.emplace_back (arg);
213224 }
214225 }
215- return {flags, code_path, code, code_cache, assets, exec_argv};
226+ return {flags,
227+ exec_argv_extension,
228+ code_path,
229+ code,
230+ code_cache,
231+ assets,
232+ exec_argv};
216233}
217234
218235std::string_view FindSingleExecutableBlob () {
@@ -297,26 +314,55 @@ std::tuple<int, char**> FixupArgsForSEA(int argc, char** argv) {
297314 if (IsSingleExecutable ()) {
298315 static std::vector<char *> new_argv;
299316 static std::vector<std::string> exec_argv_storage;
317+ static std::vector<std::string> cli_extension_args;
300318
301319 SeaResource sea_resource = FindSingleExecutableResource ();
302320
303321 new_argv.clear ();
304322 exec_argv_storage.clear ();
323+ cli_extension_args.clear ();
324+
325+ // Handle CLI extension mode for --node-options
326+ if (sea_resource.exec_argv_extension == SeaExecArgvExtension::kCli ) {
327+ // Extract --node-options and filter argv
328+ for (int i = 1 ; i < argc; ++i) {
329+ if (strncmp (argv[i], " --node-options=" , 15 ) == 0 ) {
330+ std::string node_options = argv[i] + 15 ;
331+ std::vector<std::string> errors;
332+ cli_extension_args = ParseNodeOptionsEnvVar (node_options, &errors);
333+ // Remove this argument by shifting the rest
334+ for (int j = i; j < argc - 1 ; ++j) {
335+ argv[j] = argv[j + 1 ];
336+ }
337+ argc--;
338+ i--; // Adjust index since we removed an element
339+ }
340+ }
341+ }
305342
306- // Reserve space for argv[0], exec argv, original argv, and nullptr
307- new_argv.reserve (argc + sea_resource.exec_argv .size () + 2 );
343+ // Reserve space for argv[0], exec argv, cli extension args, original argv,
344+ // and nullptr
345+ new_argv.reserve (argc + sea_resource.exec_argv .size () +
346+ cli_extension_args.size () + 2 );
308347 new_argv.emplace_back (argv[0 ]);
309348
310349 // Insert exec argv from SEA config
311350 if (!sea_resource.exec_argv .empty ()) {
312- exec_argv_storage.reserve (sea_resource.exec_argv .size ());
351+ exec_argv_storage.reserve (sea_resource.exec_argv .size () +
352+ cli_extension_args.size ());
313353 for (const auto & arg : sea_resource.exec_argv ) {
314354 exec_argv_storage.emplace_back (arg);
315355 new_argv.emplace_back (exec_argv_storage.back ().data ());
316356 }
317357 }
318358
319- // Add actual run time arguments.
359+ // Insert CLI extension args
360+ for (const auto & arg : cli_extension_args) {
361+ exec_argv_storage.emplace_back (arg);
362+ new_argv.emplace_back (exec_argv_storage.back ().data ());
363+ }
364+
365+ // Add actual run time arguments
320366 new_argv.insert (new_argv.end (), argv, argv + argc);
321367 new_argv.emplace_back (nullptr );
322368 argc = new_argv.size () - 1 ;
@@ -332,6 +378,7 @@ struct SeaConfig {
332378 std::string main_path;
333379 std::string output_path;
334380 SeaFlags flags = SeaFlags::kDefault ;
381+ SeaExecArgvExtension exec_argv_extension = SeaExecArgvExtension::kEnv ;
335382 std::unordered_map<std::string, std::string> assets;
336383 std::vector<std::string> exec_argv;
337384};
@@ -475,6 +522,27 @@ std::optional<SeaConfig> ParseSingleExecutableConfig(
475522 result.flags |= SeaFlags::kIncludeExecArgv ;
476523 result.exec_argv = std::move (exec_argv);
477524 }
525+ } else if (key == " execArgvExtension" ) {
526+ std::string_view extension_str;
527+ if (field.value ().get_string ().get (extension_str)) {
528+ FPrintF (stderr,
529+ " \" execArgvExtension\" field of %s is not a string\n " ,
530+ config_path);
531+ return std::nullopt ;
532+ }
533+ if (extension_str == " none" ) {
534+ result.exec_argv_extension = SeaExecArgvExtension::kNone ;
535+ } else if (extension_str == " env" ) {
536+ result.exec_argv_extension = SeaExecArgvExtension::kEnv ;
537+ } else if (extension_str == " cli" ) {
538+ result.exec_argv_extension = SeaExecArgvExtension::kCli ;
539+ } else {
540+ FPrintF (stderr,
541+ " \" execArgvExtension\" field of %s must be one of "
542+ " \" none\" , \" env\" , or \" cli\"\n " ,
543+ config_path);
544+ return std::nullopt ;
545+ }
478546 }
479547 }
480548
@@ -675,6 +743,7 @@ ExitCode GenerateSingleExecutableBlob(
675743 }
676744 SeaResource sea{
677745 config.flags ,
746+ config.exec_argv_extension ,
678747 config.main_path ,
679748 builds_snapshot_from_main
680749 ? std::string_view{snapshot_blob.data (), snapshot_blob.size ()}
0 commit comments