emscripten
emscripten copied to clipboard
Optimization -O1, -O2, ... get rid of the environment variables handling in file.js
Basically, the code related to the environment variables handling
var ENV = {
};
var getExecutableName = () => {
return thisProgram || './this.program';
};
var getEnvStrings = () => {
if (!getEnvStrings.strings) {
// Default values.
// Browser language detection #8751
var lang = ((typeof navigator == 'object' && navigator.languages && navigator.languages[0]) || 'C').replace('-', '_') + '.UTF-8';
var env = {
'USER': 'web_user',
'LOGNAME': 'web_user',
'PATH': '/',
'PWD': '/',
'HOME': '/home/web_user',
'LANG': lang,
'_': getExecutableName()
};
// Apply the user-provided values, if any.
for (var x in ENV) {
// x is a key in ENV; if ENV[x] is undefined, that means it was
// explicitly set to be so. We allow user code to do that to
// force variables with default values to remain unset.
if (ENV[x] === undefined) delete env[x];
else env[x] = ENV[x];
}
var strings = [];
for (var x in env) {
strings.push(`${x}=${env[x]}`);
}
getEnvStrings.strings = strings;
}
return getEnvStrings.strings;
};
It is removed when compiling with optimizations. Setting up a --pre-js extending the environment leads to an error of ENV not declared.
Version of emscripten/emsdk: emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 3.1.46 (19607820c447a13fd8d0b7680c56148427d6e1b8) clang version 18.0.0 (https://github.com/llvm/llvm-project 75501f53624de92aafce2f1da698b249a7293dc7) Target: wasm32-unknown-emscripten Thread model: posix
getEnvStrings, getExecutableName and ENV are all JS library symbols are that only included if they are needed by program being built.
The only symbol that currently depends on those ones is environ_get: https://github.com/emscripten-core/emscripten/blob/efc13c67456271592b52e3d538d42d46584b31ee/src/library_wasi.js#L99
My guess is that when optimizations are run the program no longer depends on the wasi_snapshot_preview1.environ_get symbol and so emscripten is treating them as dead code
Are you sure your program depend on the environment (e.g. does it call getenv)?
If you want to force the inclusion of a library symbol such as ENV you can use -sDEFAULT_LIBRARY_FUNCS_TO_INCLUDE=$ENV (remember to escape the dollar sign if you are typing that in a shell). But doing this is probably not what you want if the program itself is not reading from ENV.
I'm using the --pre-js to set some envvars and the application is correctly getting and using it when compiled without optimization, but on -OX, the code similar to this, doesn't work, and I get the undefined ENV error.
Module.preRun = []
Module.preRun.push(function() {ENV.GST_DEBUG='*:3'});
I understand that emscripten thinks that env related code is actually dead code, but can't see why if the application is always using getenv(). I'll check the FUNCS_TO_INCLUDE thing. Thanks
Yes, that looks like exactly that kind place where you want to use -sDEFAULT_LIBRARY_FUNCS_TO_INCLUDE=$ENV.
However, if ENV is otherwise unused that means it not needed by your program and so it not being read. i.e. if ENV is being removed that by definition the program must not be calling getenv (or any other function that reads the environment). Does that sounds right? Are you expecting this program to check its environment?
Just an update if that may help others, as this issue is the most up-to-date for this search: https://github.com/search?q=org%3Aemscripten-core+%22environment+variable%22+%22prerun%22&type=issues
To solve this issue on my side I had to use -sEXPORTED_RUNTIME_METHODS=['ENV'] instead of -sDEFAULT_LIBRARY_FUNCS_TO_INCLUDE=$ENV (with emsdk 4.0.3)
As in https://github.com/Kitware/VTK/blob/v9.4.2/Examples/Emscripten/Cxx/ConeMultiBackend/CMakeLists.txt#L49
"-sEXPORTED_RUNTIME_METHODS=['ENV']" # ENV holds the environment variables accessible by C getenv
Both -sEXPORTED_RUNTIME_METHODS=ENV and -sDEFAULT_LIBRARY_FUNCS_TO_INCLUDE=$ENV should work if you want to use ENV from within the program.
The difference with -sEXPORTED_RUNTIME_METHODS=ENV is that it exports ENV to the outside, which means it will never be removed by DCE at -O2 or -O3.
Where are you trying to use ENV from @anscfrisson ?
(note that you don't need the square brackets or quotes around there days).
Where are you trying to use
ENVfrom @anscfrisson ?
The closest example that I can share is by Kitware (@jspanchu) in VTK: https://github.com/Kitware/VTK/blob/v9.4.2/Examples/Emscripten/Cxx/ConeMultiBackend/CMakeLists.txt#L49
So that module.ENV.VTK_GRAPHICS_BACKEND = 'WEBGPU'; can be updated at runtime:
https://github.com/Kitware/VTK/blob/v9.4.2/Examples/Emscripten/Cxx/ConeMultiBackend/web/webgpu.js#L18
Both
-sEXPORTED_RUNTIME_METHODS=ENVand-sDEFAULT_LIBRARY_FUNCS_TO_INCLUDE=$ENVshould work if you want to useENVfrom within the program.The difference with
-sEXPORTED_RUNTIME_METHODS=ENVis that it exportsENVto the outside, which means it will never be removed by DCE at-O2or-O3.
Thanks for the explanation, we precisely need -sEXPORTED_RUNTIME_METHODS=ENV to remain available in all build flavors (Debug and Release).
(note that you don't need the square brackets or quotes around there days).
Thanks again for all of your explanations @sbc100!