Skip to content

Commit 8a890f8

Browse files
committed
[[ Script ]] Allow per-module native code libraries.
The user of libscript can now set a callback to be used to resolve the path to native code libraries on a per-module basis. This is used when binding foreign handlers to libraries with no path, the callback is invoked with the module context so that a mapping to an absolute path for the code module for the current platform can be computed.
1 parent ed4beeb commit 8a890f8

3 files changed

Lines changed: 114 additions & 56 deletions

File tree

libscript/include/libscript/script.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,15 @@ typedef MCScriptInstance *MCScriptInstanceRef;
3535

3636
////////////////////////////////////////////////////////////////////////////////
3737

38+
typedef bool (*MCScriptResolveSharedLibraryCallback)(MCScriptModuleRef module, MCStringRef name, MCStringRef& r_path);
39+
3840
bool MCScriptInitialize(void);
3941
void MCScriptFinalize(void);
4042

43+
void MCScriptSetResolveSharedLibraryCallback(MCScriptResolveSharedLibraryCallback callback);
44+
45+
bool MCScriptResolveSharedLibrary(MCScriptModuleRef module, MCStringRef name, MCStringRef& r_path);
46+
4147
////////////////////////////////////////////////////////////////////////////////
4248

4349
// Packages are a collection of modules which share a common set of foreign

libscript/src/script-instance.cpp

Lines changed: 90 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -936,7 +936,82 @@ static bool __split_binding(MCStringRef& x_string, codepoint_t p_char, MCStringR
936936
return true;
937937
}
938938

939-
static bool MCScriptResolveForeignFunctionBinding(MCScriptForeignHandlerDefinition *p_handler, ffi_abi& r_abi, bool p_throw, bool& r_bound)
939+
static bool MCScriptPlatformLoadSharedLibrary(MCStringRef p_path, void*& r_handle)
940+
{
941+
#if defined(_WIN32)
942+
HMODULE t_module;
943+
MCAutoStringRefAsWString t_library_wstr;
944+
if (!t_library_wstr.Lock(p_path))
945+
return false;
946+
t_module = LoadLibraryW(*t_library_wstr);
947+
if (t_module == NULL)
948+
return false;
949+
r_handle = (void *)t_module;
950+
#else
951+
MCAutoStringRefAsUTF8String t_utf8_library;
952+
if (!t_utf8_library.Lock(p_path))
953+
return false;
954+
void *t_module;
955+
t_module = dlopen(*t_utf8_library, RTLD_LAZY);
956+
if (t_module == NULL)
957+
return false;
958+
r_handle = (void *)t_module;
959+
#endif
960+
return true;
961+
}
962+
963+
static bool MCScriptPlatformLoadSharedLibraryFunction(void *p_module, MCStringRef p_function, void*& r_pointer)
964+
{
965+
MCAutoStringRefAsCString t_function_name;
966+
if (!t_function_name.Lock(p_function))
967+
return false;
968+
969+
void *t_pointer;
970+
#if defined(_WIN32)
971+
t_pointer = GetProcAddress(p_module, *t_function_name);
972+
#else
973+
t_pointer = dlsym(p_module, *t_function_name);
974+
#endif
975+
976+
return true;
977+
}
978+
979+
static bool MCScriptLoadSharedLibrary(MCScriptModuleRef p_module, MCStringRef p_library, void*& r_handle)
980+
{
981+
// If there is no library name then we resolve to the executable module.
982+
if (MCStringIsEmpty(p_library))
983+
{
984+
#if defined(_WIN32)
985+
r_handle = GetModuleHandle(NULL);
986+
#elif defined(TARGET_SUBPLATFORM_ANDROID)
987+
r_handle = dlopen("librevandroid.so", 0);
988+
#else
989+
r_handle = dlopen(NULL, 0);
990+
#endif
991+
return true;
992+
}
993+
994+
// If there is no slash in the name, we try to resolve based on the module.
995+
uindex_t t_offset;
996+
if (!MCStringFirstIndexOfChar(p_library, '/', 0, kMCStringOptionCompareExact, t_offset))
997+
{
998+
MCAutoStringRef t_mapped_library;
999+
if (MCScriptResolveSharedLibrary(p_module, p_library, Out(t_mapped_library)))
1000+
{
1001+
if (MCScriptPlatformLoadSharedLibrary(*t_mapped_library, r_handle))
1002+
return true;
1003+
}
1004+
}
1005+
1006+
// If the previous two things failed, then just try to load the library as written.
1007+
if (MCScriptPlatformLoadSharedLibrary(p_library, r_handle))
1008+
return true;
1009+
1010+
// Oh dear - no native code library for us!
1011+
return false;
1012+
}
1013+
1014+
static bool MCScriptResolveForeignFunctionBinding(MCScriptInstanceRef p_instance, MCScriptForeignHandlerDefinition *p_handler, ffi_abi& r_abi, bool p_throw, bool& r_bound)
9401015
{
9411016
MCStringRef t_rest;
9421017
t_rest = MCValueRetain(p_handler -> binding);
@@ -979,62 +1054,21 @@ static bool MCScriptResolveForeignFunctionBinding(MCScriptForeignHandlerDefiniti
9791054
if (!MCStringIsEmpty(*t_class))
9801055
return MCErrorCreateAndThrow(kMCGenericErrorTypeInfo, "reason", MCSTR("class not allowed in c binding string"), nil);
9811056

982-
983-
#ifdef _WIN32
984-
if (MCStringIsEmpty(*t_library))
1057+
void *t_module;
1058+
if (!MCScriptLoadSharedLibrary(MCScriptGetModuleOfInstance(p_instance), *t_library, t_module))
9851059
{
986-
p_handler -> function = GetProcAddress(GetModuleHandle(NULL), MCStringGetCString(*t_function));
987-
}
988-
else
989-
{
990-
HMODULE t_module;
991-
MCAutoStringRefAsWString t_library_wstr;
992-
if (!t_library_wstr.Lock(*t_library))
993-
return false;
994-
t_module = LoadLibraryW(*t_library_wstr);
995-
if (t_module == nil)
996-
{
997-
if (p_throw)
998-
return MCErrorCreateAndThrow(kMCGenericErrorTypeInfo, "reason", MCSTR("unable to load foreign library"), nil);
999-
1000-
r_bound = false;
1001-
return true;
1002-
}
1003-
p_handler -> function = GetProcAddress(t_module, MCStringGetCString(*t_function));
1004-
}
1005-
#else
1006-
if (MCStringIsEmpty(*t_library))
1007-
{
1008-
void* t_self;
1009-
#ifdef TARGET_SUBPLATFORM_ANDROID
1010-
t_self = dlopen("librevandroid.so", 0);
1011-
if (t_self == NULL)
1012-
{
1013-
return MCErrorCreateAndThrow(kMCGenericErrorTypeInfo, "reason", MCSTR("could not bind to engine"), nil);
1014-
}
1015-
#else
1016-
t_self = dlopen(NULL, 0);
1017-
#endif
1018-
p_handler -> function = dlsym(t_self, MCStringGetCString(*t_function));
1019-
}
1020-
else
1021-
{
1022-
MCAutoStringRefAsUTF8String t_utf8_library;
1023-
if (!t_utf8_library.Lock(*t_library))
1024-
return false;
1025-
void *t_module;
1026-
t_module = dlopen(*t_utf8_library, RTLD_LAZY);
1027-
if (t_module == nil)
1028-
{
1029-
if (p_throw)
1030-
return MCErrorCreateAndThrow(kMCGenericErrorTypeInfo, "reason", MCSTR("unable to load foreign library"), nil);
1031-
1032-
r_bound = false;
1033-
return true;
1034-
}
1035-
p_handler -> function = dlsym(t_module, MCStringGetCString(*t_function));
1060+
if (p_throw)
1061+
return MCErrorCreateAndThrow(kMCGenericErrorTypeInfo, "reason", MCSTR("unable to load foreign library"), nil);
1062+
1063+
r_bound = false;
1064+
return true;
10361065
}
1037-
#endif
1066+
1067+
void *t_pointer;
1068+
if (!MCScriptPlatformLoadSharedLibraryFunction(t_module, *t_function, t_pointer))
1069+
return false;
1070+
1071+
p_handler -> function = t_pointer;
10381072
}
10391073
else if (MCStringIsEqualToCString(*t_language, "cpp", kMCStringOptionCompareExact))
10401074
{
@@ -1083,7 +1117,7 @@ static bool MCScriptResolveForeignFunctionBinding(MCScriptForeignHandlerDefiniti
10831117
static bool MCScriptPrepareForeignFunction(MCScriptFrame *p_frame, MCScriptInstanceRef p_instance, MCScriptForeignHandlerDefinition *p_handler, bool p_throw, bool& r_bound)
10841118
{
10851119
ffi_abi t_abi;
1086-
if (!MCScriptResolveForeignFunctionBinding(p_handler, t_abi, p_throw, r_bound))
1120+
if (!MCScriptResolveForeignFunctionBinding(p_instance, p_handler, t_abi, p_throw, r_bound))
10871121
return false;
10881122

10891123
if (!p_throw && !r_bound)

libscript/src/script-object.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ struct MCBuiltinModule
5252
static MCScriptModuleRef s_builtin_module = nil;
5353
static MCScriptModuleRef *s_builtin_modules = nil;
5454
static uindex_t s_builtin_module_count = 0;
55+
56+
static MCScriptResolveSharedLibraryCallback s_resolve_shared_library_callback = nil;
57+
5558
static bool MCFetchBuiltinModuleSection(MCBuiltinModule**& r_modules, unsigned int& r_count);
5659

5760
bool MCScriptInitialize(void)
@@ -277,6 +280,8 @@ bool MCScriptInitialize(void)
277280
return false;
278281
}
279282

283+
s_resolve_shared_library_callback = nil;
284+
280285
return true;
281286
}
282287

@@ -288,6 +293,19 @@ void MCScriptFinalize(void)
288293
MCValueRelease(s_builtin_module);
289294
}
290295

296+
void MCScriptSetResolveSharedLibraryCallback(MCScriptResolveSharedLibraryCallback p_callback)
297+
{
298+
s_resolve_shared_library_callback = p_callback;
299+
}
300+
301+
bool MCScriptResolveSharedLibrary(MCScriptModuleRef p_module, MCStringRef p_name, MCStringRef& r_path)
302+
{
303+
if (s_resolve_shared_library_callback == nil)
304+
return false;
305+
306+
return s_resolve_shared_library_callback(p_module, p_name, r_path);
307+
}
308+
291309
////////////////////////////////////////////////////////////////////////////////
292310

293311
bool MCScriptCreateObject(MCScriptObjectKind p_kind, size_t p_size, MCScriptObject*& r_object)

0 commit comments

Comments
 (0)