Skip to content

Commit edfbe07

Browse files
authored
Support input from the global Module object in MODULARIZE_INSTANCE (#7293)
fixes #7101 Background: normally, if you define Module and properties on it, like preRun, then we notice that and use them. In MODULARIZE, however, the user creates the instances of the module, and can pass Module or something else as desired (if we passed Module there it might be surprising). However, in MODULARIZE_INSTANCE mode we are more like the normal mode in that there is a single instance, started automatically, and defining things on Module is how the user can influence it.
1 parent c2fa39c commit edfbe07

File tree

5 files changed

+181
-1
lines changed

5 files changed

+181
-1
lines changed

emcc.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2685,8 +2685,12 @@ def modularize():
26852685
}
26862686
else:
26872687
# Create the MODULARIZE_INSTANCE instance
2688+
# Note that we notice the global Module object, just like in normal
2689+
# non-MODULARIZE mode (while MODULARIZE has the user create the instances,
2690+
# and the user can decide whether to use Module there or something
2691+
# else etc.).
26882692
src = '''
2689-
var %(EXPORT_NAME)s = (%(src)s)();
2693+
var %(EXPORT_NAME)s = (%(src)s)(typeof %(EXPORT_NAME)s === 'object' ? %(EXPORT_NAME)s : {});
26902694
''' % {
26912695
'EXPORT_NAME': shared.Settings.EXPORT_NAME,
26922696
'src': src

src/settings.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -779,6 +779,14 @@ var DETERMINISTIC = 0;
779779
// to the onRuntimeInitialized callback (i.e., it waits for all
780780
// necessary async events). It receives the instance as a parameter,
781781
// for convenience.
782+
//
783+
// Note that in MODULARIZE mode we do *not* look at the global `Module`
784+
// object, so if you define things there they will be ignored. The reason
785+
// is that you will be constructing the instances manually, and can
786+
// provide Module there, or something else, as you want. This differs
787+
// in MODULARIZE_INSTANCE mode, where we *do* look at the global, since
788+
// as in non-MODULARIZE mode there is just one global instance, and it
789+
// is constructed by the setup code.
782790
var MODULARIZE = 0;
783791

784792
// Similar to MODULARIZE, but while that mode exports a function, with which you
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
int main() {
2+
EM_ASM({
3+
if (!Module.someProperty) {
4+
alert("Must see a property on Module, that arrived from outside");
5+
abort();
6+
}
7+
});
8+
REPORT_RESULT(0);
9+
return 0;
10+
}
11+
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
<!doctype html>
2+
<html lang="en-us">
3+
<head>
4+
<meta charset="utf-8">
5+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
6+
<title>Emscripten-Generated Code</title>
7+
<style>
8+
.emscripten { padding-right: 0; margin-left: auto; margin-right: auto; display: block; }
9+
textarea.emscripten { font-family: monospace; width: 80%; }
10+
div.emscripten { text-align: center; }
11+
div.emscripten_border { border: 1px solid black; }
12+
/* the canvas *must not* have any border or padding, or mouse coords will be wrong */
13+
canvas.emscripten { border: 0px none; background-color: black; }
14+
15+
.spinner {
16+
height: 50px;
17+
width: 50px;
18+
margin: 0px auto;
19+
-webkit-animation: rotation .8s linear infinite;
20+
-moz-animation: rotation .8s linear infinite;
21+
-o-animation: rotation .8s linear infinite;
22+
animation: rotation 0.8s linear infinite;
23+
border-left: 10px solid rgb(0,150,240);
24+
border-right: 10px solid rgb(0,150,240);
25+
border-bottom: 10px solid rgb(0,150,240);
26+
border-top: 10px solid rgb(100,0,200);
27+
border-radius: 100%;
28+
background-color: rgb(200,100,250);
29+
}
30+
@-webkit-keyframes rotation {
31+
from {-webkit-transform: rotate(0deg);}
32+
to {-webkit-transform: rotate(360deg);}
33+
}
34+
@-moz-keyframes rotation {
35+
from {-moz-transform: rotate(0deg);}
36+
to {-moz-transform: rotate(360deg);}
37+
}
38+
@-o-keyframes rotation {
39+
from {-o-transform: rotate(0deg);}
40+
to {-o-transform: rotate(360deg);}
41+
}
42+
@keyframes rotation {
43+
from {transform: rotate(0deg);}
44+
to {transform: rotate(360deg);}
45+
}
46+
47+
</style>
48+
</head>
49+
<body>
50+
<hr/>
51+
<figure style="overflow:visible;" id="spinner"><div class="spinner"></div><center style="margin-top:0.5em"><strong>emscripten</strong></center></figure>
52+
<div class="emscripten" id="status">Downloading...</div>
53+
<div class="emscripten">
54+
<progress value="0" max="100" id="progress" hidden=1></progress>
55+
</div>
56+
<div class="emscripten_border">
57+
<canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()"></canvas>
58+
</div>
59+
<hr/>
60+
<div class="emscripten">
61+
<input type="checkbox" id="resize">Resize canvas
62+
<input type="checkbox" id="pointerLock" checked>Lock/hide mouse pointer
63+
&nbsp;&nbsp;&nbsp;
64+
<input type="button" value="Fullscreen" onclick="Module.requestFullscreen(document.getElementById('pointerLock').checked,
65+
document.getElementById('resize').checked)">
66+
</div>
67+
68+
<hr/>
69+
<textarea class="emscripten" id="output" rows="8"></textarea>
70+
<hr>
71+
<script type='text/javascript'>
72+
var statusElement = document.getElementById('status');
73+
var progressElement = document.getElementById('progress');
74+
var spinnerElement = document.getElementById('spinner');
75+
76+
var Module = {
77+
someProperty: 1234, // This is the crucial thing!
78+
preRun: [],
79+
postRun: [],
80+
print: (function() {
81+
var element = document.getElementById('output');
82+
if (element) element.value = ''; // clear browser cache
83+
return function(text) {
84+
if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' ');
85+
// These replacements are necessary if you render to raw HTML
86+
//text = text.replace(/&/g, "&amp;");
87+
//text = text.replace(/</g, "&lt;");
88+
//text = text.replace(/>/g, "&gt;");
89+
//text = text.replace('\n', '<br>', 'g');
90+
console.log(text);
91+
if (element) {
92+
element.value += text + "\n";
93+
element.scrollTop = element.scrollHeight; // focus on bottom
94+
}
95+
};
96+
})(),
97+
printErr: function(text) {
98+
if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' ');
99+
if (0) { // XXX disabled for safety typeof dump == 'function') {
100+
dump(text + '\n'); // fast, straight to the real console
101+
} else {
102+
console.error(text);
103+
}
104+
},
105+
canvas: (function() {
106+
var canvas = document.getElementById('canvas');
107+
108+
// As a default initial behavior, pop up an alert when webgl context is lost. To make your
109+
// application robust, you may want to override this behavior before shipping!
110+
// See http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.15.2
111+
canvas.addEventListener("webglcontextlost", function(e) { alert('WebGL context lost. You will need to reload the page.'); e.preventDefault(); }, false);
112+
113+
return canvas;
114+
})(),
115+
setStatus: function(text) {
116+
if (!Module.setStatus.last) Module.setStatus.last = { time: Date.now(), text: '' };
117+
if (text === Module.setStatus.last.text) return;
118+
var m = text.match(/([^(]+)\((\d+(\.\d+)?)\/(\d+)\)/);
119+
var now = Date.now();
120+
if (m && now - Module.setStatus.last.time < 30) return; // if this is a progress update, skip it if too soon
121+
Module.setStatus.last.time = now;
122+
Module.setStatus.last.text = text;
123+
if (m) {
124+
text = m[1];
125+
progressElement.value = parseInt(m[2])*100;
126+
progressElement.max = parseInt(m[4])*100;
127+
progressElement.hidden = false;
128+
spinnerElement.hidden = false;
129+
} else {
130+
progressElement.value = null;
131+
progressElement.max = null;
132+
progressElement.hidden = true;
133+
if (!text) spinnerElement.hidden = true;
134+
}
135+
statusElement.innerHTML = text;
136+
},
137+
totalDependencies: 0,
138+
monitorRunDependencies: function(left) {
139+
this.totalDependencies = Math.max(this.totalDependencies, left);
140+
Module.setStatus(left ? 'Preparing... (' + (this.totalDependencies-left) + '/' + this.totalDependencies + ')' : 'All downloads complete.');
141+
}
142+
};
143+
Module.setStatus('Downloading...');
144+
window.onerror = function() {
145+
Module.setStatus('Exception thrown, see JavaScript console');
146+
spinnerElement.style.display = 'none';
147+
Module.setStatus = function(text) {
148+
if (text) Module.printErr('[post-exception status] ' + text);
149+
};
150+
};
151+
</script>
152+
{{{ SCRIPT }}}
153+
</body>
154+
</html>

tests/test_browser.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4130,3 +4130,6 @@ def test_browser_modularize_no_current_script(self):
41304130
</script>
41314131
''' % creation)
41324132
self.run_browser('/'.join(path + ['test.html']), None, '/report_result?0')
4133+
4134+
def test_modularize_Module_input(self):
4135+
self.btest(path_from_root('tests', 'browser', 'modularize_Module_input.cpp'), '0', args=['--shell-file', path_from_root('tests', 'browser', 'modularize_Module_input.html'), '-s', 'MODULARIZE_INSTANCE=1'])

0 commit comments

Comments
 (0)