Skip to content

Commit 4bd88b2

Browse files
authored
Add NODE_HOST_ENV to mirror host env vars under node (#18820)
This setting is enabled by default when `NODERAWFS` is enabled, but can also be disabled explicitly. Fixes: #18816, #25791
1 parent 8dfea2f commit 4bd88b2

File tree

8 files changed

+102
-3
lines changed

8 files changed

+102
-3
lines changed

ChangeLog.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ See docs/process.md for more on how version tagging works.
2626
use case. (#25645, #25440)
2727
- The fetch library now supports streaming data requests when
2828
`-sFETCH_STREAMING` is enabled.
29+
- A new `NODE_HOST_ENV` setting was added which exposes the host environment
30+
variables to the generated program, when running under Node. This setting is
31+
enabled by default when `-sNODERAWFS` is used but can also be controlled
32+
separately. (#18820)
2933

3034
4.0.20 - 11/18/25
3135
-----------------

site/source/docs/tools_reference/settings_reference.rst

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1494,7 +1494,7 @@ Default value: false
14941494
NODERAWFS
14951495
=========
14961496

1497-
Enables support for the NODERAWFS filesystem backend. This is a special
1497+
Enables support for the ``NODERAWFS`` filesystem backend. This is a special
14981498
backend as it replaces all normal filesystem access with direct Node.js
14991499
operations, without the need to do ``FS.mount()``, and this backend only
15001500
works with Node.js. The initial working directory will be same as
@@ -1504,6 +1504,20 @@ necessarily be portable between OSes - it will be as portable as a Node.js
15041504
program would be, which means that differences in how the underlying OS
15051505
handles permissions and errors and so forth may be noticeable.
15061506

1507+
Enabling this setting will also enable :ref:`NODE_HOST_ENV` by default.
1508+
1509+
Default value: false
1510+
1511+
.. _node_host_env:
1512+
1513+
NODE_HOST_ENV
1514+
=============
1515+
1516+
When running under Node, expose the underlying OS environment variables.
1517+
This is similar to how ``NODERAWFS`` exposes the underlying FS.
1518+
This setting gets enabled by default when ``NODERAWFS`` is enabled, but can
1519+
also be controlled separately.
1520+
15071521
Default value: false
15081522

15091523
.. _node_code_caching:

src/lib/libwasi.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,12 @@ var WasiLibrary = {
6767
'_': getExecutableName()
6868
#endif
6969
};
70+
#if ENVIRONMENT_MAY_BE_NODE && NODE_HOST_ENV
71+
if (ENVIRONMENT_IS_NODE) {
72+
// When NODE_HOST_ENV is enabled we mirror then entire host environment.
73+
env = process.env;
74+
}
75+
#endif
7076
// Apply the user-provided values, if any.
7177
for (var x in ENV) {
7278
// x is a key in ENV; if ENV[x] is undefined, that means it was

src/settings.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1023,7 +1023,7 @@ var FILESYSTEM = true;
10231023
// [link]
10241024
var FORCE_FILESYSTEM = false;
10251025

1026-
// Enables support for the NODERAWFS filesystem backend. This is a special
1026+
// Enables support for the ``NODERAWFS`` filesystem backend. This is a special
10271027
// backend as it replaces all normal filesystem access with direct Node.js
10281028
// operations, without the need to do ``FS.mount()``, and this backend only
10291029
// works with Node.js. The initial working directory will be same as
@@ -1032,9 +1032,17 @@ var FORCE_FILESYSTEM = false;
10321032
// necessarily be portable between OSes - it will be as portable as a Node.js
10331033
// program would be, which means that differences in how the underlying OS
10341034
// handles permissions and errors and so forth may be noticeable.
1035+
//
1036+
// Enabling this setting will also enable :ref:`NODE_HOST_ENV` by default.
10351037
// [link]
10361038
var NODERAWFS = false;
10371039

1040+
// When running under Node, expose the underlying OS environment variables.
1041+
// This is similar to how ``NODERAWFS`` exposes the underlying FS.
1042+
// This setting gets enabled by default when ``NODERAWFS`` is enabled, but can
1043+
// also be controlled separately.
1044+
var NODE_HOST_ENV = false;
1045+
10381046
// This saves the compiled wasm module in a file with name
10391047
// ``$WASM_BINARY_NAME.$V8_VERSION.cached``
10401048
// and loads it on subsequent runs. This caches the compiled wasm code from
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#include <cassert>
2+
#include <filesystem>
3+
#include <fstream>
4+
#include <iostream>
5+
6+
namespace fs = std::filesystem;
7+
8+
int main() {
9+
// libc++'s temp_directory_path depends on one of these env vars
10+
// being set, and falls back to /tmp as a default.
11+
// Log these values in case this test ever fails:
12+
const char* env_paths[] = {"TMPDIR", "TMP", "TEMP", "TEMPDIR"};
13+
for (int i = 0; i < sizeof(env_paths)/sizeof(char*); i++) {
14+
const char* p = getenv(env_paths[i]);
15+
std::cout << env_paths[i] << " -> " << (p ? p : "(NULL)") << "\n";
16+
if (p) {
17+
std::cout << env_paths[i] << " exists: " << fs::exists(env_paths[i]) << "\n";
18+
}
19+
}
20+
std::cout << "default /tmp exists: " << fs::exists("/tmp") << "\n";
21+
22+
fs::path tmp{fs::temp_directory_path()};
23+
std::cout << "temp_directory_path: " << tmp << "\n";
24+
assert(fs::exists(tmp));
25+
std::cout << "exists ok!" << "\n";
26+
return 0;
27+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
exists ok!

test/test_other.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7840,6 +7840,24 @@ def test_override_js_execution_environment(self):
78407840
seen = self.run_js('test.js', engine=engine, assert_returncode=NON_ZERO)
78417841
self.assertContained('Module.ENVIRONMENT has been deprecated. To force the environment, use the ENVIRONMENT compile-time option (for example, -sENVIRONMENT=web or -sENVIRONMENT=node', seen)
78427842

7843+
@requires_node
7844+
@with_env_modify({'FOO': 'bar'})
7845+
@parameterized({
7846+
'': ([], '|(null)|\n'),
7847+
'rawfs': (['-sNODERAWFS'], '|bar|\n'),
7848+
'rawfs_no_env': (['-sNODERAWFS', '-sNODE_HOST_ENV=0'], '|(null)|\n'),
7849+
'enabled': (['-sNODE_HOST_ENV'], '|bar|\n'),
7850+
})
7851+
def test_node_host_env(self, args, expected):
7852+
create_file('src.c', r'''
7853+
#include <stdlib.h>
7854+
#include <stdio.h>
7855+
int main() {
7856+
printf("|%s|\n", getenv("FOO"));
7857+
}
7858+
''')
7859+
self.do_runf('src.c', expected, cflags=args)
7860+
78437861
def test_override_c_environ(self):
78447862
create_file('pre.js', r'''
78457863
Module.preRun = () => { ENV.hello = '💩 world'; ENV.LANG = undefined; }
@@ -13644,12 +13662,20 @@ def test_fs_icase(self):
1364413662
# c++20 for ends_with().
1364513663
self.do_other_test('test_fs_icase.cpp', cflags=['-sCASE_INSENSITIVE_FS', '-std=c++20'])
1364613664

13665+
@crossplatform
1364713666
@with_all_fs
1364813667
def test_std_filesystem(self):
1364913668
if (WINDOWS or MACOS) and self.get_setting('NODERAWFS'):
1365013669
self.skipTest('Rawfs directory removal works only on Linux')
1365113670
self.do_other_test('test_std_filesystem.cpp')
1365213671

13672+
@crossplatform
13673+
@with_all_fs
13674+
def test_std_filesystem_tempdir(self):
13675+
if (WINDOWS or MACOS) and self.get_setting('NODERAWFS') and self.get_setting('WASMFS'):
13676+
self.skipTest('NODERAWFS + WASMFS is does not allow access to arbitrary paths')
13677+
self.do_other_test('test_std_filesystem_tempdir.cpp', cflags=['-g'])
13678+
1365313679
def test_strict_js_closure(self):
1365413680
self.do_runf('hello_world.c', cflags=['-sSTRICT_JS', '-Werror=closure', '--closure=1', '-O3'])
1365513681

tools/link.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1405,7 +1405,6 @@ def limit_incoming_module_api():
14051405
# see https://github.com/emscripten-core/emscripten/issues/18723#issuecomment-1429236996
14061406
if settings.MODULARIZE:
14071407
default_setting('NODEJS_CATCH_REJECTION', 0)
1408-
default_setting('NODEJS_CATCH_EXIT', 0)
14091408

14101409
if settings.POLYFILL:
14111410
# Emscripten requires certain ES6+ constructs by default in library code
@@ -1884,6 +1883,20 @@ def get_full_import_name(name):
18841883
if settings.PTHREADS:
18851884
settings.REQUIRED_EXPORTS.append('_emscripten_tls_init')
18861885

1886+
if settings.NODERAWFS:
1887+
default_setting('NODE_HOST_ENV', 1)
1888+
1889+
if not settings.ENVIRONMENT_MAY_BE_NODE:
1890+
# Node-specific settings only make sense if ENVIRONMENT_MAY_BE_NODE
1891+
if settings.NODERAWFS:
1892+
diagnostics.warning('unused-command-line-argument', 'NODERAWFS ignored since `node` not in `ENVIRONMENT`')
1893+
if settings.NODE_CODE_CACHING:
1894+
diagnostics.warning('unused-command-line-argument', 'NODE_CODE_CACHING ignored since `node` not in `ENVIRONMENT`')
1895+
if settings.NODEJS_CATCH_EXIT:
1896+
diagnostics.warning('unused-command-line-argument', 'NODEJS_CATCH_EXIT ignored since `node` not in `ENVIRONMENT`')
1897+
if settings.NODEJS_CATCH_REJECTION and 'NODEJS_CATCH_REJECTION' in user_settings:
1898+
diagnostics.warning('unused-command-line-argument', 'NODEJS_CATCH_REJECTION ignored since `node` not in `ENVIRONMENT`')
1899+
18871900
settings.PRE_JS_FILES = options.pre_js
18881901
settings.POST_JS_FILES = options.post_js
18891902

0 commit comments

Comments
 (0)