Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@joyeecheung
Copy link
Member

@joyeecheung joyeecheung commented Dec 24, 2025

For reviewers: the bulk of the core changes are in the commit sea: add --build-sea to generate SEA directly with Node.js binary; The dependency updating tools and license updates are in deps: add tools and scripts to pull LIEF as a dependency. The rest are mostly refactoring and pulling LIEF using the script added in the previous commit.


Instead of relying on a WASM build of postject to perform the injection, add LIEF as dependency and generate the SEA directly from core via a new CLI option --build-sea which takes the SEA config. Thi simplifies SEA generation for users and makes it easier to debug/maintain the SEA building process.

For the time being, backward compatibility with the postject-based SEA building process will be maintained, until there's motivation to break it (e.g. for optimizations)

The new process is simplified to as follows - no more knowledge about the blob location in the binary needed:

$ echo 'console.log("Hello")' > hello.js
$ echo '{ "main": "hello.js", "output": "sea" }' > sea-config.json
$ node --build-sea sea-config.json
$ ./sea
Hello

This idea was discussed a while back (brought up by @marco-ippolito) at the collaboration summit to improve the UX of SEA building process, which currently requires users to use an external tool (i.e. postject) to perform the injection, and know about the layout of the target binary. For most users, the details are probably not very useful. Moving the injection process into core simplifies the process.

Bringing it into core may also make it easier to implement some of the ideas brought up back in 2022 that would require close coordination with core to implement (e.g. trimming ICU data post-build to reduce binary size).

I've been helping out with the SEA feature from time to time and as I see it, apart from UX improvement, I found the current WASM-based tool somewhat difficult to debug when I was trying to fix nodejs/postject#105. Also, the WASM build is significantly slower than a native build, which adds friction to the debugging process.

$ time out/Release/node test/sea/test-single-executable-application.js
Copied /Users/joyee/projects/node/out/Release/node to /Users/joyee/projects/node/test/.tmp.0/sea
Injected /Users/joyee/projects/node/test/.tmp.0/sea-prep.blob into /Users/joyee/projects/node/test/.tmp.0/sea
Signed /Users/joyee/projects/node/test/.tmp.0/sea

User time: 5.12s
System time: 0.38s
CPU time: 90%
Total time: 6.06s

$ time out/Release/node test/sea/test-build-sea.js
Signed /Users/joyee/projects/node/test/.tmp.0/sea

User time: 1.79s
System time: 0.34s
CPU time: 74%
Total time: 2.85s

At the summit @RaisinTen mentioned one concern about the potential binary size increase. With this POC the binary size is only increased by 5-6 MB on macOS/Linux, and ~3MB on Windows, which seems acceptable (as a reference, this is smaller than the decrease we recently got from compiling V8 with default hidden visibility #56290 (comment))

# Linux
$ ls -lah ./node_without_lief ./out/Release/node
-rwxr-xr-x 1 developer developer 122M Dec 24 16:50 ./node_without_lief
-rwxr-xr-x 1 developer developer 128M Dec 24 16:51 ./out/Release/node

# macOS
$ ls -lah ./node_without_lief ./out/Release/node
-rwxr-xr-x@ 1 joyee  staff   125M Dec 24 17:48 ./node_without_lief
-rwxr-xr-x@ 1 joyee  staff   130M Dec 24 17:48 ./out/Release/node

# Windows
$ ls -lah out\Release\node.exe .\node_main.exe
-rwxr-xr-x 1 joyee 197121 87M Jan  1 19:29 '.\node_main.exe'
-rwxr-xr-x 1 joyee 197121 90M Jan  1 19:42 'out\Release\node.exe'

In addition, I think the LIEF library may also be useful for other purposes e.g. demangling the names in the V8 prof profiles, which is a current bottleneck when trying to analyze logs via --prof-process by calling out to nm and c++filt.


Commits

test: use fixture directories for sea tests

Instead of copying and writing files on the fly for SEA tests,
put the fixtures into a directory and copy them into tmpdir
for testing. This allows easier reproduction and debugging
when they do fail - we can just copy the entire fixture directory
and test directly from there.

deps: add tools and scripts to pull LIEF as a dependency

deps: add LIEF as a dependency

sea: split sea binary manipulation code

Split the sea binary manipulation code to a seperate file so that
adding more low-level binary manipulation code doesn't clobber the
higher-level code.

sea: add --build-sea to generate SEA directly with Node.js binary

Instead of relying on a WASM build of postject to perform the
injection, add LIEF as dependency and generate the SEA directly
from core via a new CLI option --build-sea which takes the SEA
config. This simplifies SEA generation for users and makes it
easier to debug/maintain the SEA building process.

test: migrate to --build-sea in existing SEA tests

Only leave a smoking test for the postject-based workflow
in test-single-executable-application.js

@nodejs-github-bot
Copy link
Collaborator

Review requested:

  • @nodejs/security-wg
  • @nodejs/tsc

@nodejs-github-bot nodejs-github-bot added build Issues and PRs related to build files or the CI. dependencies Pull requests that update a dependency file. meta Issues and PRs related to the general management of the project. needs-ci PRs that need a full CI run. labels Dec 24, 2025
@joyeecheung joyeecheung changed the title [WIP] sea: add --build-sea to generate SEA directly with Node.js binary [WIP] sea: add --build-sea to generate single executable directly with Node.js binary Dec 24, 2025
@joyeecheung joyeecheung changed the title [WIP] sea: add --build-sea to generate single executable directly with Node.js binary [WIP] sea: generate single executable directly with Node.js binary Dec 24, 2025
@joyeecheung joyeecheung force-pushed the build-sea branch 5 times, most recently from 1c95882 to 47c1149 Compare January 1, 2026 23:08
@joyeecheung joyeecheung changed the title [WIP] sea: generate single executable directly with Node.js binary sea: generate single executable directly with Node.js binary Jan 2, 2026
@nodejs-github-bot

This comment was marked as outdated.

Instead of copying and writing files on the fly for SEA tests,
put the fixtures into a directory and copy them into tmpdir
for testing. This allows easier reproduction and debugging
when they do fail - we can just copy the entire fixture directory
and test directly from there.
@nodejs-github-bot

This comment was marked as outdated.

Split the sea binary manipulation code to a seperate file so that
adding more low-level binary manipulation code doesn't clobber the
higher-level code.
@nodejs-github-bot
Copy link
Collaborator

Instead of relying on a WASM build of postject to perform the
injection, add LIEF as dependency and generate the SEA directly
from core via a new CLI option --build-sea which takes the SEA
config. This simplifies SEA generation for users and makes it
easier to debug/maintain the SEA building process.
Only leave a smoking test for the postject-based workflow
in test-single-executable-application.js
@joyeecheung joyeecheung marked this pull request as ready for review January 4, 2026 08:30
@joyeecheung
Copy link
Member Author

joyeecheung commented Jan 4, 2026

I think this is ready for review now. An explanation about the commits:

  • test: use fixture directories for sea tests: stop writing fixtures on-the-fly in the existing SEA tests, move the fixtures into directories checked into source, so they are easier to debug/migrate
  • deps: add tools and scripts to pull LIEF as a dependency: adds the updater and script to trim LIEF and shim the CMake configuration process
  • deps: add LIEF as a dependency: pull a copy of LIEF into deps using the previous scripts (where the majority of the diff comes from)
  • sea: split sea binary manipulation code: refactoring for the upcoming change
  • sea: add --build-sea to generate SEA directly with Node.js binary: the bulk of the actual change in this PR, most new code is in src/node_sea_bin.cc and deps/LIEF/lief.gyp, as well as the tests and docs change. The C++ part is heavily based on postject.cpp and postject JS API with fixups for the Node.js internal style and migration to the new LIEF API (the version of LIEF added here is a lot newer than what postject has, since postject hasn't been updated for 3 years)
  • test: migrate to --build-sea in existing SEA tests: migrate most existing SEA tests which used postject to using --build-sea instead. Only test-single-executable-application.js keeps the postject-based build process to test that it continues to work (until we need to break it, if ever)

cc @nodejs/tsc since this updates the LICENSE (LIEF was already in LICENSE, but only as part of test/fixtures/postject-copy which only contained the WASM build artifact of LIEF 0.13.0; I added a new copy into LICENSE in case the source LICENSE in the newer deps/LIEF starts to diverge, also it's now in the Node.js binary, not just a WASM build in the test fixture)
Also @nodejs/single-executable @nodejs/cpp-reviewers @nodejs/startup for reviews

@joyeecheung joyeecheung added the review wanted PRs that need reviews. label Jan 4, 2026
@bnb
Copy link
Contributor

bnb commented Jan 4, 2026

+1 to this, really lovely DX improvement for the average SEA user and will make SEA an even easier choice for building standalone CLIs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

build Issues and PRs related to build files or the CI. dependencies Pull requests that update a dependency file. meta Issues and PRs related to the general management of the project. needs-ci PRs that need a full CI run. review wanted PRs that need reviews.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

postject corrupts the .gnu.hash section of the binary in a Linux arm64 docker container

3 participants