emscripten-core / emscripten

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

Unable to add _emscripten_thread_exit_joinable to EXPORTED_FUNCTIONS #22108

Closed allsey87 closed 1 week ago

allsey87 commented 1 week ago

When building with both -pthread and -sRELOCATABLE, I get an error saying that _emscripten_thread_exit_joinable needs to be added to EXPORTED_FUNCTIONS. However, while adding EXPORTED_FUNCTIONS=__emscripten_thread_exit_joinable shows that --export=_emscripten_thread_exit_joinable is now passed to wasm-ld, I get the exact same error.

This issue is related to #21844, but I would like to focus here on why EXPORTED_FUNCTIONS is not working.

Version of emscripten/emsdk:

root@2d7bfb9259d9:/src# emcc -v
emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 3.1.61 (67fa4c16496b157a7fc3377afd69ee0445e8a6e3)
clang version 19.0.0git (https:/github.com/llvm/llvm-project 7cfffe74eeb68fbb3fb9706ac7071f8caeeb6520)
Target: wasm32-unknown-emscripten
Thread model: posix
InstalledDir: /emsdk/upstream/bin

Failing command line in full:

emcc -v -pthread -sRELOCATABLE -sEXPORTED_FUNCTIONS=_main,__emscripten_thread_exit_joinable test.c

Test.c source

root@2d7bfb9259d9:/src# cat test.c 
int main() {
    return 0;
}

Full link command and output with -v appended:

root@2d7bfb9259d9:/src# emcc -v -pthread -sRELOCATABLE -sEXPORTED_FUNCTIONS=_main,__emscripten_thread_exit_joinable test.c 
 /emsdk/upstream/bin/clang -target wasm32-unknown-emscripten -fignore-exceptions -fPIC -fvisibility=default -mllvm -combiner-global-alias-analysis=false -mllvm -enable-emscripten-sjlj -mllvm -disable-lsr --sysroot=/emsdk/upstream/emscripten/cache/sysroot -D__EMSCRIPTEN_SHARED_MEMORY__=1 -DEMSCRIPTEN -Werror=implicit-function-declaration -Xclang -iwithsysroot/include/fakesdl -Xclang -iwithsysroot/include/compat -v -pthread -matomics -mbulk-memory test.c -c -o /tmp/emscripten_temp__0hwmhis/test_0.o
clang version 19.0.0git (https:/github.com/llvm/llvm-project 7cfffe74eeb68fbb3fb9706ac7071f8caeeb6520)
Target: wasm32-unknown-emscripten
Thread model: posix
InstalledDir: /emsdk/upstream/bin
 (in-process)
 "/emsdk/upstream/bin/clang-19" -cc1 -triple wasm32-unknown-emscripten -emit-obj -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name test.c -mrelocation-model pic -pic-level 2 -mframe-pointer=none -ffp-contract=on -fno-rounding-math -mconstructor-aliases -target-feature +atomics -target-feature +bulk-memory -target-feature +mutable-globals -target-feature +sign-ext -target-feature +mutable-globals -target-cpu generic -target-feature +atomics -target-feature +bulk-memory -debugger-tuning=gdb -fdebug-compilation-dir=/src -v -fcoverage-compilation-dir=/src -resource-dir /emsdk/upstream/lib/clang/19 -D __EMSCRIPTEN_SHARED_MEMORY__=1 -D EMSCRIPTEN -isysroot /emsdk/upstream/emscripten/cache/sysroot -internal-isystem /emsdk/upstream/lib/clang/19/include -internal-isystem /emsdk/upstream/emscripten/cache/sysroot/include/wasm32-emscripten -internal-isystem /emsdk/upstream/emscripten/cache/sysroot/include -Werror=implicit-function-declaration -ferror-limit 19 -fvisibility=default -pthread -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fignore-exceptions -fcolor-diagnostics -iwithsysroot/include/fakesdl -iwithsysroot/include/compat -mllvm -combiner-global-alias-analysis=false -mllvm -enable-emscripten-sjlj -mllvm -disable-lsr -o /tmp/emscripten_temp__0hwmhis/test_0.o -x c test.c
clang -cc1 version 19.0.0git based upon LLVM 19.0.0git default target x86_64-unknown-linux-gnu
ignoring nonexistent directory "/emsdk/upstream/emscripten/cache/sysroot/include/wasm32-emscripten"
#include "..." search starts here:
#include <...> search starts here:
 /emsdk/upstream/emscripten/cache/sysroot/include/fakesdl
 /emsdk/upstream/emscripten/cache/sysroot/include/compat
 /emsdk/upstream/lib/clang/19/include
 /emsdk/upstream/emscripten/cache/sysroot/include
End of search list.
 /emsdk/upstream/bin/clang --version
 /emsdk/upstream/bin/wasm-ld -o a.out.wasm -L/emsdk/upstream/emscripten/cache/sysroot/lib/wasm32-emscripten/pic /tmp/emscripten_temp__0hwmhis/test_0.o /emsdk/upstream/emscripten/cache/sysroot/lib/wasm32-emscripten/pic/crtbegin.o -lGL-mt-getprocaddr -lal -lhtml5 -lbulkmemory -lstubs-debug -lnoexit -lc-mt-debug -ldlmalloc-mt -lcompiler_rt-mt -lc++-mt-noexcept -lc++abi-debug-mt-noexcept -lsockets-mt -mllvm -combiner-global-alias-analysis=false -mllvm -enable-emscripten-sjlj -mllvm -disable-lsr /tmp/tmp7cxrjadnlibemscripten_js_symbols.so --import-memory --shared-memory --strip-debug --export=_emscripten_thread_exit_joinable --export=emscripten_stack_get_end --export=emscripten_stack_get_free --export=emscripten_stack_get_base --export=emscripten_stack_get_current --export=emscripten_stack_set_limits --export=_emscripten_stack_alloc --export=_emscripten_thread_free_data --export=_emscripten_thread_crashed --export=emscripten_main_runtime_thread_id --export=emscripten_main_thread_process_queued_calls --export=_emscripten_run_on_main_thread_js --export=__get_temp_ret --export=__set_temp_ret --export=__wasm_call_ctors --export=_emscripten_tls_init --export=_emscripten_thread_init --export=setThrew --export=_emscripten_stack_restore --export=_emscripten_thread_exit --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 -pie --no-export-dynamic -z stack-size=65536 --no-growable-memory --initial-memory=16777216 --no-entry --stack-first
 /emsdk/upstream/bin/llvm-objcopy a.out.wasm a.out.wasm --remove-section=.debug* --remove-section=producers
 /emsdk/upstream/bin/wasm-emscripten-finalize --dyncalls-i64 --pass-arg=legalize-js-interface-export-originals --pass-arg=legalize-js-interface-exported-helpers a.out.wasm -o a.out.wasm --detect-features
 /emsdk/node/18.20.3_64bit/bin/node /emsdk/upstream/emscripten/src/compiler.mjs /tmp/tmphvry3t52.json
error: undefined symbol: _emscripten_thread_exit_joinable (referenced by root reference (e.g. compiled C/C++ code))
warning: To disable errors for undefined symbols use `-sERROR_ON_UNDEFINED_SYMBOLS=0`
warning: __emscripten_thread_exit_joinable may need to be added to EXPORTED_FUNCTIONS if it arrives from a system library
Error: Aborting compilation due to previous errors
emcc: error: '/emsdk/node/18.20.3_64bit/bin/node /emsdk/upstream/emscripten/src/compiler.mjs /tmp/tmphvry3t52.json' failed (returned 1)
sbc100 commented 1 week ago

Can I ask why are you trying to build with -sRELOCATABLE? Obviously we should fix this, but using that flag directly not common/recommended.

sbc100 commented 1 week ago

The reason that _emscripten_thread_exit_joinable is not available is that that symbol is only defined when -sMAIN_MODULE is used:

https://github.com/emscripten-core/emscripten/blob/75940022b722903c813a115baa0d9251cf047b9c/src/library_pthread.js#L1155-L1156

Unfortunetly at the callsite we protect that call with -DEMSCRIPTEN_DYNAMIC_LINKING which I believe is set whenever -sRELOCTABLE is used.. so there is a mismatch there:

https://github.com/emscripten-core/emscripten/blob/75940022b722903c813a115baa0d9251cf047b9c/system/lib/pthread/pthread_create.c#L343-L346

allsey87 commented 1 week ago

Can I ask why are you trying to build with -sRELOCATABLE? Obviously we should fix this, but using that flag directly not common/recommended.

I am probably a bit confused here, but I am trying to compile a set of static libraries that will be linked into either the main module or the side module. Now these libraries are built via Autoconf and Automake so the build process also includes compiling small test programs to see what features emcc has.

Initially I was just using -fPIC since I thought that neither -sMAIN_MODULE or -sSIDE_MODULE made sense here, but just using -fPIC alone is not enough to get PIC variants of system libraries from the cache. In order to get the PIC variants, -sRELOCATABLE has to be set (or set indirectly via -sMAIN_MODULE or -sSIDE_MODULE in emcc) to get the correct cache path.

Since I am compiling static libraries, I guess the version of the cache in use doesn't really matter since the static library will never actually be linked against anything in there, but I thought for the configure script compiler tests it would be more correct for those tests to use the system libraries coming from the correct cache path.

sbc100 commented 1 week ago

If you are building static libraries that you don't need -fPIC or MAIN_MODULE. For autoconf and automake and would recommend disabling dynamic linking completely using --disable-shared.

allsey87 commented 1 week ago

Huh, I thought the code would still need to be compiled with -fPIC if it is going to be linked into a relocatable module at some point...

sbc100 commented 1 week ago

Sure, yes, if you the final output is a MAIN_MODULE or a SIDE_MODULE than yes you would want to build with -fPIC. Is your final output of those?

sbc100 commented 1 week ago

In any case #22110 should fix this particular bug. In the long run I'm still hoping we can remove -sRELOCATBLE as a link flag since we don't test that mode fully, and I'm not sure what its usefulness is these days.

allsey87 commented 1 week ago

Sure, yes, if you the final output is a MAIN_MODULE or a SIDE_MODULE than yes you would want to build with -fPIC. Is your final output of those?

Yes, the final output will be either a MAIN_MODULE or SIDE_MODULE, the reason for adding -sRELOCATBLE is because I want the configure tests to link against the -fPIC variants of the system libraries since those are the only ones available when using emscripten_cache(flags = ["--pic"]).

sbc100 commented 1 week ago

In that case I would recommend using -sMAIN_MODULE=2 rather then -sRELOCTABLE

sbc100 commented 1 week ago

Sure, yes, if you the final output is a MAIN_MODULE or a SIDE_MODULE than yes you would want to build with -fPIC. Is your final output of those?

Yes, the final output will be either a MAIN_MODULE or SIDE_MODULE, the reason for adding -sRELOCATBLE is because I want the configure tests to link against the -fPIC variants of the system libraries since those are the only ones available when using emscripten_cache(flags = ["--pic"]).

Can't you setup the cache to contains both types of libraries? What if you have a statically linked binary and a dynamically linked binary in the same project?

allsey87 commented 1 week ago

Yeah, I was thinking that. Once I get some initial feedback on the direction of that PR, I will investigate calling embuilder multiple times with the different configurations.

allsey87 commented 1 week ago

In that case I would recommend using -sMAIN_MODULE=2 rather then -sRELOCTABLE

This is a decent workaround, but it seems incorrect that by default, if I compile code with -fPIC, it will link against non--fPIC system libraries. Perhaps the cache should be checking these flags directly instead of relying on the higher level Emscripten arguments like -sRELOCATABLE?

sbc100 commented 1 week ago

I'm proposing that we drop -sRELOCATABLE completely... unless you can think of a good use case for it.