Emscripten: To use dlopen, you need to use Emscripten's linking support

Created on 7 Jun 2016  路  20Comments  路  Source: emscripten-core/emscripten

I try to link dynamic lib to my code, but I get message as in issue name. I use dlopen for link library and set compilers flags from main - MAIN_MODULE=1 and SIDE_MODULE=1 for .so.
My Makefile for dynamic lib:

libWebLib.js: WebLib.cpp
    emcc -fPIC -c WebLib.cpp -o WebLib.o
    emcc -shared -Wl,libWebLib.js -o libWebLib.js WebLib.o -s SIDE_MODULE=1
clean: $rm *.o *.so

And loadlib:

  void *handle;
  handle = dlopen("libWebLib.so", RTLD_NOW);
good first bug help wanted

Most helpful comment

We'll need to cherry-pick anyway since it isn't in a released version yet. I can do that if nobody beats me to it.

All 20 comments

Which version is this with? Older ones might need an extra DLOPEN or DLOPEN_SUPPORT flag.

Best to look at the dlopen-using tests in the test suite (such as test_dlfcn_basic), and see how they do it, since that is guaranteed to work.

I use 1.35 version.
Where I can found it (test_dlfcn_basic)?

Do a search in tests/. I am guessing it's in test_core.py there.

Ok, I found it. But now, dlopen() return NULL value.
I builded lib as:
emcc liblib.cpp -s SIDE_MODULE=1
And after, renamed output file a.out.js to liblib.so and move lib near main module.

Might be a warning in the console?

I would make sure you can run a test suite example first, then look at the difference between the two, moving between them until you find the issue.

No warnings.
Yes, I have already run tests and all were fine.
But my variant doesn't work.

Then I would bisect on the difference. If you end up with a small testcase showing an emscripten bug, please submit a PR with the new test.

I also had this problem. help!

I'm getting this error while using the SDL2 port (with -s USE_SDL=2). Is there a way around this?

I'm getting this error while using the SDL2 port (with -s USE_SDL=2). Is there a way around this?

Yeah, same here. I'm working on em-dosbox and want to activate OpenGL rendering output which is using SDL2 and does call dlopen() internally when (PFNGLGENBUFFERSARBPROC)SDL_GL_GetProcAddress("glGenBuffersARB");
is called.

https://github.com/dreamlayers/em-dosbox/blob/em-dosbox-svn-sdl2/src/gui/sdlmain.cpp#L1968

I guess we need to link against OpenGL directly, add OpenGL to dosbox_LDADD, add -s MAIN_MODULE=1 to the dosbox_LDFLAGS and somehow figure to emcc OpenGL with SIDE_MODULE=1 but I do really struggle to do it correctly... just missing some C/C++ and toolchain experience...

https://github.com/dreamlayers/em-dosbox/blob/em-dosbox-svn-sdl2/src/Makefile.am#L24

Running from pitfall to pitfall..

@kripken It would be super nice if you could help us. I already tried really hard to figure how it works... read the code/build config of BananaBread to activate -s LEGACY_GL_EMULATION=1 as well
and your call to dlopen() works well:

https://github.com/kripken/BananaBread/blob/5a22a0a86a2b0f9f89dd6311a6ecc28ac07097fc/cube2/src/engine/rendergl.cpp#L137

I believe having OpenGL working in em-dosbox would speed up all webbased old DOS games :) Would be so cool to play Rayman and other games in good speed in browser.

...and it's almost working. I think it's just the dlopen() issue that needs to me sorted... then it should work. Direct SDL/GL calls are already working in browser, see: OpenGL max_textsize: 3449712 which was: glGetIntegerv (GL_MAX_TEXTURE_SIZE, &sdl.opengl.max_texsize); in C++.

Bildschirmfoto 2019-05-05 um 16 47 38

It's probably better to get SDL2 to avoid dlopen for that, and call emscripten_GetProcAddress directly. That would not reqiure dynamic linking support, and be much more efficient too. Might be best to open an issue/PR for that on the SDL2 port repo.

Wow, good point. Thank you! I will try emscripten_GetProcAddress now

I checked emscripten core and SDL port for emscripten_GetProcAddress and found that for my eyes it seems pretty much okay... Looks more like a problem on my and @pulsejet side, because there is:

https://github.com/emscripten-core/emscripten/blob/39158e5e344460d5c0a5da8913f87e4cb0db6e4a/system/lib/gl/gl.c#L1448

and also the other functions used in my code are declared:

https://github.com/emscripten-core/emscripten/blob/39158e5e344460d5c0a5da8913f87e4cb0db6e4a/system/include/GL/gl.h#L941

So... in the original DosBox code it says (header/include):

#ifndef GL_ARB_vertex_buffer_object
#define GL_ARB_vertex_buffer_object 1
typedef void (APIENTRYP PFNGLGENBUFFERSARBPROC) (GLsizei n, GLuint *buffers);
typedef void (APIENTRYP PFNGLBINDBUFFERARBPROC) (GLenum target, GLuint buffer);
typedef void (APIENTRYP PFNGLDELETEBUFFERSARBPROC) (GLsizei n, const GLuint *buffers);
typedef void (APIENTRYP PFNGLBUFFERDATAARBPROC) (GLenum target, GLsizeiptr size, const 
GLvoid *data, GLenum usage);
typedef GLvoid* (APIENTRYP PFNGLMAPBUFFERARBPROC) (GLenum target, GLenum access);
typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERARBPROC) (GLenum target);
#endif

PFNGLGENBUFFERSARBPROC glGenBuffersARB = NULL;
PFNGLBINDBUFFERARBPROC glBindBufferARB = NULL;
PFNGLDELETEBUFFERSARBPROC glDeleteBuffersARB = NULL;
PFNGLBUFFERDATAARBPROC glBufferDataARB = NULL;
PFNGLMAPBUFFERARBPROC glMapBufferARB = NULL;
PFNGLUNMAPBUFFERARBPROC glUnmapBufferARB = NULL;

https://github.com/dreamlayers/em-dosbox/blob/em-dosbox-svn-sdl2/src/gui/sdlmain.cpp#L82

and later on:

glGenBuffersARB = (PFNGLGENBUFFERSARBPROC)SDL_GL_GetProcAddress("glGenBuffersARB");
glBindBufferARB = (PFNGLBINDBUFFERARBPROC)SDL_GL_GetProcAddress("glBindBufferARB");
glDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC)SDL_GL_GetProcAddress("glDeleteBuffersARB");
glBufferDataARB = (PFNGLBUFFERDATAARBPROC)SDL_GL_GetProcAddress("glBufferDataARB");
glMapBufferARB = (PFNGLMAPBUFFERARBPROC)SDL_GL_GetProcAddress("glMapBufferARB");
glUnmapBufferARB = (PFNGLUNMAPBUFFERARBPROC)SDL_GL_GetProcAddress("glUnmapBufferARB");

https://github.com/dreamlayers/em-dosbox/blob/em-dosbox-svn-sdl2/src/gui/sdlmain.cpp#L1968

It's the first complex project I'm porting using emscripten, so I'm struggling a little bit with understanding everything that goes on behind the scenes here. So far I understood that the original code tries to fetch the address to a native lib in memory. By setting -s USE_SDL=2 the emscripten SDL port code is used and seems to be automtially transpiled to JS and linked as a side module. There is probably some function name -> function map and a call to emscripten_GetProcAddress would return the function reference for the function name given (in JS).

Also, the emscripten SDL port headers and GL headers are used instead of the system installed ones. So when I call SDL_GL_GetProcAddress I need dynamic linking support for emscripten to be able to "see" the dependencies and return a function reference instead when transpiled to JS (?) -- and when I would use emscripten_GetProcAddress directly, I don't need dynamic linking (?)

Could you give me one further hint about what would be the best way to modify this dosbox code to let it work best with emscripten?

Because I tried to use emscripten_GetProcAddress in my C code directly (included emscripten.h to make sure it's declared) but I get sdlmain.cpp:2002:50: error: use of undeclared identifier 'emscripten_GetProcAddress'

Also, I get:

warning: undefined symbol: glCallList
warning: undefined symbol: glDeleteLists
warning: undefined symbol: glEndList
warning: undefined symbol: glGenLists
warning: undefined symbol: glIsList
warning: undefined symbol: glNewList

which I don't really understand because GL/gl.h which declares them is included

The em++ call is:

em++  -O3  -s USE_SDL=2 -s TOTAL_MEMORY=167772160 -s ALLOW_MEMORY_GROWTH=0 -s FORCE_FILESYSTEM=1 -s "BINARYEN_TRAP_MODE='clamp'" -s LEGACY_GL_EMULATION=1 -s ERROR_ON_UNDEFINED_SYMBOLS=0 -s EXTRA_EXPORTED_RUNTIME_METHODS='["GL", "cwrap", "ccall"]' -s EMTERPRETIFY=1 -s EMTERPRETIFY_ASYNC=1 -s [email protected] -s FETCH=1  -s WASM=1  -o dosbox.html dosbox.o  cpu/libcpu.a debug/libdebug.a dos/libdos.a fpu/libfpu.a  hardware/libhardware.a gui/libgui.a ints/libints.a misc/libmisc.a shell/libshell.a hardware/serialport/libserial.a libs/gui_tk/libgui_tk.a

I tried to use emscripten_GetProcAddress in my C code directly (included emscripten.h to make sure it's declared) but I get sdlmain.cpp:2002:50: error: use of undeclared identifier 'emscripten_GetProcAddress'

That should just work, so you may be hitting a bug. With EMCC_DEBUG=1 in the env it will log which system libraries are linked in, and gl contains that function. If nothing works out, a reproducible testcase we can debug would be good enough for us to fix it.

My Emscripten version is sdk-1.38.30-64bit, I'm having the same kind of error when using SDL2 in Rust, attempting to load function pointers for GL.

Here's the stack trace that I resolved:

I've tried to compile with dynamic linking enabled (-s MAIN_MODULE=1), but that leads to a compile-time error that isn't present otherwise, though it seems unrelated:

Unsupported:   %15 = tail call { i128, i1 } @llvm.uadd.with.overflow.i128(i128 %5, i128 1) #9
LLVM ERROR: Instruction not yet supported for integer types larger than 64 bits

I've used Emscripten / SDL2 in a similar project a while ago without having to worry about dynamic linking; I wonder why this has popped up since then.
I might try compiling the old code and/or bisecting to see what happened.

This is a bug in SDL2 that I just ran into myself. I have fixed it in revision control, so pulling the latest sources and rebuilding SDL should resolve this for you.

(We added some code to deal with pedantic EGL 1.4 implementations that can't find all symbols with eglGetProcAddress(), the fallback being to try looking for them ourselves with dlsym. This was for...Android, I think? But obviously this makes Emscripten deeply unhappy, so now we only use eglGetProcAddress there and everything works again.)

Unless this bug needs to remain open until Emscripten's SDL2 package is updated, this can be considered resolved now.

Sorry for the trouble!

Thanks for fixing upstream. Sounds like we need to update https://github.com/emscripten-ports/SDL2 now? If you feel like doing that that would be awesome, otherwise we can mark this bug as help-wanted and good-first-bug.

We may want to cherry-pick that fix unless we've planned an update soon. @Daft-Freak what do you think?

We'll need to cherry-pick anyway since it isn't in a released version yet. I can do that if nobody beats me to it.

An error occurred running the Unity content on this page. See your browser JavaScript console for more info. The error was: abort("To use dlopen, you need to use Emscripten's linking support, see https://github.com/kripken/emscripten/wiki/Linking") at jsStackTrace@http://.....

i am getting this error and it tells me to use emscripten's linking support as you can see and i am not really knowledgeable about this stuff could someone guide me properly on how to fix my issue

i was trying use and API via

using (var client = new System.Net.Http.HttpClient())
        {
            client.BaseAddress = new Uri("http://localhost:55044/Api/");
            var responseTask = client.GetAsync("Values?name=TESTNAME&recipientEmail=" + recipientEmail.text);
            responseTask.Wait();

            Debug.Log("message sent");
            var result = responseTask.Result;
            if (result.IsSuccessStatusCode)
            }

but i getting the above error

Was this page helpful?
0 / 5 - 0 ratings

Related issues

kripken picture kripken  路  4Comments

rpellerin picture rpellerin  路  3Comments

answer1103 picture answer1103  路  4Comments

surma picture surma  路  4Comments

yahsaves picture yahsaves  路  4Comments