Skip to content

Commit 9f3441b

Browse files
committed
Add Module['scriptDirectory'] to fix loading files that should be relative to main .js file on Node.js.
1 parent b2c9a15 commit 9f3441b

File tree

9 files changed

+78
-0
lines changed

9 files changed

+78
-0
lines changed

emcc.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2713,6 +2713,8 @@ def generate_html(target, options, js_target, target_basename,
27132713
} else if (Module['memoryInitializerPrefixURL']) {
27142714
memoryInitializer = Module['memoryInitializerPrefixURL'] + memoryInitializer;
27152715
}
2716+
// If URL to memory initializer is relative, treat it relative with respect to Module['scriptDirectory'], if that is present.
2717+
if (Module['scriptDirectory'] && !/^(?:[a-z]+:)?[\/\\\\]\/?/i.test(memoryInitializer)) memoryInitializer = Module['scriptDirectory'] + memoryInitializer;
27162718
Module['memoryInitializerRequestURL'] = memoryInitializer;
27172719
var meminitXHR = Module['memoryInitializerRequest'] = new XMLHttpRequest();
27182720
meminitXHR.open('GET', memoryInitializer, true);

src/Fetch.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ var Fetch = {
115115
// of these are passed, then the default URL 'pthread-main.js' relative to the main html file is loaded.
116116
if (typeof Module['locateFile'] === 'function') fetchJs = Module['locateFile'](fetchJs);
117117
else if (Module['pthreadMainPrefixURL']) fetchJs = Module['pthreadMainPrefixURL'] + fetchJs;
118+
fetchJs = joinUrl(Module['scriptDirectory'], fetchJs);
118119
Fetch.worker = new Worker(fetchJs);
119120
Fetch.worker.onmessage = function(e) {
120121
out('fetch-worker sent a message: ' + e.filename + ':' + e.lineno + ': ' + e.message);

src/library_debugger_toolkit.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,7 @@ var CyberDWARFHeapPrinter = function(cdFileLocation) {
451451
} else if (Module['cdInitializerPrefixURL']) {
452452
cdFileLocation = Module['cdInitializerPrefixURL'] + cdFileLocation;
453453
}
454+
cdFileLocation = joinUrl(Module['scriptDirectory'], cdFileLocation);
454455
if (ENVIRONMENT_IS_NODE || ENVIRONMENT_IS_SHELL) {
455456
var data = Module['read'](cdFileLocation);
456457
install_cyberdwarf(data);

src/library_pthread.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,7 @@ var LibraryPThread = {
260260
else if (Module['pthreadMainPrefixURL']) pthreadMainJs = Module['pthreadMainPrefixURL'] + pthreadMainJs;
261261

262262
for (var i = 0; i < numWorkers; ++i) {
263+
pthreadMainJs = joinUrl(Module['scriptDirectory'], pthreadMainJs);
263264
var worker = new Worker(pthreadMainJs);
264265

265266
(function(worker) {

src/postamble.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,9 @@ if (memoryInitializer) {
4545
} else if (Module['memoryInitializerPrefixURL']) {
4646
memoryInitializer = Module['memoryInitializerPrefixURL'] + memoryInitializer;
4747
}
48+
memoryInitializer = joinUrl(Module['scriptDirectory'], memoryInitializer);
4849
}
50+
4951
if (ENVIRONMENT_IS_NODE || ENVIRONMENT_IS_SHELL) {
5052
var data = Module['readBinary'](memoryInitializer);
5153
HEAPU8.set(data, GLOBAL_BASE);

src/preamble.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -844,6 +844,18 @@ function stackTrace() {
844844
return demangleAll(js);
845845
}
846846

847+
function isAbsolutePath(path) {
848+
return isDataURI(path) || /^(?:[a-z]+:)?[\/\\]\/?/i.test(path);
849+
}
850+
851+
// Joins relative URL 'b' to URL 'a'. 'a' may be empty, in which case 'b' is returned.
852+
// If 'b' is an absolute URL, then 'a' is ignored and 'b' is returned as-is as well.
853+
function joinUrl(a, b) {
854+
#if ASSERTIONS
855+
if (a && !a.endsWith('/')) throw 'First parameter to joinUrl() should end in /!';
856+
#endif
857+
return (a && !isAbsolutePath(b)) ? a + b : b;
858+
}
847859
// Memory management
848860

849861
var PAGE_SIZE = 16384;
@@ -2031,6 +2043,9 @@ function integrateWasmJS() {
20312043
asmjsCodeFile = Module['locateFile'](asmjsCodeFile);
20322044
}
20332045
}
2046+
wasmTextFile = joinUrl(Module['scriptDirectory'], wasmTextFile);
2047+
wasmBinaryFile = joinUrl(Module['scriptDirectory'], wasmBinaryFile);
2048+
asmjsCodeFile = joinUrl(Module['scriptDirectory'], asmjsCodeFile);
20342049

20352050
// utilities
20362051

src/shell.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ if (ENVIRONMENT_IS_NODE) {
9494

9595
// Expose functionality in the same simple way that the shells work
9696
// Note that we pollute the global namespace here, otherwise we break in node
97+
if (!Module['scriptDirectory']) Module['scriptDirectory'] = __dirname + '/';
98+
9799
var nodeFS;
98100
var nodePath;
99101

tests/test_other.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8539,3 +8539,56 @@ def test_html_preprocess(self):
85398539
T4:NO_EXIT_RUNTIME > 1
85408540
T5:NO_EXIT_RUNTIME
85418541
T6:(else) !NO_EXIT_RUNTIME""", output)
8542+
8543+
# Tests that Emscripten-compiled applications can be run from a relative path with node command line that is different than the current working directory.
8544+
def test_node_js_run_from_different_directory(self):
8545+
args = ['-O3', '-s', 'WASM=1', '--memory-init-file', '1', '-s', 'BINARYEN_METHOD="asmjs,native-wasm"']
8546+
# Test that .mem.js is loaded up properly even if running the build output from a separate directory.
8547+
os.mkdir('subdir')
8548+
Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world.c'), '-o', os.path.join('subdir', 'a.js')] + args).communicate()
8549+
ret = Popen(NODE_JS + [os.path.join('subdir', 'a.js')], stdout=PIPE).communicate()[0]
8550+
try_delete('subdir')
8551+
assert 'hello, world!' in ret
8552+
8553+
# Test that the build is loaded properly when Module.locateFile is being used, where Module.locateFile() specifies an absolute path already.
8554+
os.mkdir('subdir')
8555+
open(os.path.join('subdir', 'pre.js'), 'w').write('''
8556+
var Module = {};
8557+
Module.memoryInitializerPrefixURL = 'this_should_be_getting_ignored_since_locateFile_is_specified/';
8558+
Module.locateFile = function(f) { return __dirname + '/' + f; }
8559+
''')
8560+
8561+
Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world.c'), '-o', os.path.join('subdir', 'a.js'), '--pre-js', os.path.join('subdir', 'pre.js')] + args).communicate()
8562+
ret = Popen(NODE_JS + [os.path.join('subdir', 'a.js')], stdout=PIPE).communicate()[0]
8563+
try_delete('subdir')
8564+
assert 'hello, world!' in ret
8565+
8566+
# Test that the build is loaded properly when Module.locateFile is being used, and it returns a relative path.
8567+
os.mkdir('subdir')
8568+
open(os.path.join('subdir', 'pre.js'), 'w').write('''
8569+
var Module = {};
8570+
Module.memoryInitializerPrefixURL = 'this_should_be_getting_ignored_since_locateFile_is_specified/';
8571+
Module.locateFile = function(f) { return 'data/' + f; }
8572+
''')
8573+
8574+
Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world.c'), '-o', os.path.join('subdir', 'a.js'), '--pre-js', os.path.join('subdir', 'pre.js')] + args).communicate()
8575+
os.mkdir(os.path.join('subdir', 'data'))
8576+
os.rename(os.path.join('subdir', 'a.js.mem'), os.path.join('subdir', 'data', 'a.js.mem'))
8577+
os.rename(os.path.join('subdir', 'a.asm.js'), os.path.join('subdir', 'data', 'a.asm.js'))
8578+
ret = Popen(NODE_JS + [os.path.join('subdir', 'a.js')], stdout=PIPE).communicate()[0]
8579+
try_delete('subdir')
8580+
assert 'hello, world!' in ret
8581+
8582+
# Test that the build is loaded properly when memoryInitializerPrefixURL is being used, and it returns a relative path.
8583+
os.mkdir('subdir')
8584+
open(os.path.join('subdir', 'pre.js'), 'w').write('''
8585+
var Module = {};
8586+
Module.memoryInitializerPrefixURL = 'data/';
8587+
''')
8588+
8589+
Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world.c'), '-o', os.path.join('subdir', 'a.js'), '--pre-js', os.path.join('subdir', 'pre.js')] + args).communicate()
8590+
os.mkdir(os.path.join('subdir', 'data'))
8591+
os.rename(os.path.join('subdir', 'a.js.mem'), os.path.join('subdir', 'data', 'a.js.mem'))
8592+
ret = Popen(NODE_JS + [os.path.join('subdir', 'a.js')], stdout=PIPE).communicate()[0]
8593+
try_delete('subdir')
8594+
assert 'hello, world!' in ret

tools/file_packager.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -738,6 +738,7 @@ def was_seen(name):
738738
var REMOTE_METADATA_NAME = typeof Module['locateFile'] === 'function' ?
739739
Module['locateFile']('%(metadata_file)s') :
740740
((Module['filePackagePrefixURL'] || '') + '%(metadata_file)s');
741+
REMOTE_METADATA_NAME = joinUrl(Module['scriptDirectory'], REMOTE_METADATA_NAME);
741742
var xhr = new XMLHttpRequest();
742743
xhr.onreadystatechange = function() {
743744
if (xhr.readyState === 4 && xhr.status === 200) {

0 commit comments

Comments
 (0)