🎨 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`
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
use std.dylib;
var dlhandle = dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so"));
var dlhandle = dylib.dlopen("libfib");
var fib = dlhandle.fib;
for(var i = 1; i<30; i += 1)
println(dylib.dlcall(fib, i));
@ -660,7 +660,7 @@ dylib.dlclose(dlhandle.lib);
```javascript
use std.dylib;
var dlhandle = dylib.dlopen("libfib."~(os.platform()=="windows"?"dll":"so"));
var dlhandle = dylib.dlopen("libfib");
var fib = dlhandle.fib;
var invoke = dylib.limitcall(1); # this means the called function has only one parameter
for(var i = 1; i<30; i += 1)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,9 +1,14 @@
#include "natives/dylib_lib.h"
#include "util/util.h"
#include "util/fs.h"
#include <cstdlib>
#include <vector>
namespace nasal {
const auto dynamic_library_type_name = "dylib";
const auto function_address_type_name = "faddr";
const auto dynamic_library_type_name = "nasal::dynamic_library";
const auto function_address_type_name = "nasal::function_address";
void dynamic_library_destructor(void* pointer) {
#ifdef _WIN32
@ -13,33 +18,74 @@ void dynamic_library_destructor(void* pointer) {
#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) {
auto dlname = ctx->localr[1];
if (!dlname.is_str()) {
auto dl = ctx->localr[1];
if (!dl.is_str()) {
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
#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) {
return nas_err("dylib::dlopen", "malloc failed");
}
memset(wide_string, 0, sizeof(wchar_t) * dlname.str().size() + 1);
mbstowcs(wide_string, dlname.str().c_str(), dlname.str().size() + 1);
memset(wide_string, 0, sizeof(wchar_t) * dlname.size() + 1);
mbstowcs(wide_string, dlname.c_str(), dlname.size() + 1);
// 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;
#else
void* dynamic_library_pointer = dlopen(
dlname.str().c_str(), RTLD_LOCAL|RTLD_LAZY
dlname.c_str(), RTLD_LOCAL|RTLD_LAZY
);
#endif
// check library pointer and insert into returned hashmap
if (!dynamic_library_pointer) {
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);

View File

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

View File

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

View File

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

View File

@ -8,22 +8,6 @@ use std.unix;
# open dynamic lib. return a hash including dl pointer and function pointers
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);
}

View File

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