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) {

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);

90969197

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);

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

}

217234218235

std::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;

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

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

}

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()}