Emscripten linking errors

I’m compiling the FMOD GDextension plugin for Godot for web. While this plugin compiles fine for all other platforms, it fails when building for web.

wasm-ld: error: ../fmod/api/studio/lib/upstream/w32/fmodstudioL_bindings.a(fmod_os_js_api.o): relocation R_WASM_MEMORY_ADDR_SLEB cannot be used against symbol `JSFMOD::gSystemMap`; recompile with -fPIC
wasm-ld: error: ../fmod/api/studio/lib/upstream/w32/fmodstudioL_bindings.a(fmod_os_js_api.o): relocation R_WASM_MEMORY_ADDR_SLEB cannot be used against symbol `JSFMOD::gSystemMap`; recompile with -fPIC
wasm-ld: error: ../fmod/api/studio/lib/upstream/w32/fmodstudioL_bindings.a(fmod_os_js_api.o): relocation R_WASM_MEMORY_ADDR_SLEB cannot be used against symbol `JSFMOD::gSystemMap`; recompile with -fPIC
wasm-ld: error: ../fmod/api/studio/lib/upstream/w32/fmodstudioL_bindings.a(fmod_os_js_api.o): relocation R_WASM_MEMORY_ADDR_SLEB cannot be used against symbol `.L.str.160`; recompile with -fPIC
wasm-ld: error: ../fmod/api/studio/lib/upstream/w32/fmodstudioL_bindings.a(fmod_os_js_api.o): relocation R_WASM_MEMORY_ADDR_SLEB cannot be used against symbol `.L.str.160`; recompile with -fPIC
wasm-ld: error: ../fmod/api/studio/lib/upstream/w32/fmodstudioL_bindings.a(fmod_os_js_api.o): relocation R_WASM_MEMORY_ADDR_SLEB cannot be used against symbol `.L.str.161`; recompile with -fPIC
wasm-ld: error: ../fmod/api/studio/lib/upstream/w32/fmodstudioL_bindings.a(fmod_os_js_api.o): relocation R_WASM_MEMORY_ADDR_SLEB cannot be used against symbol `.L.str.161`; recompile with -fPIC
wasm-ld: error: ../fmod/api/studio/lib/upstream/w32/fmodstudioL_bindings.a(fmod_os_js_api.o): relocation R_WASM_MEMORY_ADDR_SLEB cannot be used against symbol `.L.str.161`; recompile with -fPIC
wasm-ld: error: ../fmod/api/studio/lib/upstream/w32/fmodstudioL_bindings.a(fmod_os_js_api.o): relocation R_WASM_MEMORY_ADDR_SLEB cannot be used against symbol `.L.str.161`; recompile with -fPIC
wasm-ld: error: ../fmod/api/studio/lib/upstream/w32/fmodstudioL_bindings.a(fmod_os_js_api.o): relocation R_WASM_MEMORY_ADDR_SLEB cannot be used against symbol `JSFMOD::gSoundMap`; recompile with -fPIC
wasm-ld: error: ../fmod/api/studio/lib/upstream/w32/fmodstudioL_bindings.a(fmod_os_js_api.o): relocation R_WASM_MEMORY_ADDR_SLEB cannot be used against symbol `JSFMOD::gSoundMap`; recompile with -fPIC
wasm-ld: error: ../fmod/api/studio/lib/upstream/w32/fmodstudioL_bindings.a(fmod_os_js_api.o): relocation R_WASM_MEMORY_ADDR_SLEB cannot be used against symbol `JSFMOD::gSoundMap`; recompile with -fPIC
wasm-ld: error: ../fmod/api/studio/lib/upstream/w32/fmodstudioL_bindings.a(fmod_os_js_api.o): relocation R_WASM_MEMORY_ADDR_SLEB cannot be used against symbol `.L.str.160`; recompile with -fPIC
wasm-ld: error: ../fmod/api/studio/lib/upstream/w32/fmodstudioL_bindings.a(fmod_os_js_api.o): relocation R_WASM_MEMORY_ADDR_SLEB cannot be used against symbol `.L.str.160`; recompile with -fPIC
wasm-ld: error: ../fmod/api/studio/lib/upstream/w32/fmodstudioL_bindings.a(fmod_os_js_api.o): relocation R_WASM_MEMORY_ADDR_SLEB cannot be used against symbol `.L.str.161`; recompile with -fPIC
wasm-ld: error: ../fmod/api/studio/lib/upstream/w32/fmodstudioL_bindings.a(fmod_os_js_api.o): relocation R_WASM_MEMORY_ADDR_SLEB cannot be used against symbol `.L.str.161`; recompile with -fPIC
wasm-ld: error: ../fmod/api/studio/lib/upstream/w32/fmodstudioL_bindings.a(fmod_os_js_api.o): relocation R_WASM_MEMORY_ADDR_SLEB cannot be used against symbol `JSFMOD::gChannelMap`; recompile with -fPIC
wasm-ld: error: ../fmod/api/studio/lib/upstream/w32/fmodstudioL_bindings.a(fmod_os_js_api.o): relocation R_WASM_MEMORY_ADDR_SLEB cannot be used against symbol `JSFMOD::gChannelMap`; recompile with -fPIC
wasm-ld: error: ../fmod/api/studio/lib/upstream/w32/fmodstudioL_bindings.a(fmod_os_js_api.o): relocation R_WASM_MEMORY_ADDR_SLEB cannot be used against symbol `JSFMOD::gChannelMap`; recompile with -fPIC
wasm-ld: error: ../fmod/api/studio/lib/upstream/w32/fmodstudioL_bindings.a(fmod_os_js_api.o): relocation R_WASM_MEMORY_ADDR_SLEB cannot be used against symbol `.L.str.160`; recompile with -fPIC
wasm-ld: error: too many errors emitted, stopping now (use -error-limit=0 to see all errors)
em++: error: 'D:/Users/pmdevita/Downloads/fmod-gdextension/emsdk/upstream/bin\wasm-ld.exe -o demo\addons\fmod\libs\web\libGodotFmod.web.template_debug.wasm32.wasm --whole-archive -s ../fmod/api/studio/lib/upstream/w32/fmodstudioL_bindings.a src\fmod_cache.o src\fmod_server.o src\fmod_string_names.o src\register_types.o src\callback\event_callbacks.o src\callback\file_callbacks.o src\core\fmod_file.o src\core\fmod_sound.o src\data\performance_data.o src\tools\fmod_editor_export_plugin.o src\tools\fmod_editor_plugin.o src\nodes\fmod_bank_loader.o src\nodes\fmod_event_emitter_2d.o src\nodes\fmod_event_emitter_3d.o src\nodes\fmod_listener_2d.o src\nodes\fmod_listener_3d.o src\resources\fmod_dsp_settings.o src\resources\fmod_settings.o src\resources\fmod_software_format_settings.o src\resources\fmod_sound_3d_settings.o src\studio\fmod_bank.o src\studio\fmod_bus.o src\studio\fmod_event.o src\studio\fmod_event_description.o src\studio\fmod_parameter_description.o src\studio\fmod_vca.o -LD:\Users\pmdevita\Downloads\fmod-gdextension\fmod\api\studio\lib\upstream\w32 -LD:\Users\pmdevita\Downloads\fmod-gdextension\emsdk\upstream\emscripten\cache\sysroot\lib\wasm32-emscripten\pic godot-cpp\bin\libgodot-cpp.web.template_debug.wasm32.nothreads.a --no-whole-archive --keep-section=target_features -mllvm -combiner-global-alias-analysis=false -mllvm -wasm-enable-sjlj -mllvm -disable-lsr -mllvm -exception-model=wasm --import-memory --strip-debug --export-dynamic --export=__wasm_call_ctors --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 --export-if-defined=__main_argc_argv --export-if-defined=__wasm_apply_data_relocs --export-if-defined=fflush --experimental-pic --unresolved-symbols=import-dynamic --no-shlib-sigcheck -shared --stack-first' failed (returned 1)
scons: *** [demo\addons\fmod\libs\web\libGodotFmod.web.template_debug.wasm32.wasm] Error 1
scons: building terminated because of errors.

I’ve also attempted to build against the bitcode distribution. This does compile, but when I boot Godot in the browser with it, I get this error in the console. Not sure where I read it as well, but it seemed like bitcode was going to get phased out at some point, so I’d prefer to not use it if that’s the case.

Uncaught (in promise) LinkError: imported function 'env.__atomic_store_8' signature mismatch 

I’m using FMOD Engine 2.02.26, compiling with Emscripten 3.1.74 against Godot 4.3.

There have been some previous threads touching the same topic. This one Issues with compiling for HTML5 using emscripten is fairly old now though, and as far as I understand, dynamic linking is not experimental in Emscripten anymore.

There is also this thread Emscripten link errors - #4 by rwkay which looks to be doing the exact same thing but for GameMaker. I’m not sure I understand this problem with the licensing, it’s not like I have to get a special build of Unity or Unreal statically built with FMOD so I can use it on the web (the distribution of that would be definitely be against the EULA).

If possible, I would like to explore two solutions. The first would be the original request from the GameMaker thread - would it be possible to get a w32 build of FMOD compiled with -fPIC?

If that is not permissible, would it instead be possible to get a build of FMOD compiled as a wasm dynamic library? This could then be dynamically linked against like we do for the other platforms, and avoid any EULA-related concerns of static compilation. I’ll note that while yes, there are wasm builds of FMOD included in the SDK, they are compiled for use directly with Javascript and trying to build against them results in this error:

wasm-ld: error: ../fmod/api/studio/lib/upstream/wasm/fmodstudioL.wasm: not a relocatable wasm file

I’ll add some info if anyone wants to look at my work. My branch is here GitHub - pmdevita/fmod-gdextension at web-support and you can view the diff with the master branch here Comparing utopia-rise:master...pmdevita:web-support · utopia-rise/fmod-gdextension · GitHub I’m compiling without thread support since FMOD doesn’t support it. Scons command looks something like this

scons target=template_debug platform=web fmod_lib_dir=path/to/fmod/html threads=no verbose=yes

We found other issues with this as fmod uses Emscripten features to embed JavaScript calls and callbacks…

Unfortunately at the time we were testing it Emscripten did not support this within a dynamic library, this meant we had to abandon the approach that we had. We have put the FMOD support for WASM on hold just now - but I do think there is scope to add it in the future but it would involve glueing it in at a Javascript level rather than using dynamic linking at the Emscripten level.

If you can get it working with dynamic linking and Emscripten then let us know as it would be by far the easiest method to support it.

Russell

Thank you for the suggestions, I have floated both of these options to the Dev team for consideration.

The problem as I understand it (I’m a dev, not legal) would be this part of what you are trying to do:

-o demo\addons\fmod\libs\web\libGodotFmod.web.template_debug.wasm32.wasm

Which is to say you aren’t generating an end-user application, you are generating a library for use in an end-user application, which I think would violate our EULA.
In any case, I will chat with the Dev team and see if either of these options are viable.

Just checking in, has there been any updates on this?

We compiled with PIC in our most recent release 2.02.27, and I’ve been assured there are indeed no EULA issues with what you are trying to do. I can get the FMOD GDExtension branch you posted compiling with it, but I lack the Godot knowledge to see if that results in a working HTML5 build.
Can you please give the latest version of FMOD a shot and let me know if you hit any other issues?

I can confirm it does indeed compile without errors now, thank you! It appears some kind of runtime error is occurring now though and I have yet to get it to print out a readable traceback. I’ll update when I do.

1 Like

Through the work of @bitbrain and sphynx, we have gotten FMOD to compile and boot on the web without crashing. However, we are unable to get audio playback, it looks like there’s some issue with FMOD starting the Web Audio context through its JS glue code. This might be a result of us compiling it as a side module, the emscripten docs mention

…only the singleton main module includes the JavaScript environment and side modules are pure WebAssembly modules.

Any ideas on what to do from here? The web-support branch on GitHub should now compile and the demo Godot project should be able to export with it using the web template with threads off and gdextension support on.

bitbrain also started a thread here that might be a good place to move to.

Working on this a bit more, it does seem that the issue is likely with loading the Web Audio JS code, I’m not sure it’s possible from a side module. I think a possible option would be to separate this from the wasm binary into its own file and pass its functions through as part of the imports when we call WebAssembly.instantiate for Godot. Does that sound doable?

EDIT: Dug into the Unity HTML5 binary a bit and it looks like it’s also bundling the audio worker JS in there. I would think that Unity loads it as a side module so maybe there is some way to do this after all and we’re missing something

Hi,

It is a requirement that you must have a window instance/handle to supply to an AudioContext to have something for FMOD to send audio to.
ie some basic webaudio code.

var AudioContext = window.AudioContext || window.webkitAudioContext;
var audioCtx = new AudioContext();

This might be your issue? You can supply a user supplied window handle to FMOD’s construction stage. The are not typically available in a worker or standalone side module.

In current FMOD API 2.4 testing we have a working node version for example, but it has to be FMOD_OUTPUTTYPE_NOSOUND due to the lack of a browser window.

I may have misinterpreted the limitations of a side module, but if you can pass in the main window handle to fmods initialization you could have your issue resolved.

Alright, I have some more information now. Here’s what the console looks like when we start in the web.

I think I was mistaken about side modules not being able to include JS, this error is being produced by some of FMOD’s inline JS so it’s definitely able to execute it. Just to be sure as well, I tested that we can create AudioContexts from a side module by inlining some JS with the EM_ASMpreprocessor. I don’t think there should be any technical limitations from emscripten.

It sounds like what you mentioned with supplying windowis what’s mentioned in the docs here and I’ve added that snippet in. It’s called during the init of the gdextension before it loads FMOD. It doesn’t seem to have changed anything though. Is there something more I should do?

Maybe the JS function that adds FMOD_JS_MixerFastpathFunctionand FMOD_JS_MixerSlowpathFunctionto Module isn’t getting called? I don’t see them on the Module by the time this error throws when I inspect with the debugger.

This is FMOD 2.03.06 and I’m currently using emcc 4.0.21

Hi you should be able to inspect the FMOD module in the debugger and determine if that symbol exists or not (it does in the js file). It seems a bit like fmod was loaded in one main module or worklet, then is being referred to or used by a different worklet , where typically you have to use messaging to communicate between them.

I also see the fact that it is trying to access slowpath mixer function that you dont have SharedArrayBuffer support on your browser?

if you can use the L version of FMOD as well it will give a lot more debug output which could be useful.