emscripten-core / emscripten

Emscripten: An LLVM-to-WebAssembly Compiler
Other
25.43k stars 3.25k forks source link

Emscripten and GLFW: can't compile due to linking error #20446

Open mrmav opened 9 months ago

mrmav commented 9 months ago

I need help understanding how I would use emscripten with glfw. My first initial problem was the cmake configure command complain about this:

CMake Error at /home/mrmav/cmake/cmake-3.27.7-linux-x86_64/share/cmake-3.27/Modules/FindPackageHandleStandardArgs.cmake:230 (message):
  Could NOT find X11 (missing: X11_X11_LIB)
Call Stack (most recent call first):
  /home/mrmav/cmake/cmake-3.27.7-linux-x86_64/share/cmake-3.27/Modules/FindPackageHandleStandardArgs.cmake:600 (_FPHSA_FAILURE_MESSAGE)
  /home/mrmav/cmake/cmake-3.27.7-linux-x86_64/share/cmake-3.27/Modules/FindX11.cmake:665 (find_package_handle_standard_args)
  engine/external/glfw/CMakeLists.txt:206 (find_package)

After hours trying to fix this issue, I found someone stating that when building with emscripten, one doesn't need to add the glfw library? So I added a guard to my cmakelists:

# if(NOT EMSCRIPTEN) 
    # not adding glfw, since emscripten includes it??
    add_subdirectory(external/glfw)
# endif()

I still linked like so: target_link_libraries(${PROJECT_NAME} glfw ${GLFW_LIBRARIES} imgui) I also added the following:

# https://thatonegamedev.com/cpp/programming-a-c-game-for-the-web-emscripten/
if (EMSCRIPTEN)
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -s USE_GLFW=3 -s ASSERTIONS=1 -s WASM=1 -s ASYNCIFY -sMAX_WEBGL_VERSION=2")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s USE_GLFW=3 -s ASSERTIONS=1 -s WASM=1 -s ASYNCIFY -sMAX_WEBGL_VERSION=2")
    set(CMAKE_EXECUTABLE_SUFFIX ".html")
endif ()

Now I'm getting linking errors, stating that glfw symbols are not found. Can anybody point me in the right direction on how to use emscripten and glfw? Thank you!

Version of emscripten/emsdk:

emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 3.1.47 (431685f05c67f0424c11473cc16798b9587bb536)
clang version 18.0.0 (https://github.com/llvm/llvm-project 21030b9ab4487d845e29792063f5666d8c4b8e09)
Target: wasm32-unknown-emscripten
Thread model: posix
InstalledDir: /home/mrmav/repos/emsdk/upstream/bin

Failing command line in full:

[ 35%] Linking CXX executable self-gamejam.js
cache:INFO: generating system asset: symbol_lists/026fad9af443ccf46b78e2f965a6e355dbcc75ff.json... (this will be cached in "/home/mrmav/repos/emsdk/upstream/emscripten/cache/symbol_lists/026fad9af443ccf46b78e2f965a6e355dbcc75ff.json" for subsequent builds)
cache:INFO:  - ok
wasm-ld: error: CMakeFiles/self-gamejam.dir/engine/src/Input/Input.cpp.o: undefined symbol: glfwUpdateGamepadMappings
wasm-ld: error: CMakeFiles/self-gamejam.dir/engine/src/Input/Input.cpp.o: undefined symbol: glfwGetGamepadState
em++: error: '/home/mrmav/repos/emsdk/upstream/bin/wasm-ld -o self-gamejam.wasm CMakeFiles/self-gamejam.dir/src/MapLoader.cpp.o CMakeFiles/self-gamejam.dir/src/SkiGame.cpp.o CMakeFiles/self-gamejam.dir/src/Sprite.cpp.o CMakeFiles/self-gamejam.dir/src/main.cpp.o CMakeFiles/self-gamejam.dir/src/Player.cpp.o CMakeFiles/self-gamejam.dir/src/InputCursor.cpp.o CMakeFiles/self-gamejam.dir/src/GameCamera.cpp.o CMakeFiles/self-gamejam.dir/engine/src/Game.cpp.o CMakeFiles/self-gamejam.dir/engine/src/Timer.cpp.o CMakeFiles/self-gamejam.dir/engine/src/OpenGL/ShaderAttributes.cpp.o CMakeFiles/self-gamejam.dir/engine/src/OpenGL/Texture2D.cpp.o CMakeFiles/self-gamejam.dir/engine/src/Render/Camera2D.cpp.o CMakeFiles/self-gamejam.dir/engine/src/Render/Spritebatch.cpp.o CMakeFiles/self-gamejam.dir/engine/src/Render/BitmapFont.cpp.o CMakeFiles/self-gamejam.dir/engine/src/Input/Input.cpp.o CMakeFiles/self-gamejam.dir/engine/src/Utils/Utils.cpp.o CMakeFiles/self-gamejam.dir/engine/src/Utils/Rectangle.cpp.o CMakeFiles/self-gamejam.dir/engine/src/Systems/FrameAnimation.cpp.o CMakeFiles/self-gamejam.dir/engine/src/Systems/TileSet.cpp.o CMakeFiles/self-gamejam.dir/engine/external/glad/glad.c.o CMakeFiles/self-gamejam.dir/engine/external/imgui/backends/imgui_impl_glfw.cpp.o CMakeFiles/self-gamejam.dir/engine/external/imgui/backends/imgui_impl_opengl3.cpp.o engine/libsimple-cpp-engine.a engine/external/libimgui.a -L/home/mrmav/repos/emsdk/upstream/emscripten/cache/sysroot/lib/wasm32-emscripten -lGL-webgl2 -lal -lhtml5 -lstubs-debug -lnoexit -lc-debug -ldlmalloc -lcompiler_rt -lc++-noexcept -lc++abi-debug-noexcept -lsockets -mllvm -combiner-global-alias-analysis=false -mllvm -enable-emscripten-sjlj -mllvm -disable-lsr /tmp/tmpmwn1j5emlibemscripten_js_symbols.so --export-if-defined=main --export-if-defined=__start_em_asm --export-if-defined=__stop_em_asm --export-if-defined=__start_em_lib_deps --export-if-defined=__stop_em_lib_deps --export-if-defined=__start_em_js --export-if-defined=__stop_em_js --export-if-defined=__main_argc_argv --export-if-defined=fflush --export=emscripten_stack_get_end --export=emscripten_stack_get_free --export=emscripten_stack_get_base --export=emscripten_stack_get_current --export=emscripten_stack_init --export=stackSave --export=stackRestore --export=stackAlloc --export=__errno_location --export=__get_temp_ret --export=__set_temp_ret --export=malloc --export=free --export=__wasm_call_ctors --export-table -z stack-size=65536 --initial-memory=16777216 --max-memory=16777216 --no-entry --stack-first --table-base=1' failed (returned 1)
gmake[2]: *** [CMakeFiles/self-gamejam.dir/build.make:459: self-gamejam.js] Error 1
gmake[1]: *** [CMakeFiles/Makefile2:383: CMakeFiles/self-gamejam.dir/all] Error 2
gmake: *** [Makefile:136: all] Error 2

Full link command and output with -v appended:

[ 18%] Linking CXX executable self-gamejam.js
/home/mrmav/cmake/cmake-3.27.7-linux-x86_64/bin/cmake -E cmake_link_script CMakeFiles/self-gamejam.dir/link.txt --verbose=1
/home/mrmav/repos/emsdk/upstream/emscripten/em++  -s USE_GLFW=3 -s ASSERTIONS=1 -s WASM=1 -s ASYNCIFY -sMAX_WEBGL_VERSION=2 @CMakeFiles/self-gamejam.dir/objects1.rsp -o self-gamejam.js @CMakeFiles/self-gamejam.dir/linkLibs.rsp
wasm-ld: error: CMakeFiles/self-gamejam.dir/engine/src/Input/Input.cpp.o: undefined symbol: glfwUpdateGamepadMappings
wasm-ld: error: CMakeFiles/self-gamejam.dir/engine/src/Input/Input.cpp.o: undefined symbol: glfwGetGamepadState
em++: error: '/home/mrmav/repos/emsdk/upstream/bin/wasm-ld -o self-gamejam.wasm CMakeFiles/self-gamejam.dir/src/MapLoader.cpp.o CMakeFiles/self-gamejam.dir/src/SkiGame.cpp.o CMakeFiles/self-gamejam.dir/src/Sprite.cpp.o CMakeFiles/self-gamejam.dir/src/main.cpp.o CMakeFiles/self-gamejam.dir/src/Player.cpp.o CMakeFiles/self-gamejam.dir/src/InputCursor.cpp.o CMakeFiles/self-gamejam.dir/src/GameCamera.cpp.o CMakeFiles/self-gamejam.dir/engine/src/Game.cpp.o CMakeFiles/self-gamejam.dir/engine/src/Timer.cpp.o CMakeFiles/self-gamejam.dir/engine/src/OpenGL/ShaderAttributes.cpp.o CMakeFiles/self-gamejam.dir/engine/src/OpenGL/Texture2D.cpp.o CMakeFiles/self-gamejam.dir/engine/src/Render/Camera2D.cpp.o CMakeFiles/self-gamejam.dir/engine/src/Render/Spritebatch.cpp.o CMakeFiles/self-gamejam.dir/engine/src/Render/BitmapFont.cpp.o CMakeFiles/self-gamejam.dir/engine/src/Input/Input.cpp.o CMakeFiles/self-gamejam.dir/engine/src/Utils/Utils.cpp.o CMakeFiles/self-gamejam.dir/engine/src/Utils/Rectangle.cpp.o CMakeFiles/self-gamejam.dir/engine/src/Systems/FrameAnimation.cpp.o CMakeFiles/self-gamejam.dir/engine/src/Systems/TileSet.cpp.o CMakeFiles/self-gamejam.dir/engine/external/glad/glad.c.o CMakeFiles/self-gamejam.dir/engine/external/imgui/backends/imgui_impl_glfw.cpp.o CMakeFiles/self-gamejam.dir/engine/external/imgui/backends/imgui_impl_opengl3.cpp.o engine/libsimple-cpp-engine.a engine/external/libimgui.a -L/home/mrmav/repos/emsdk/upstream/emscripten/cache/sysroot/lib/wasm32-emscripten -lGL-webgl2 -lal -lhtml5 -lstubs-debug -lnoexit -lc-debug -ldlmalloc -lcompiler_rt -lc++-noexcept -lc++abi-debug-noexcept -lsockets -mllvm -combiner-global-alias-analysis=false -mllvm -enable-emscripten-sjlj -mllvm -disable-lsr /tmp/tmpp28bmczalibemscripten_js_symbols.so --export-if-defined=main --export-if-defined=__start_em_asm --export-if-defined=__stop_em_asm --export-if-defined=__start_em_lib_deps --export-if-defined=__stop_em_lib_deps --export-if-defined=__start_em_js --export-if-defined=__stop_em_js --export-if-defined=__main_argc_argv --export-if-defined=fflush --export=emscripten_stack_get_end --export=emscripten_stack_get_free --export=emscripten_stack_get_base --export=emscripten_stack_get_current --export=emscripten_stack_init --export=stackSave --export=stackRestore --export=stackAlloc --export=__errno_location --export=__get_temp_ret --export=__set_temp_ret --export=malloc --export=free --export=__wasm_call_ctors --export-table -z stack-size=65536 --initial-memory=16777216 --max-memory=16777216 --no-entry --stack-first --table-base=1' failed (returned 1)
gmake[2]: *** [CMakeFiles/self-gamejam.dir/build.make:459: self-gamejam.js] Error 1
gmake[2]: Leaving directory '/home/mrmav/repos/self-gamejam/build'
gmake[1]: *** [CMakeFiles/Makefile2:383: CMakeFiles/self-gamejam.dir/all] Error 2
gmake[1]: Leaving directory '/home/mrmav/repos/self-gamejam/build'
gmake: *** [Makefile:136: all] Error 2
Ma-Pe-Ma commented 9 months ago

You were right: you should not add your GLFW source when you compile your project with emscripten as it uses its own implementation.

Your problem at the end is that GLFW's gamepad handling implementation has not been completed yet for emscripten that's why your compiler can't find the glfwUpdateGamepadMappings and glfwGetGamepadState functions. If you don't call these functions then there shouldn't be a problem when compiling.

To get gamepad input, I used the HTML5 bindings without problems. However this may have limitations too as it is the only polling-based API while the others are event-based as it is stated at the top of the page.

By the way, earlier this problem prevented using ImGui with GLFW + Emscripten but the ImGui teams also realized that the problem is not their fault, if you check the commit (at the bottom of the linked issue) then you can see they just started to use the __EMSCRIPTEN__ macro to ignore the aforementioned functions.

So if you want to use GLFW's gamepad handling then you have to wait for the complete implementation (or start contributing to it yourself). Until then use the HTML5 API.

sbc100 commented 8 months ago

If anyone would like to add glfwUpdateGamepadMappings and glfwGetGamepadState to emscripten's GLFW implementation that would be great! Marking this bug a help wanted.

mrmav commented 8 months ago

You were right: you should not add your GLFW source when you compile your project with emscripten as it uses its own implementation.

Your problem at the end is that GLFW's gamepad handling implementation has not been completed yet for emscripten that's why your compiler can't find the glfwUpdateGamepadMappings and glfwGetGamepadState functions. If you don't call these functions then there shouldn't be a problem when compiling.

To get gamepad input, I used the HTML5 bindings without problems. However this may have limitations too as it is the only polling-based API while the others are event-based as it is stated at the top of the page.

By the way, earlier this problem prevented using ImGui with GLFW + Emscripten but the ImGui teams also realized that the problem is not their fault, if you check the commit (at the bottom of the linked issue) then you can see they just started to use the __EMSCRIPTEN__ macro to ignore the aforementioned functions.

So if you want to use GLFW's gamepad handling then you have to wait for the complete implementation (or start contributing to it yourself). Until then use the HTML5 API.

Thank you for this response! It was very insightful in many ways. I'll take a look and add the guard as you mentioned and try it when I get the time. Will also take a look if for web builds I can manage using the HTML5 bindings.

I'll close this issue when I get the chance of testing this.

ljjjj228 commented 2 months ago

我在编译使用glfw库的c项目时,也遇到了找不到X11的错误,是emscripten 不能编译引用glfw的程序吗? 希望你能给到帮助,谢谢