🎨 optimize implementation of dlopen
This commit is contained in:
parent
456ed5c782
commit
bbd4d1907b
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
2
makefile
2
makefile
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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*);
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue