sea: implement execArgvExtension · nodejs/node@352d635
@@ -7,6 +7,7 @@
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) {
8687uint32_t flags = static_cast<uint32_t>(sea.flags);
8788Debug("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));
8995DCHECK_EQ(written_total, SeaResource::kHeaderSize);
90969197Debug("Write SEA code path %p, size=%zu\n",
@@ -158,6 +164,11 @@ SeaResource SeaDeserializer::Read() {
158164CHECK_EQ(magic, kMagic);
159165 SeaFlags flags(static_cast<SeaFlags>(ReadArithmetic<uint32_t>()));
160166Debug("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);
161172CHECK_EQ(read_total, SeaResource::kHeaderSize);
162173163174 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}
217234218235std::string_view FindSingleExecutableBlob() {
@@ -297,26 +314,55 @@ std::tuple<int, char**> FixupArgsForSEA(int argc, char** argv) {
297314if (IsSingleExecutable()) {
298315static std::vector<char*> new_argv;
299316static std::vector<std::string> exec_argv_storage;
317+static std::vector<std::string> cli_extension_args;
300318301319 SeaResource sea_resource = FindSingleExecutableResource();
302320303321 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+ }
305342306-// 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]);
309348310349// Insert exec argv from SEA config
311350if (!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());
313353for (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 }
318358319-// 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@@ -674,6 +742,7 @@ ExitCode GenerateSingleExecutableBlob(
674742 }
675743 SeaResource sea{
676744 config.flags,
745+ config.exec_argv_extension,
677746 config.main_path,
678747 builds_snapshot_from_main
679748 ? std::string_view{snapshot_blob.data(), snapshot_blob.size()}