|
| 1 | +# Maintaining Single Executable Applications support |
| 2 | + |
| 3 | +Support for [single executable applications](https://github.com/nodejs/node/blob/master/doc/contributing/technical-priorities.md#single-executable-applications) |
| 4 | +is on of the key technical priorities identified for the success of Node.js. |
| 5 | + |
| 6 | +## High level strategy |
| 7 | + |
| 8 | +From the [next-10 discussions](https://github.com/nodejs/next-10/blob/main/meetings/summit-nov-2021.md#single-executable-applications) |
| 9 | +there are 2 approaches the projects believes are important to support: |
| 10 | + |
| 11 | +* Compile with node into executable (boxnode approach) |
| 12 | +* Bundled onto exising Node.js exe (pkg approach) |
| 13 | + |
| 14 | +### Compile with node into executable |
| 15 | + |
| 16 | +No specific code within the Node.js project is needed to support the |
| 17 | +option of compiling a bundled application along with Node.js into a single |
| 18 | +executable application. |
| 19 | + |
| 20 | +### Bundled onto Existing Node.js |
| 21 | + |
| 22 | +The project does not plan to provide the complete solution but instead the key |
| 23 | +elements which are required in the Node.js executable in order to enabling |
| 24 | +bundling with the shipping Node.js binaries. This includes: |
| 25 | + |
| 26 | +* Looking for a segment within the executable that holds bundled code. |
| 27 | +* Running the bundled code when such a segement is found. |
| 28 | + |
| 29 | +It is left up to external tools/solutions to: |
| 30 | + |
| 31 | +* Bundled code into a single script that can be executed with -e on |
| 32 | + the command line. |
| 33 | +* Generating a command line with appropriate options, including -e to |
| 34 | + run the bundle script. |
| 35 | +* adding a segment to the existing Node.js executable which contains |
| 36 | + the command line and appropriate headers. |
| 37 | +* re-generating or removing signatures on the resulting executable |
| 38 | +* providing a virtual file system, and hooking it in if needed to |
| 39 | + support native modules or reading file contents. |
| 40 | + |
| 41 | +## Maintaining |
| 42 | + |
| 43 | +### Compile with node into executable |
| 44 | + |
| 45 | +There are not special consideration needed. |
| 46 | + |
| 47 | +### Bundled onto Existing Node.js |
| 48 | + |
| 49 | +The following header must be included in a segment in order to have it run |
| 50 | +as a single executable application: |
| 51 | + |
| 52 | +JSCODEVVVVVVVVFFFFFFFFF |
| 53 | + |
| 54 | +where: |
| 55 | + |
| 56 | +* VVVVVVVV string representing the version to be used to interpret the section, |
| 57 | + for example `00000001`. |
| 58 | +* FFFFFFFF string representing the flags to be used in the process of starting |
| 59 | + the bundled application. Currently this must be `00000000` to indicate that |
| 60 | + no flags are set. |
| 61 | + |
| 62 | +The characters in both `VVVVVVVV` and `FFFFFFFF` are restricted to being |
| 63 | +between the characters "0" and "F" such that they can each be converted to |
| 64 | +a 32 bit integer. |
| 65 | + |
| 66 | +The string following the header is treated as a set of command line options |
| 67 | +that are used as a prefix to any additional command line options passed when |
| 68 | +the executable was started. For example, for a simple single hello world |
| 69 | +for version `00000001`could be: |
| 70 | + |
| 71 | +```text |
| 72 | +JSCODE0000000100000000-e \"console.log('Hello from single binary');\" |
| 73 | +``` |
| 74 | + |
| 75 | +Support for bundling onto existing Node.js binaries is maintained |
| 76 | +in `src/node_single_binary.*`. |
| 77 | + |
| 78 | +Currently only POSIX compliant platform are suppported. The goal |
| 79 | +is to expand this to include Windows and MacOS as well. |
| 80 | + |
| 81 | +If a breaking change is required to the content after the header, the version |
| 82 | +`VVVVVVVV` should be incremented. Support for a new format |
| 83 | +may be introduced as a SemVer minor provided that older versions |
| 84 | +are still supported. Removing support for a version is SemVer major. |
| 85 | + |
| 86 | +The `FFFFFFFF` are a set of flags that are used to control the |
| 87 | +process of starting the application. For example they might indicate |
| 88 | +that some set of arguments should be suppressed on the command line. |
| 89 | +Currently no flags are in use. |
| 90 | + |
| 91 | +For test purposes \[LIFE}(<https://github.com/lief-project/LIEF>) can |
| 92 | +be used to add a section in the required format. The following is a |
| 93 | +simple example for doing so on Linux. It can be improved as it |
| 94 | +currently replaces an existing section instead of adding a new |
| 95 | +one: |
| 96 | + |
| 97 | +```text |
| 98 | +#!/usr/bin/env python |
| 99 | +import lief |
| 100 | +binary = lief.parse('node') |
| 101 | +
|
| 102 | +segment = lief.ELF.Segment() |
| 103 | +segment.type = lief.ELF.SEGMENT_TYPES.LOAD |
| 104 | +segment.flags = lief.ELF.SEGMENT_FLAGS.R |
| 105 | +stringContent = "JSCODE0000000100000000-e \"console.log('Hello from single binary');\"" |
| 106 | +segment.content = bytearray(stringContent.encode()) |
| 107 | +segment = binary.replace(segment, binary[lief.ELF.SEGMENT_TYPES.NOTE]) |
| 108 | +
|
| 109 | +binary.write("hello") |
| 110 | +``` |
0 commit comments