SanderMertens / flecs

A fast entity component system (ECS) for C & C++

Home Page:https://www.flecs.dev

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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!