Skip to content

Commit 2969713

Browse files
author
Morten Sørvig
committed
Make embind work with -fvisibility=hidden
Export emscripten::val and emscripten::memory_view in order to prevent embind errors: BindingError: _emval_take_value has unknown type N10emscripten11memory_viewIhEE Embind generates a numerical type id from the address of the std::type_info object resulting from evaluating a typeid expressiion (e.g. 'void *id = &typeid(T)'). However, C++ does not guarantee that this address is identical for all evaluations of the typeid expression. In practice it is when using static linking, but not when using dynamic linking when the libraries are built with the '-fvisibility=hidden' compiler option. The non-identical id's then cause embind to decide that types have not been registered when used from a library, since they have been registered with a different id by the main wasm module. Exporting the types in question makes typeid addresses identical again, and fixes/works around the issue.
1 parent 59d2290 commit 2969713

File tree

3 files changed

+62
-2
lines changed

3 files changed

+62
-2
lines changed

system/include/emscripten/val.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <variant>
2424
#endif
2525

26+
#define EMSCRIPTEN_EXPORT __attribute__((visibility("default")))
2627

2728
namespace emscripten {
2829

@@ -284,7 +285,7 @@ struct WireTypePack {
284285
static const char name##_symbol[] = #name; \
285286
static const ::emscripten::internal::symbol_registrar<name##_symbol> name##_registrar
286287

287-
class val {
288+
class EMSCRIPTEN_EXPORT val {
288289
public:
289290
// missing operators:
290291
// * ~ - + ++ --

system/include/emscripten/wire.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include <string>
2525

2626
#define EMSCRIPTEN_ALWAYS_INLINE __attribute__((always_inline))
27+
#define EMSCRIPTEN_EXPORT __attribute__((visibility("default")))
2728

2829
#ifndef EMSCRIPTEN_HAS_UNBOUND_TYPE_NAMES
2930
#define EMSCRIPTEN_HAS_UNBOUND_TYPE_NAMES 1
@@ -430,7 +431,7 @@ constexpr bool typeSupportsMemoryView() {
430431
} // namespace internal
431432

432433
template<typename ElementType>
433-
struct memory_view {
434+
struct EMSCRIPTEN_EXPORT memory_view {
434435
memory_view() = delete;
435436
explicit memory_view(size_t size, const ElementType* data)
436437
: size(size)

test/test_other.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,16 @@ def decorated(self, *args, **kwargs):
209209

210210
return decorated
211211

212+
def requires_dylink(func):
213+
assert callable(func)
214+
215+
@wraps(func)
216+
def decorated(self, *args, **kwargs):
217+
self.check_dylink()
218+
return func(self, *args, **kwargs)
219+
220+
return decorated
221+
212222

213223
def llvm_nm(file):
214224
output = shared.run_process([LLVM_NM, file], stdout=PIPE).stdout
@@ -3346,6 +3356,54 @@ def test_embind_jsgen_method_pointer_stability(self):
33463356
# AOT JS generation still works correctly.
33473357
self.do_runf('other/embind_jsgen_method_pointer_stability.cpp', 'done')
33483358

3359+
def build_dylink_lib(self, filename, outfile='liblib.so', emcc_args=None):
3360+
self.clear_setting('MAIN_MODULE')
3361+
self.set_setting('SIDE_MODULE')
3362+
cmd = [compiler_for(filename), filename, '-o', outfile] + self.get_emcc_args()
3363+
if emcc_args:
3364+
cmd += emcc_args
3365+
self.run_process(cmd)
3366+
3367+
def prep_dylink_main(self):
3368+
self.clear_setting('SIDE_MODULE')
3369+
self.set_setting('MAIN_MODULE', 1)
3370+
3371+
@requires_dylink
3372+
def test_embind_dylink_visibility_hidden(self):
3373+
# Check that embind is usable from a library built with "-fvisibility=hidden"
3374+
create_file('liba.cpp', r'''
3375+
#include <emscripten/val.h>
3376+
3377+
#define EXPORT __attribute__((visibility("default")))
3378+
using namespace emscripten;
3379+
3380+
EXPORT void liba_fun() {
3381+
unsigned char buffer[1];
3382+
val view(typed_memory_view(1, buffer));
3383+
}
3384+
''')
3385+
3386+
self.build_dylink_lib('liba.cpp', outfile='liba.so', emcc_args=['-std=c++11', '-fvisibility=hidden'])
3387+
self.prep_dylink_main()
3388+
self.emcc_args = ['liba.so', '-L.', '--bind']
3389+
create_file('main.cpp', r'''
3390+
#include <stdio.h>
3391+
#include <emscripten/val.h>
3392+
3393+
using namespace emscripten;
3394+
3395+
void liba_fun();
3396+
3397+
int main() {
3398+
3399+
liba_fun();
3400+
3401+
printf("done\n");
3402+
return 0;
3403+
}
3404+
''')
3405+
self.do_runf('main.cpp', 'done\n')
3406+
33493407
def test_emit_tsd(self):
33503408
self.run_process([EMCC, test_file('other/test_emit_tsd.c'),
33513409
'--emit-tsd', 'test_emit_tsd.d.ts', '-sEXPORT_ES6',

0 commit comments

Comments
 (0)