🎨 optimize implementation of dlopen

This commit is contained in:
ValKmjolnir 2024-06-20 00:29:14 +08:00
parent 456ed5c782
commit bbd4d1907b
13 changed files with 76 additions and 40 deletions

View File

@ -639,11 +639,11 @@ Windows(`.dll`):
`g++ -shared -o libfib.dll fib.o` `g++ -shared -o libfib.dll fib.o`
Then we write a test nasal file to run this fib function, using `os.platform()` we could write a cross-platform program: Then we write a test nasal file to run this fib function:
```javascript ```javascript
use std.dylib; use std.dylib;
var dlhandle = dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so")); var dlhandle = dylib.dlopen("libfib");
var fib = dlhandle.fib; var fib = dlhandle.fib;
for(var i = 1; i<30; i += 1) for(var i = 1; i<30; i += 1)
println(dylib.dlcall(fib, i)); println(dylib.dlcall(fib, i));
@ -660,7 +660,7 @@ dylib.dlclose(dlhandle.lib);
```javascript ```javascript
use std.dylib; use std.dylib;
var dlhandle = dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so")); var dlhandle = dylib.dlopen("libfib");
var fib = dlhandle.fib; var fib = dlhandle.fib;
var invoke = dylib.limitcall(1); # this means the called function has only one parameter var invoke = dylib.limitcall(1); # this means the called function has only one parameter
for(var i = 1; i<30; i += 1) for(var i = 1; i<30; i += 1)

View File

@ -618,12 +618,11 @@ Windows(`.dll`):
`g++ -shared -o libfib.dll fib.o` `g++ -shared -o libfib.dll fib.o`
好了那么我们可以写一个测试用的nasal代码来运行这个斐波那契函数了。 好了那么我们可以写一个测试用的nasal代码来运行这个斐波那契函数了:
下面例子中`os.platform()`是用来检测当前运行的系统环境的,这样可以实现跨平台:
```javascript ```javascript
use std.dylib; use std.dylib;
var dlhandle = dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so")); var dlhandle = dylib.dlopen("libfib");
var fib = dlhandle.fib; var fib = dlhandle.fib;
for(var i = 1; i<30; i += 1) for(var i = 1; i<30; i += 1)
println(dylib.dlcall(fib, i)); println(dylib.dlcall(fib, i));
@ -640,7 +639,7 @@ dylib.dlclose(dlhandle.lib);
```javascript ```javascript
use std.dylib; use std.dylib;
var dlhandle = dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so")); var dlhandle = dylib.dlopen("libfib");
var fib = dlhandle.fib; var fib = dlhandle.fib;
var invoke = dylib.limitcall(1); # this means the called function has only one parameter var invoke = dylib.limitcall(1); # this means the called function has only one parameter
for(var i = 1; i<30; i += 1) for(var i = 1; i<30; i += 1)

View File

@ -189,6 +189,8 @@ build/dylib_lib.o: \
src/nasal.h\ src/nasal.h\
src/nasal_type.h\ src/nasal_type.h\
src/nasal_gc.h\ src/nasal_gc.h\
src/util/util.h\
src/util/fs.h\
src/natives/dylib_lib.h src/natives/dylib_lib.cpp | build src/natives/dylib_lib.h src/natives/dylib_lib.cpp | build
$(CXX) $(CXXFLAGS) src/natives/dylib_lib.cpp -o build/dylib_lib.o $(CXX) $(CXXFLAGS) src/natives/dylib_lib.cpp -o build/dylib_lib.o

View File

@ -1,7 +1,7 @@
use std.dylib; use std.dylib;
use std.os; use std.os;
var _dl = dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so")); var _dl = dylib.dlopen("libfib");
var _fib = _dl.fib; var _fib = _dl.fib;

View File

@ -6,7 +6,7 @@ var (
getch, getch,
nonblock nonblock
) = func { ) = func {
var lib = dylib.dlopen("libkey"~(os.platform()=="windows"? ".dll":".so")); var lib = dylib.dlopen("libkey");
var kb = lib.nas_kbhit; var kb = lib.nas_kbhit;
var gt = lib.nas_getch; var gt = lib.nas_getch;
var nb = lib.nas_noblock; var nb = lib.nas_noblock;

View File

@ -1,7 +1,7 @@
use std.dylib; use std.dylib;
use std.os; use std.os;
var _dl = dylib.dlopen("libmat."~(os.platform()=="windows"?"dll":"so")); var _dl = dylib.dlopen("libmat");
var _vec2 = _dl.nas_vec2; var _vec2 = _dl.nas_vec2;

View File

@ -2,7 +2,7 @@ use std.dylib;
use std.os; use std.os;
var socket = func() { var socket = func() {
var lib = dylib.dlopen("libnasock"~(os.platform()=="windows"? ".dll":".so")); var lib = dylib.dlopen("libnasock");
var sock = lib.nas_socket; var sock = lib.nas_socket;
var closesocket = lib.nas_closesocket; var closesocket = lib.nas_closesocket;

View File

@ -1,9 +1,14 @@
#include "natives/dylib_lib.h" #include "natives/dylib_lib.h"
#include "util/util.h"
#include "util/fs.h"
#include <cstdlib>
#include <vector>
namespace nasal { namespace nasal {
const auto dynamic_library_type_name = "dylib"; const auto dynamic_library_type_name = "nasal::dynamic_library";
const auto function_address_type_name = "faddr"; const auto function_address_type_name = "nasal::function_address";
void dynamic_library_destructor(void* pointer) { void dynamic_library_destructor(void* pointer) {
#ifdef _WIN32 #ifdef _WIN32
@ -13,33 +18,74 @@ void dynamic_library_destructor(void* pointer) {
#endif #endif
} }
std::string search_dynamic_library_path(const std::string& dlname) {
const auto ext = (util::is_windows()? ".dll":".so");
const auto lib_path = (util::is_windows()? ".\\":"./") + dlname + ext;
if (fs::exists(lib_path)) {
return lib_path;
}
const auto env_path = std::string(getenv("PATH"));
const auto sep = (util::is_windows()? ";":":");
// do split string
std::vector<std::string> env_path_vec = {};
usize last = 0;
usize pos = env_path.find(sep, 0);
while(pos!=std::string::npos) {
if (pos>last) {
env_path_vec.push_back(env_path.substr(last, pos-last));
}
last = pos + 1;
pos = env_path.find(sep, last);
}
if (last!=env_path.length()) {
env_path_vec.push_back(env_path.substr(last));
}
const auto path_front = util::is_windows()? "\\module\\":"/module/";
for(auto& p : env_path_vec) {
p += path_front + lib_path;
if (fs::exists(p)) {
return p;
}
}
return "";
}
var builtin_dlopen(context* ctx, gc* ngc) { var builtin_dlopen(context* ctx, gc* ngc) {
auto dlname = ctx->localr[1]; auto dl = ctx->localr[1];
if (!dlname.is_str()) { if (!dl.is_str()) {
return nas_err("dylib::dlopen", "\"libname\" must be string"); return nas_err("dylib::dlopen", "\"libname\" must be string");
} }
const auto dlname = search_dynamic_library_path(dl.str());
if (dlname.empty()) {
return nas_err("dylib::dlopen",
"cannot find dynamic lib <" + dl.str() + ">"
);
}
// get library pointer // get library pointer
#ifdef _WIN32 #ifdef _WIN32
wchar_t* wide_string = new wchar_t[dlname.str().size()+1]; wchar_t* wide_string = new wchar_t[dlname.size()+1];
if (!wide_string) { if (!wide_string) {
return nas_err("dylib::dlopen", "malloc failed"); return nas_err("dylib::dlopen", "malloc failed");
} }
memset(wide_string, 0, sizeof(wchar_t) * dlname.str().size() + 1); memset(wide_string, 0, sizeof(wchar_t) * dlname.size() + 1);
mbstowcs(wide_string, dlname.str().c_str(), dlname.str().size() + 1); mbstowcs(wide_string, dlname.c_str(), dlname.size() + 1);
// load library by using wide string name // load library by using wide string name
void* dynamic_library_pointer = LoadLibraryA(dlname.str().c_str()); void* dynamic_library_pointer = LoadLibraryA(dlname.c_str());
delete []wide_string; delete []wide_string;
#else #else
void* dynamic_library_pointer = dlopen( void* dynamic_library_pointer = dlopen(
dlname.str().c_str(), RTLD_LOCAL|RTLD_LAZY dlname.c_str(), RTLD_LOCAL|RTLD_LAZY
); );
#endif #endif
// check library pointer and insert into returned hashmap // check library pointer and insert into returned hashmap
if (!dynamic_library_pointer) { if (!dynamic_library_pointer) {
return nas_err("dylib::dlopen", return nas_err("dylib::dlopen",
"cannot open dynamic lib <" + dlname.str() + ">" "cannot open dynamic lib <" + dl.str() + ">"
); );
} }
auto return_hash = ngc->temp = ngc->alloc(vm_type::vm_hash); auto return_hash = ngc->temp = ngc->alloc(vm_type::vm_hash);

View File

@ -11,10 +11,15 @@
#include <sys/wait.h> #include <sys/wait.h>
#endif #endif
#include <cstring>
#include <sstream>
namespace nasal { namespace nasal {
void dynamic_library_destructor(void*); void dynamic_library_destructor(void*);
std::string search_dynamic_library_path(const std::string&);
var builtin_dlopen(context*, gc*); var builtin_dlopen(context*, gc*);
var builtin_dlclose(context*, gc*); var builtin_dlclose(context*, gc*);
var builtin_dlcallv(context*, gc*); var builtin_dlcallv(context*, gc*);

View File

@ -6,7 +6,7 @@
namespace nasal { namespace nasal {
const auto file_type_name = "file"; const auto file_type_name = "nasal::FILE";
void filehandle_destructor(void* ptr) { void filehandle_destructor(void* ptr) {
fclose(static_cast<FILE*>(ptr)); fclose(static_cast<FILE*>(ptr));

View File

@ -2,7 +2,7 @@
namespace nasal { namespace nasal {
const auto dir_type_name = "dir"; const auto dir_type_name = "nasal::DIR";
void dir_entry_destructor(void* ptr) { void dir_entry_destructor(void* ptr) {
#ifndef _MSC_VER #ifndef _MSC_VER

View File

@ -8,22 +8,6 @@ use std.unix;
# open dynamic lib. return a hash including dl pointer and function pointers # open dynamic lib. return a hash including dl pointer and function pointers
var dlopen = func(libname) { var dlopen = func(libname) {
# find dynamic lib from local dir first
libname = (os.platform()=="windows"? ".\\":"./")~libname;
if (io.exists(libname))
return __dlopen(libname);
# find dynamic lib through PATH
var envpath = split(os.platform()=="windows"? ";":":", unix.getenv("PATH"));
# first find ./module
append(envpath, ".");
var path = os.platform()=="windows"? "\\module\\":"/module/";
foreach(var p;envpath) {
p ~= path~libname;
if (io.exists(p)) {
libname = p;
break;
}
}
return __dlopen(libname); return __dlopen(libname);
} }

View File

@ -23,7 +23,7 @@ func() {
}(); }();
var speed_test = func() { var speed_test = func() {
var dd = dylib.dlopen("libfib."~(os.platform()=="windows"? "dll":"so")); var dd = dylib.dlopen("libfib");
println("[dylib ] ", dd); println("[dylib ] ", dd);
var fd = dd.quick_fib; var fd = dd.quick_fib;
var vec_call = dylib.dlcall; var vec_call = dylib.dlcall;