Fatal errors when trying to integrate into Emscripten project
Falkgaard opened this issue · comments
Hi, I recently started an Emscripten/WebGL C++ project, but I'm having difficulties integrating Flecs. I'm not quite sure where to ask for help for this, but I figured I'd give it a shot here first.
Describe the bug
If I try to add some basic Flecs code to my C++ project, then when I build and run it I get the following error output:
[WARN] [Emscripten]: error: api.c: 258: member 'flecs.meta.Vector.type' has an invalid error range [2447656..0] line 241 > inlineScript:39:62
[WARN] [Emscripten]: fatal: entity.c: 2040: flecs.meta.Vector (CONSTRAINT_VIOLATED) line 241 > inlineScript:39:62
[WARN] [Emscripten]: Aborted(native code called abort()) line 241 > inlineScript:39:62
Uncaught RuntimeError: Aborted(native code called abort())
abort http://localhost:8000/js/webtemplate.js line 241 > srcScript:875
_abort http://localhost:8000/js/webtemplate.js line 241 > srcScript:5538
invoke_ii http://localhost:8000/js/webtemplate.js line 241 > srcScript:12503
webtemplate http://localhost:8000/js/webtemplate.js line 241 > srcScript:906
callMain http://localhost:8000/js/webtemplate.js line 241 > srcScript:13133
doRun http://localhost:8000/js/webtemplate.js line 241 > srcScript:13184
run http://localhost:8000/js/webtemplate.js line 241 > srcScript:13195
quit_ http://localhost:8000/js/webtemplate.js:241
handleException http://localhost:8000/js/webtemplate.js:9178
callMain http://localhost:8000/js/webtemplate.js:13127
doRun http://localhost:8000/js/webtemplate.js:13171
run http://localhost:8000/js/webtemplate.js:13182
setTimeout handler*run http://localhost:8000/js/webtemplate.js:13178
runCaller http://localhost:8000/js/webtemplate.js:13098
removeRunDependency http://localhost:8000/js/webtemplate.js:842
receiveInstance http://localhost:8000/js/webtemplate.js:1057
receiveInstantiationResult http://localhost:8000/js/webtemplate.js:1075
promise callback*webtemplate/instantiateAsync/webtemplate< http://localhost:8000/js/webtemplate.js:1010
promise callback*instantiateAsync http://localhost:8000/js/webtemplate.js:1002
createWasm http://localhost:8000/js/webtemplate.js:1096
webtemplate http://localhost:8000/js/webtemplate.js:12390
<anonymous> http://localhost:8000/:61
webtemplate.js line 241 > srcScript:875:11
abort http://localhost:8000/js/webtemplate.js line 241 > srcScript:875
_abort http://localhost:8000/js/webtemplate.js line 241 > srcScript:5538
abort http://localhost:8000/js/webtemplate.wasm:0
flecs_throw_invalid_delete http://localhost:8000/js/webtemplate.wasm:814003
flecs_on_delete_mark http://localhost:8000/js/webtemplate.wasm:799054
flecs_on_delete http://localhost:8000/js/webtemplate.wasm:785747
ecs_delete http://localhost:8000/js/webtemplate.wasm:782017
ecs_struct_init http://localhost:8000/js/webtemplate.wasm:677963
FlecsMetaImport http://localhost:8000/js/webtemplate.wasm:689521
ecs_import http://localhost:8000/js/webtemplate.wasm:708128
ecs_import_c http://localhost:8000/js/webtemplate.wasm:708359
ecs_init http://localhost:8000/js/webtemplate.wasm:1239127
AppContext::AppContext() http://localhost:8000/js/webtemplate.wasm:72277
invoke_ii http://localhost:8000/js/webtemplate.js line 241 > srcScript:12503
main http://localhost:8000/js/webtemplate.wasm:71735
webtemplate http://localhost:8000/js/webtemplate.js line 241 > srcScript:906
callMain http://localhost:8000/js/webtemplate.js line 241 > srcScript:13133
doRun http://localhost:8000/js/webtemplate.js line 241 > srcScript:13184
run http://localhost:8000/js/webtemplate.js line 241 > srcScript:13195
enter resource://devtools/server/actors/utils/event-loop.js:82
_onExceptionUnwind resource://devtools/server/actors/thread.js:2020
quit_ http://localhost:8000/js/webtemplate.js:241
handleException http://localhost:8000/js/webtemplate.js:9178
callMain http://localhost:8000/js/webtemplate.js:13127
doRun http://localhost:8000/js/webtemplate.js:13171
run http://localhost:8000/js/webtemplate.js:13182
(Async: setTimeout handler)
run http://localhost:8000/js/webtemplate.js:13178
runCaller http://localhost:8000/js/webtemplate.js:13098
removeRunDependency http://localhost:8000/js/webtemplate.js:842
receiveInstance http://localhost:8000/js/webtemplate.js:1057
receiveInstantiationResult http://localhost:8000/js/webtemplate.js:1075
(Async: promise callback)
webtemplate http://localhost:8000/js/webtemplate.js:1010
(Async: promise callback)
instantiateAsync http://localhost:8000/js/webtemplate.js:1002
createWasm http://localhost:8000/js/webtemplate.js:1096
webtemplate http://localhost:8000/js/webtemplate.js:12390
<anonymous> http://localhost:8000/:61
To Reproduce
Not quite sure...
Expected behavior
Seeing [ECS test]: Bob lives!
in the logger.
Additional context
System info:
Operating System: Arch Linux
Kernel: Linux 6.4.12-arch1-1
Architecture: x86-64
Hardware Vendor: Lenovo
Hardware Model: Lenovo ideapad Y700-15ISK
em++ --version:
emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 3.1.44-git (bec42dac7873903d09d713963e34020c22a8bd2d)
In the C++ code, all the Flecs code is the following:
#include <flecs.h>
// ...
class App {
public:
App(/*...*/) {
// ...
/* at the end of the init code */
auto bob = ecs.entity("Bob");
fmt::print( "[ECS test]: {} lives!\n", bob.name() );
}
// ...
private:
// ...
flecs::world ecs;
};
// ...
And if I comment these Flecs parts out of the code above, then the application runs as intended (sans any Flecs, of course).
main.cpp
has the following:
// ...
extern "C" int
main( int argc, char **argv )
{
try {
App ctx {};
#ifdef __EMSCRIPTEN__
emscripten_set_main_loop_arg( loop, &ctx, 0, true );
#else
while ( not glfwWindowShouldClose( ctx ) ) { loop( &ctx ); }
#endif
return EXIT_SUCCESS;
}
catch ( char const *eStr ) {
fmt::print( ERR_OS, "[ERROR]: \"{}\"\n", eStr );
}
catch ( ... ) {
fmt::print( ERR_OS, "[ERROR]: Unknown fatal error!\n" );
}
}
The App instance gets constructed before the Emscripten main-loop (since it's responsible for most initialization and such), but this shouldn't be an issue for Flecs, should it?
Some possibly relevant parts of the CMakeLists.txt
:
# ...
include(FetchContent)
#################################################################################
# Flecs #
#################################################################################
set(FETCHCONTENT_UPDATES_DISCONNECTED TRUE)
FetchContent_Declare(
flecs
GIT_REPOSITORY https://github.com/SanderMertens/flecs
GIT_TAG v3.2.7
)
FetchContent_GetProperties( flecs )
if( NOT flecs_POPULATED )
FetchContent_Populate( flecs )
add_subdirectory( ${flecs_SOURCE_DIR} ${flecs_BINARY_DIR} EXCLUDE_FROM_ALL )
endif()
# TODO: investigate FLECS_CUSTOM_BUILD later.
#################################################################################
# ...
target_link_libraries( ${MAIN_APP_NAME} glm imgui fmt::fmt flecs::flecs_static )
# ...
elseif( IMGUI_TARGET_WEB )
# Set specific flags for emcc and to place the result under /web/js/
set_target_properties( ${MAIN_APP_NAME} PROPERTIES
COMPILE_FLAGS "-O0 -g -gsource-map \
-s USE_WEBGL2 \
-s USE_GLFW=3 \
-s NO_DISABLE_EXCEPTION_CATCHING "
LINK_FLAGS "-O0 -g -gsource-map \
-s USE_WEBGL2 \
-s USE_GLFW=3 \
-s NO_DISABLE_EXCEPTION_CATCHING \
-s WASM \
-s FULL_ES3 \
-s DEMANGLE_SUPPORT \
-s DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR \
-s ASSERTIONS \
-s FORCE_FILESYSTEM \
-s EXPORTED_RUNTIME_METHODS=['cwrap, FS'] \
-s ALLOW_MEMORY_GROWTH=1 \
-s MODULARIZE \
-s EXPORT_NAME='\"${MAIN_APP_NAME}\"' \
--preload-file ../assets/ "
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/web/js
)
target_compile_definitions( ${MAIN_APP_NAME} PRIVATE -DIMGUIAPP_TARGET_WEB )
endif()
And some possibly relevant parts of the index.html
:
<script type="text/javascript" src="js/webtemplate.js"></script>
<body>
<div class="emscripten_border">
<canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()"></canvas>
</div>
<script type='text/javascript'>
try {
var moduleArgs = {
totalDependencies : 0,
preRun : [],
postRun : [],
print : (function() {})(),
printErr : function(text) { console.warn('[WARN] [Emscripten]: '+text) },
setStatus : function(text) {},
monitorRunDependencies : function(left) {},
canvas : (function() {
var canvas = document.getElementById('canvas');
canvas.addEventListener(
"webglcontextlost",
function(e) {
alert('WebGL context lost. You will need to reload the page.');
e.preventDefault();
},
false
);
return canvas;
})()
};
window.addEventListener( 'resize', js_resizeCanvas, false );
function js_resizeCanvas() {
document.getElementById('canvas').width = window.innerWidth;
document.getElementById('canvas').height = window.innerHeight;
};
webtemplate(moduleArgs).then( (instance) => {} );
}
catch(e) {
console.log( getExceptionMessage(e).toString() );
}
</script>
</body>
</html>
Do I need to do something particular with moduleArgs or something?
Thanks in advance for any help!
I really hope that I can get this working, Flecs seems absolutely amazing. ❤️
edit:
When I build the project as a binary without Emscripten, I get the expected output:
...
[INFO]: Done initializing!
[ECS test]: Bob lives!
[INFO] [App]: Destructing a model...
...
Hm, that sounds like an uninitialized value somewhere, I'll try to reproduce it
Try adding -s STACK_SIZE=1mb
to your link flags. I'm not sure what the minimum required is, it seems the emscripten default was previously higher, but now is only 64k.
Discovered this because using the flecs C API in emscripten builds gives this error after ecs_init
: Stack overflow detected. You can try increasing -sSTACK_SIZE (currently set to 65536)
Closing this issue as this fix seems to work for multiple people. Feel free to comment here if the issue wasn't resolved!