英文:
Is there a data type for c FILE in Golang?
问题
我最近遇到了一个问题,尝试将https://github.com/robpike/strings编译为DLL(共享库),其中cgo
不识别os.File
作为可导出的数据类型。我想将这个dll导入到一个使用ctypes
的Python脚本中。
我对Go语言相对陌生,在大量搜索后,我找不到我的问题的答案。
strings.go
package main
import (
"bufio"
"flag"
"fmt"
"io"
"log"
"os"
"strconv"
"C"
)
var (
min = flag.Int("min", 6, "minimum length of UTF-8 strings printed, in runes")
max = flag.Int("max", 256, "maximum length of UTF-8 strings printed, in runes")
ascii = flag.Bool("ascii", false, "restrict strings to ASCII")
offset = flag.Bool("offset", false, "show file name and offset of start of each string")
)
var stdout *bufio.Writer
func main() {
}
//export do
func do(file *os.File) {
in := bufio.NewReader(file)
str := make([]rune, 0, *max)
filePos := int64(0)
print := func() {
if len(str) >= *min {
s := string(str)
// if *offset {
// fmt.Printf("%s:#%d:\t%s\n", name, filePos-int64(len(s)), s)
// } else {
fmt.Println(s)
// }
}
str = str[0:0]
}
for {
var (
r rune
wid int
err error
)
// One string per loop.
for ; ; filePos += int64(wid) {
r, wid, err = in.ReadRune()
if err != nil {
if err != io.EOF {
log.Print(err)
}
return
}
if !strconv.IsPrint(r) || *ascii && r >= 0xFF {
print()
continue
}
// It's printable. Keep it.
if len(str) >= *max {
print()
}
str = append(str, r)
}
}
}
期望结果:go build -o strings.dll -buildmode=c-shared
输出具有导出函数do
的strings.dll
问题:.\strings.go:41:15: Go type not supported in export: os.File
编辑:我遇到了这个问题:read file descriptor: The handle is invalid.
Python驱动程序(在Windows amd64上使用Python 3.10.5):
from ctypes import *
mydll = cdll.LoadLibrary("./strings.dll")
strings = mydll.dodo
strings.argtypes = [c_int]
strings.restype = c_void_p
with open("./go.mod", "rb") as h:
print(strings(h.fileno()))
英文:
I recently ran into an issue trying to compile https://github.com/robpike/strings as a DLL (shared lib), where cgo
doesn't recognise os.File
as an exportable data type. I want to import this dll into a python script with ctypes
.
I am relatively new to golang, and after a lot of googling I couldn't find an answer to my question.
strings.go
package main
import (
"bufio"
"flag"
"fmt"
"io"
"log"
"os"
"strconv"
"C"
)
var (
min = flag.Int("min", 6, "minimum length of UTF-8 strings printed, in runes")
max = flag.Int("max", 256, "maximum length of UTF-8 strings printed, in runes")
ascii = flag.Bool("ascii", false, "restrict strings to ASCII")
offset = flag.Bool("offset", false, "show file name and offset of start of each string")
)
var stdout *bufio.Writer
func main() {
}
//export do
func do(file *os.File) {
in := bufio.NewReader(file)
str := make([]rune, 0, *max)
filePos := int64(0)
print := func() {
if len(str) >= *min {
s := string(str)
// if *offset {
// fmt.Printf("%s:#%d:\t%s\n", name, filePos-int64(len(s)), s)
// } else {
fmt.Println(s)
// }
}
str = str[0:0]
}
for {
var (
r rune
wid int
err error
)
// One string per loop.
for ; ; filePos += int64(wid) {
r, wid, err = in.ReadRune()
if err != nil {
if err != io.EOF {
log.Print(err)
}
return
}
if !strconv.IsPrint(r) || *ascii && r >= 0xFF {
print()
continue
}
// It's printable. Keep it.
if len(str) >= *max {
print()
}
str = append(str, r)
}
}
}
Expectation: go build -o strings.dll -buildmode=c-shared
outputs strings.dll
with exported function do
Problem: .\strings.go:41:15: Go type not supported in export: os.File
EDIT:I am running into this issue: read file descriptor: The handle is invalid.
Python driver (3.10.5 on windows amd64):
from ctypes import *
mydll = cdll.LoadLibrary("./strings.dll")
strings = mydll.dodo
strings.argtypes = [c_int]
strings.restype = c_void_p
with open("./go.mod", "rb") as h:
print(strings(h.fileno()))
答案1
得分: 4
Cgo不支持将结构映射到C语言。实际上,在导出的函数中,你只能使用字符串、整数和本地C类型。
调用函数可以传递文件描述符而不是os.File
。文件描述符是一个整数。
我在你的代码中添加了func dodo(fd int)
函数,并导出该函数代替do
函数。
package main
import (
"C"
"bufio"
"flag"
"fmt"
"io"
"log"
"os"
"strconv"
)
var (
min = flag.Int("min", 6, "minimum length of UTF-8 strings printed, in runes")
max = flag.Int("max", 256, "maximum length of UTF-8 strings printed, in runes")
ascii = flag.Bool("ascii", false, "restrict strings to ASCII")
offset = flag.Bool("offset", false, "show file name and offset of start of each string")
)
var stdout *bufio.Writer
func main() {
}
//export dodo
func dodo(fd int) {
file := os.NewFile(uintptr(fd), "file descriptor")
if file == nil {
return
}
do(file)
}
func do(file *os.File) {
in := bufio.NewReader(file)
str := make([]rune, 0, *max)
filePos := int64(0)
print := func() {
if len(str) >= *min {
s := string(str)
// if *offset {
// fmt.Printf("%s:#%d:\t%s\n", name, filePos-int64(len(s)), s)
// } else {
fmt.Println(s)
// }
}
str = str[0:0]
}
for {
var (
r rune
wid int
err error
)
// One string per loop.
for ; ; filePos += int64(wid) {
r, wid, err = in.ReadRune()
if err != nil {
if err != io.EOF {
log.Print(err)
}
return
}
if !strconv.IsPrint(r) || *ascii && r >= 0xFF {
print()
continue
}
// It's printable. Keep it.
if len(str) >= *max {
print()
}
str = append(str, r)
}
}
}
构建代码(Linux):
go build -o libstrings.so -buildmode=c-shared .
这个命令会生成libstrings.h
和libstrings.so
文件。
下面是一个使用libstrings.so
的示例程序some.c
:
// perror
#include <stdio.h>
// open and O_RDONLY
#include <fcntl.h>
// close
#include <unistd.h>
// dodo
#include "libstrings.h"
int main(int argc, char **argv) {
int fd = open("go.mod", O_RDONLY);
if (fd < 0) {
perror("Failed to open file");
return 1;
}
dodo(fd);
close(fd);
return 0;
}
构建:
gcc -o some.exe some.c -L ./ -lstrings
执行:
LD_LIBRARY_PATH=. ./some.exe
结果:它按预期打印了go.mod
文件的内容。
module example.org
go 1.19
英文:
Cgo doesn't support mapping structures to C. Actually, all you can use in the exported functions is strings, integers and native C types.
Instead of os.File
the calling function can pass file decriptor. It is an integer.
I added func dodo(fd int)
to your code and export this function instead of do
.
package main
import (
"C"
"bufio"
"flag"
"fmt"
"io"
"log"
"os"
"strconv"
)
var (
min = flag.Int("min", 6, "minimum length of UTF-8 strings printed, in runes")
max = flag.Int("max", 256, "maximum length of UTF-8 strings printed, in runes")
ascii = flag.Bool("ascii", false, "restrict strings to ASCII")
offset = flag.Bool("offset", false, "show file name and offset of start of each string")
)
var stdout *bufio.Writer
func main() {
}
//export dodo
func dodo(fd int) {
file := os.NewFile(uintptr(fd), "file descriptor")
if file == nil {
return
}
do(file)
}
func do(file *os.File) {
in := bufio.NewReader(file)
str := make([]rune, 0, *max)
filePos := int64(0)
print := func() {
if len(str) >= *min {
s := string(str)
// if *offset {
// fmt.Printf("%s:#%d:\t%s\n", name, filePos-int64(len(s)), s)
// } else {
fmt.Println(s)
// }
}
str = str[0:0]
}
for {
var (
r rune
wid int
err error
)
// One string per loop.
for ; ; filePos += int64(wid) {
r, wid, err = in.ReadRune()
if err != nil {
if err != io.EOF {
log.Print(err)
}
return
}
if !strconv.IsPrint(r) || *ascii && r >= 0xFF {
print()
continue
}
// It's printable. Keep it.
if len(str) >= *max {
print()
}
str = append(str, r)
}
}
}
Build the code (Linux):
go build -o libstrings.so -buildmode=c-shared .
This command produced libstrings.h
and libstrings.so
Example some.c
program that uses libstrings.so
// perror
#include <stdio.h>
// open and O_RDONLY
#include<fcntl.h>
// close
#include <unistd.h>
// dodo
#include "libstrings.h"
int main(int argc, char **argv) {
int fd = open("go.mod", O_RDONLY);
if (fd < 0) {
perror("Failed to open file");
return 1;
}
dodo(fd);
close(fd);
return 0;
}
Build:
gcc -o some.exe some.c -L ./ -lstrings
Execute:
LD_LIBRARY_PATH=. ./some.exe
Result: it prints the contents of go.mod
file as expected.
module example.org
go 1.19
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论