/
NativeLibs.pm6
91 lines (80 loc) · 2.58 KB
/
NativeLibs.pm6
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
use v6;
unit module NativeLibs:auth<sortiz>:ver<0.0.2>;
use NativeCall :ALL;
our constant is-win = Rakudo::Internals.IS-WIN();
class Loader {
# Right now NC::cglobal unload loaded libraries too fast, so we need our own loader
class DLLib is repr('CPointer') { };
my \dyncall = $*VM.config<nativecall_backend> eq 'dyncall';
has Str $.name;
has DLLib $.library;
my sub dlerror(--> Str) is native { * } # For linux or darwin/OS X
my sub GetLastError(--> uint32) is native('kernel32') { * } # On Microsoft land
method !dlerror() {
given $*VM.config<osname>.lc {
when 'linux' | 'darwin' {
dlerror() // '';
}
when 'mswin32' | 'mingw' | 'msys' | 'cygwin' {
"error({ GetLastError })";
}
}
}
my sub dlLoadLibrary(Str --> DLLib) is native { * } # dyncall
my sub dlopen(Str, uint32 --> DLLib) is native { * } # libffi
my sub LoadLibraryA(Str --> DLLib) is native('kernel32') { * }
method !dlLoadLibrary(Str $libname --> DLLib) {
is-win ?? LoadLibraryA($libname) !!
dyncall ?? dlLoadLibrary($libname) !!
dlopen($libname, 0x102); # RTLD_GLOBAL | RTLD_NOW
}
method load(::?CLASS:U: $libname) {
with self!dlLoadLibrary($libname) {
self.bless(:name($libname), :library($_));
} else {
fail "Cannot load native library '$libname'" ~ self!dlerror();
}
}
sub dlFreeLibrary(DLLib) is native { * };
method dispose {
with $!library {
dlFreeLibrary($_);
$_ = Nil;
}
}
}
class Searcher {
method !test(Str() $try, $wks) {
(try cglobal($try, $wks, Pointer)) ~~ Pointer ?? $try !! Nil
}
method try-versions(Str $libname, Str $wks, *@vers) {
my $wlibname;
for @vers {
my $ver = $_.defined ?? Version.new($_) !! Version;
$wlibname = $_ and last with self!test:
$*VM.platform-library-name($libname.IO, :version($ver)), $wks;
}
$wlibname //= self!test: $*VM.platform-library-name($libname.IO), $wks
unless @vers; # Try unversionized
# Try common practice in Windows;
$wlibname //= self!test: $*VM.platform-library-name("lib$libname".IO), $wks;
$wlibname;
}
method at-runtime($libname, $wks, *@vers) {
-> {
with self.try-versions($libname, $wks, |@vers) {
$_
} else {
# The sensate thing to do is die, but somehow that don't work
# ( 'Cannot invoke this object' ... )
# so let NC::!setup die for us returning $libname.
# die "Cannot locate native library '$libname'"
$libname;
}
}
}
}
# Reexport on demand all of NativeCall
CHECK for NativeCall::EXPORT::.keys {
UNIT::EXPORT::{$_} := NativeCall::EXPORT::{$_};
}