I'm playing a bit with NativeCall to get familiar with that side of Perl6. Of course, I'm trying to load libstatgrab first (what else?).
So I start with easiest part - the host information. Since no cluster support yet, it's just one result - no worries for complication.
The code:
#!/usr/bin/env perl6
use v6;
use NativeCall;
enum sg_error (
SG_ERROR_NONE => 0,
SG_ERROR_INVALID_ARGUMENT => 1,
...
);
class sg_error_details is repr('CStruct') {
has int32 $.error;
has int32 $.errno_value;
has Str $.error_arg;
};
sub sg_init(int32 $ignore_errors) returns int32 is native('statgrab') { * };
enum sg_host_state (
sg_unknown_configuration => 0,
sg_physical_host => 1,
sg_virtual_machine => 2,
sg_paravirtual_machine => 3,
sg_hardware_virtualized => 4
);
class sg_host_info is repr('CStruct') {
has Str $.os_name;
has Str $.os_release;
has Str $.os_version;
has Str $.platform;
has Str $.hostname;
has uint32 $.bitwidth;
has int32 $.host_state;
has uint32 $.ncpus;
has uint32 $.maxcpus;
has uint64 $.uptime;
has uint64 $.systime;
};
sub sg_get_host_info(size_t is rw) returns Pointer is native('statgrab') is symbol('sg_get_host_info_r') { * };
sub sg_free_host_info(Pointer) is native('statgrab') is symbol('sg_free_stats_buf') { * };
sub MAIN() {
my int32 $ignore_errors = 0;
my $error = sg_init($ignore_errors);
if $error != SG_ERROR_NONE {
say "Maeh: $error";
exit 1;
}
my size_t $num_host_infos = 0;
my $res = sg_get_host_info($num_host_infos);
if $num_host_infos > 0 {
my $host_info = nativecast(sg_host_info, $res);
with $host_info {
say "You're using ", $_.os_name, " on ", $_.hostname;
}
}
sg_free_host_info($res);
}
Starting it (dumb) results in loading library error:
$ perl6 statgrab.p6
Cannot locate native library 'libstatgrab.dylib': dlopen(libstatgrab.dylib, 1): image not found
in method setup at /Users/sno/rakudo/share/perl6/sources/24DD121B5B4774C04A7084827BFAD92199756E03 (NativeCall) line 283
in method CALL-ME at /Users/sno/rakudo/share/perl6/sources/24DD121B5B4774C04A7084827BFAD92199756E03 (NativeCall) line 570
in sub MAIN at statgrab.p6 line 95
in block <unit> at statgrab.p6 line 93
Okay - giving it some search path:
$ LD_LIBRARY_PATH=/opt/pkg/lib:$LD_LIBRARY_PATH perl6 statgrab.p6
Cannot locate native library 'libstatgrab.dylib': dlopen(libstatgrab.dylib, 1): image not found
Same picture when using DYLD_LIBRARY_PATH - which is supported by dlopen(3) on Darwin, too.
But changing in the directory works:
$ (cd /opt/pkg/lib && perl6 /data/Projects/OSS/p6-Unix-Statgrab/statgrab.p6 )
You're using Darwin on ernie.[...]
Is there a lack of search path passthrough in the way how moarvm is called?
doug$ perl6 -v
This is Rakudo Star version 2018.10 built on MoarVM version 2018.10
implementing Perl 6.c.
On a fairly recent Rakudo Star on MacOS High Sierra, the script worked "out of the box" for me:
edited script to remove '...'.
Script failed to load the library (really missing!)
brew install libstatgrab
Script ran successfully:
vader:learning doug$ perl6 nativecall_mac_Sno.pl6
You're using Darwin on Vader.local
Homebrew installed the library as follows:
$ v /usr/local/lib
total 11904
-rw-r--r-- 1 doug admin 6080828 Sep 23 12:40 libmoar.dylib
lrwxr-xr-x 1 doug admin 51 Mar 23 11:02 libstatgrab.10.dylib# -> ../Cellar/libstatgrab/0.91/lib/libstatgrab.10.dylib
lrwxr-xr-x 1 doug admin 44 Mar 23 11:02 libstatgrab.a# -> ../Cellar/libstatgrab/0.91/lib/libstatgrab.a
lrwxr-xr-x 1 doug admin 48 Mar 23 11:02 libstatgrab.dylib# -> ../Cellar/libstatgrab/0.91/lib/libstatgrab.dylib
drwxr-xr-x 3 doug admin 102 Mar 23 11:02 pkgconfig/
For me, the perl6 executable is indeed a shell script, but it worked (there was no need to pass any extra LD_LIBRARY_PATH=...).
doug$ file `which perl6`
/Applications/Rakudo/bin/perl6: POSIX shell script text executable, ASCII text, with very long lines
doug$ set | grep LIBRARY
doug$
I have also had issues with my nativecall scripts finding the library, but have always solved them by fixing the library install and/or supplying 'LD_LIBRARY_PATH'.
Sorry this experience was Less Than Awesome for you
Related
I am trying to compile a program with tinygo from Linux, when I enter the following command :
GOARCH=arm tinygo build -o <OutputName> ./main.go
I got :
/usr/lib/gcc-cross/arm-linux-gnueabihf/9/../../../../arm-linux-gnueabihf/bin/ld: /tmp/tinygo859602615/main.o: in function `syscall.Seek':
/usr/local/go/src/syscall/syscall_linux_arm.go:60: undefined reference to `syscall.seek'
The relevant codes indicated here above are :
// Underlying system call writes to newoffset via pointer.
// Implemented in assembly to avoid allocation.
func seek(fd int, offset int64, whence int) (newoffset int64, err Errno)
func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
newoffset, errno := seek(fd, offset, whence)
if errno != 0 {
return 0, errno
}
return newoffset, nil
}
I have just use sudo apt-get install arm-linux-gnueabihf to install this package.
However, GOARCH=arm go build -o ./main.go works without any problem.
Using CGO_ENABLED="0" flag doesn't change anything.
I have searched on the Internet and found no similar issues. Thank you for any possible information.
Environment :
Linux 5.4.0-73-generic #82-Ubuntu SMP Wed Apr 14 17:39:42 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
go version go1.16.3 linux/amd64
CGO_ENABLED="1"
GOROOT="/usr/local/go"
TINYGOROOT="/usr/local/lib/tinygo"
I was reading about exec in Go https://gobyexample.com/execing-processes, and tried to do the same using goroutines.
In the following code, I'm trying to make Go run ls, then print a success message in the main thread. However, it's only printing the ls, but not the success message.
What's going on?
Thanks.
package main
import "syscall"
import "os"
import "os/exec"
import "fmt"
func main() {
p := fmt.Println
done := make(chan bool)
binary, lookErr := exec.LookPath("ls")
if lookErr != nil {
panic(lookErr)
}
args := []string{"ls", "-a", "-l", "-h"}
env := os.Environ()
go func() {
execErr := syscall.Exec(binary, args, env)
if execErr != nil {
panic(execErr)
}
done <- true
}()
<-done
p("Done with exec")
}
Here's the output:
Valeriys-MacBook-Pro:test valeriy$ go run test.go
total 8
drwxr-xr-x 3 valeriy staff 96B Dec 17 15:46 .
drwxr-xr-x 8 valeriy staff 256B Dec 17 00:06 ..
-rw-r--r-- 1 valeriy staff 433B Dec 17 15:38 test.go
syscall.Exec replaces the current process with the one invoked.
If you want to run an external command while keeping the original program running, you need to use exec.Command
By the way, the link you included does say:
Sometimes we just want to completely replace the current Go process
with another (perhaps non-Go) one.
If you really want to use the syscall package, you can use syscall.StartProcess which does a fork/exec as opposed to a plain exec.
I'm using google protocol buffer library with:
$protoc --version
libprotoc 2.5.0
I search internet and it says the value encoding of a integer consists of multibytes that each byte 1st bit, is the indicator to say whether the encoding should continue to another byte. My understanding:
For a number 101 (0x65), it has only 1 byte, so its encoded value is still 0x65
For a number 0x6565, as long as it has 2 bytes, and intel uses little endian, the 1st byte should modify its first bit to be 1, and thus 0x65+0x80=0xe5, so the whole integer will have 2 bytes, and should become
0x65e5
This is my expectation. but I tested with my sample program. First I tried to set a "0x65" value to log7.data, and set "0x6565" to log8.data, and use xxl command to check them
cat 7.proto
message hello
{
required int32 f1=1;
}
$cat 7.cpp
#include "7.pb.h"
#include<fstream>
using namespace std;
int main()
{
fstream f("./log7.data",ios::binary|ios::out);
hello p;
p.set_f1(0x65);
p.SerializeToOstream(&f);
return 0;
}
$cat 8.cpp
#include ".pb.h"
#include<fstream>
using namespace std;
int main()
{
fstream f("./log8.data",ios::binary|ios::out);
hello p;
p.set_f1(0x6565);
p.SerializeToOstream(&f);
return 0;
}
Check the output:
$protoc 7.proto --cpp_out=./
g++ 7.cpp 7.pb.cc -lprotobuf && ./a.out && xxd log7.data
00000000: 0865 .e
$protoc 8.proto --cpp_out=./
$g++ 8.cpp 8.pb.cc -lprotobuf && ./a.out && xxd log8.data
00000000: 08e5 ca01 ....
You can see, for log8.data, I expect it to be "08e5 65", but it's actually "08e5 ca01". How to explain this value?
Thanks.
you need to split by 7 bit and add first bit
0x6565 => to binary
0b110010101100101 => split by 7 bit
0b1 1001010 1100101 => add first bit except first
0b1 11001010 11100101 => now show in hex
0x01cae5
Running this little script shows me that there is 12 opened descriptors when I run it. I know that 0,1,2 are stdin,stdout,sterr but what about the other 9 and why they're all opened and empty? Also, fd 9 seems to be a directory and I have no idea how to read it since fs.read returns Error: EISDIR, illegal operation on a directory.
fs = require('fs')
for(var i = 0; i < 1000; i++)
{
console.log(i,fs.fstatSync(i).size)
}
You can look at /proc/<pid of node process>/fd/. (If you are on linux)
0 -> /dev/pts/16
1 -> /dev/pts/16
2 -> /dev/pts/16
3 -> pipe:[6567721]
4 -> pipe:[6567721]
5 -> anon_inode:[eventpoll]
6 -> pipe:[6567722]
7 -> pipe:[6567722]
8 -> anon_inode:[eventfd]
9 -> /
So the directory of fd 9 is the root directory and the others are various forms of special file descriptors. I assume the two pairs of pipes are used by node internally to communicate between threads, as no other process is using them (checked with lsof | grep 656772)
Of course this does not tell you why, but it may be a first pointer.
how to read it since fs.read returns Error: EISDIR, illegal operation on a directory.
Directories should be read using fs.readdir
http://nodejs.org/api/fs.html#fs_fs_readdir_path_callback
I have the following code in a .dll:
namespace MyNamespace
{
extern "C" __declspec(dllexport) int __stdcall GetOptionID(unsigned long num)
{
return 0;
}
}
This is compiled on Visual C++ 2010, so I also have a .def file containing GetOptionID. I can see that the function is exported, and mangled as _GetOptionID#4, using dumpbin /exports:
File Type: DLL
Section contains the following exports for MyLibrary.dll
00000000 characteristics
53D269CB time date stamp Fri Jul 25 15:29:31 2014
0.00 version
1 ordinal base
13 number of functions
13 number of names
ordinal hint RVA name
1 0 0006F030 CmdOne = _CmdOne#16
2 1 0006F510 CmdUnimpl = _CmdUnimpl#16
3 2 0006EBB0 DefineThing = _DefineThing#32
4 3 0006E0C0 GetOptionID = _GetOptionID#4
In a separate executable, I attempt to check for the presence of GetOptionID:
HINSTANCE hinst = LoadLibraryEx(file_name, NULL, DONT_RESOLVE_DLL_REFERENCES);
if(!hinst)
return FALSE;
FARPROC_IDI lp = (FARPROC_IDI) GetProcAddress(hinst, "_GetOptionID#4");
auto e = GetLastError();
Running through this code in the debugger, I can see that:
LoadLibraryEx succeeds - I have a valid-looking hinst
GetProcAddress fails - lp is 0x00000000
GetLastError returns 127
I can see the function has been exported, and I can see its name matches the entry point I'm looking for. How come GetProcAddress is failing?
Ah, solved it myself. Defining the function in the .def file causes its name to be completely unmangled, meaning the correct target for GetProcAddress was simply GetOptionID.
However, since I have other .dlls that undergo the same check and really are _GetOptionID#4, the actual solution was to remove GetOptionID from the .def file.