cgo翻译

command cgo

Cgo支持创建可以调用C代码的Go包。

在go command中使用cgo

为了在常规go代码中使用cgo,需要引入pseudo-package “C”。然后,Go代码可以引用诸如类型C.size_t,变量C.stdout或函数C.putchar。

如果在导入“ C”后立即添加注释,则在编译程序包的C部分时,将该注释(称为前导)用作标头。例如:

// #include <stdio.h>
// #include <errno.h>
import "C"

序言可以包含任何C代码,包括函数,变量声明和定义。然后可以从Go代码中引用这些内容,就好像它们是在package“ C”中定义的。在序言中声明的所有变量都可以使用,即使它们以小写字母开头。例外:前导中的静态变量可能无法从Go代码中引用;但是允许使用静态函数。

有关示例,请参见 G O R O O T / m i s c / c g o / s t d i o 和 GOROOT/misc/cgo/stdio和 GOROOT/misc/cgo/stdioGOROOT/misc/cgo/gmp。看到 有关使用cgo的简介:https 😕/golang.org/doc/articles/c_go_cgo.html 。

在这些注释中,可以使用伪#cgo指令定义CFLAGS,CPPFLAGS,CXXFLAGS,FFLAGS和LDFLAGS,以调整C,C ++或Fortran编译器的行为。多个指令中定义的值被串联在一起。该指令可以包括一系列构建约束,影响系统的这些约束满足如下约束(有关约束语法的详细信息,请参阅https://golang.org/pkg/go/build/#hdr-Build_Constraints)。例如:

// #cgo CFLAGS: -DPNG_DEBUG=1
// #cgo amd64 386 CFLAGS: -DX86=1
// #cgo LDFLAGS: -lpng
// #include <png.h>
import "C"

另外,CPPFLAGS和LDFLAGS可以通过pkg-config工具使用’: 如‘#cgo pkg-config:’指令后跟软件包名称。例如:

// #cgo pkg-config: png cairo
// #include <png.h>
import "C"

可以通过设置PKG_CONFIG环境变量来更改默认的pkg-config工具。

出于安全原因,仅允许使用有限的标志集,尤其是-D,-U,-I和-l。要允许其他标志,请将CGO_CFLAGS_ALLOW设置为与新标志匹配的正则表达式。要禁止本应允许的标志,请将CGO_CFLAGS_DISALLOW设置为与必须禁止的参数匹配的正则表达式。在这两种情况下,正则表达式都必须匹配完整的参数:要允许-mfoo = bar,请使用CGO_CFLAGS_ALLOW =’-mfoo.*’,而不仅仅是CGO_CFLAGS_ALLOW =’-mfoo’。类似命名的变量控制适用于CPPFLAGS,CXXFLAGS,FFLAGS和LDFLAGS。

同样出于安全原因,只允许使用有限的一组字符,特别是数字字符和一些符号(例如‘.’),这些符号将不会以意想不到的方式进行解释。尝试使用禁止的字符将报错"malformed #cgo argument"。

构建时,将CGO_CFLAGS,CGO_CPPFLAGS,CGO_CXXFLAGS,CGO_FFLAGS和CGO_LDFLAGS环境变量添加到从这些指令派生的flags。为特定程序包指定的flags应使用指令而不是环境变量,以便在未修改的环境中构建工程。从环境变量获得的flags不受上述安全限制的约束。

软件包中的所有cgo CPPFLAGS和CFLAGS伪指令被串联在一起,并用于编译该软件包中的C文件。程序包中的所有CPPFLAGS和CXXFLAGS伪指令被串联在一起,并用于编译该程序包中的C ++文件。程序包中的所有CPPFLAGS和FFLAGS指令都已连接在一起,并用于编译该程序包中的Fortran文件。程序中任何程序包中的所有LDFLAGS伪指令在链接时被串联并使用。所有pkg-config伪指令被串联并同时发送到pkg-config,以添加到每个适当的命令行flags。

解析cgo指令后,任何出现的字符串$ {SRCDIR}都将替换为包含源文件的目录的绝对路径。这样可以将预编译的静态库包含在包目录中并正确链接。例如,如果package foo位于目录/go/src/foo中:

// #cgo LDFLAGS: -L${SRCDIR}/libs -lfoo

将扩展为:

// #cgo LDFLAGS: -L/go/src/foo/libs -lfoo

当Go工具看到一个或多个Go文件使用特殊的import "C"时,它将在目录中查找其他非Go文件,并将其编译为Go包的一部分。任何.c,.s,.S或.sx文件都将使用C编译器进行编译。任何.cc,.cpp或.cxx文件都将使用C ++编译器进行编译。任何.f,.F,.for或.f90文件都将使用fortran编译器进行编译。任何.h,.hh,.hpp或.hxx文件都不会单独编译,但是,如果更改了这些头文件,则将重新编译该程序包(包括其非Go源文件)。请注意,对其他目录中文件的更改不会导致重新编译软件包,因此,该软件包的所有非Go源代码应存储在软件包目录中,而不是子目录中。默认的C和C ++编译器可以通过CC和CXX环境变​​量进行更改,分别; 这些环境变量可能包括命令行选项。

在系统上进行本地创建时,默认情况下将启用cgo工具。交叉编译时默认情况被禁用。您可以通过在运行go工具时设置CGO_ENABLED环境变量来控制它:将其设置为1以启用cgo,将其设置为0以禁用它。如果启用了cgo,go工具将设置构建约束“ cgo”。import “C"暗含“ cgo”构建约束,就好像文件说”// +build cgo"。因此,如果禁用了cgo,则go工具将不会构建import “C” 的文件。(有关构建约束的更多信息,请参见https://golang.org/pkg/go/build/#hdr-Build_Constraints)。

交叉编译时,必须指定C交叉编译器供cgo使用。您可以通过在使用make.bash构建工具链时设置通用CC_FOR_TARGET或更具体的CC_FOR_KaTeX parse error: Expected group after '_' at position 7: {GOOS}_̲{GOARCH} 环境变量(例如, CC_FOR_linux_arm)来完成此操作,也可以在您运行go工具时随时设置CC环境变量。

CXX_FOR_TARGET,CXX_FOR_KaTeX parse error: Expected group after '_' at position 7: {GOOS}_̲{GOARCH}和CXX环境变​​量对于C ++代码的工作方式相似。

go运用c

在Go文件中,可以在Go的关键字中加下划线来访问C的结构字段名称(即Go中的关键字):如果x指向具有名为type"的字段的C结构,则x._type将访问该字段。无法在Go中表示的C结构字段(例如bit fields或未对齐的数据)在Go结构中被省略,由适当的填充替换以到达下一个字段或结构体的末尾。

标准C数值类型的名为C.char,C.schar(有符号字符),C.uchar(无符号字符),C.short,C.ushort(无符号短整型),C.int,C.uint( unsigned int),C.long,C.ulong(无符号long),C.longlong(long long),C.ulonglong(无符号long long),C.float,C.double,C.complexfloat(复数float)和C.complexdouble(复数double)。C类型的void *由Go的unsafe.Pointer表示。C类型__int128_t和__uint128_t用 '[16]byte’表示。

在Go中通常由指针类型表示的一些特殊C类型由uintptr表示。请参阅下面的特殊情况部分。

要直接访问struct,union或enum类型,,为其前缀struct_,union_或enum_, 就像C.struct_stat一样。

任何C类型T的大小都可以通过C.sizeof_T获得。就像C.sizeof_struct_stat一样。

对于任意C function(即使void functions)都可以通过多个赋值文本的方式获取返回值(如果有)和 C errno 变量 error (使用 '_'来跳过void函数返回的void)。例如

n, err = C.sqrt(-1)
_, err := C.voidFunc()
var n, err = C.sqrt(1)

当前不支持调用C函数指针,但是您可以声明Go变量,该变量包含C函数指针,并将它们在Go和C之间来回传递。C代码可能调用从Go接收到的函数指针。例如:

package main

// typedef int (*intFunc) ();
//
// int
// bridge_int_func(intFunc f)
// {
//		return f();
// }
//
// int fortytwo()
// {
//	    return 42;
// }
import "C"
import "fmt"

func main() {
	f := C.intFunc(C.fortytwo)
	fmt.Println(int(C.bridge_int_func(f)))
	// Output: 42
}

在C语言中,写为固定大小数组的函数参数实际上需要一个指向数组第一个元素的指针。C编译器知道此调用约定并相应地调整了调用,但是Go不能。在Go中,必须将指针显式传递第一个元素的指针:‘C.f(&C.x[0])’。

不支持调用可变C函数。通过使用C函数包装器可以避免这种情况。例如:

package main

// #include <stdio.h>
// #include <stdlib.h>
//
// static void myprint(char* s) {
//   printf("%s\n", s);
// }
import "C"
import "unsafe"

func main() {
	cs := C.CString("Hello from stdio")
	C.myprint(cs)
	C.free(unsafe.Pointer(cs))
}

几个函数通过复制数据实现了在Go和C类型之间进行转换。在pseudo-Go定义中:

// Go string to C string
// The C string is allocated in the C heap using malloc.
// It is the caller's responsibility to arrange for it to be
// freed, such as by calling C.free (be sure to include stdlib.h
// if C.free is needed).
func C.CString(string) *C.char

// Go []byte slice to C array
// The C array is allocated in the C heap using malloc.
// It is the caller's responsibility to arrange for it to be
// freed, such as by calling C.free (be sure to include stdlib.h
// if C.free is needed).
func C.CBytes([]byte) unsafe.Pointer

// C string to Go string
func C.GoString(*C.char) string

// C data with explicit length to Go string
func C.GoStringN(*C.char, C.int) string

// C data with explicit length to Go []byte
func C.GoBytes(unsafe.Pointer, C.int) []byte

作为一种特殊情况,C.malloc不会直接调用C库malloc,而是会调用Go heler function,该函数包装C库malloc但保证永不返回nil。如果C的malloc指示内存不足,则helper function会使程序崩溃,就像Go本身内存不足时一样。因为C.malloc不会失败,所以它没有返回errno的两个结果的形式。

c引用go

Go函数可以通过以下方式导出以供C代码使用:

//export MyFunction
func MyFunction(arg1, arg2 int, arg3 string) int64 {...}

//export MyFunction2
func MyFunction2(arg1, arg2 int, arg3 string) (int64, *C.char) {...}

它们将以C代码形式提供:

extern GoInt64 MyFunction(int arg1, int arg2, GoString arg3);
extern struct MyFunction2_return MyFunction2(int arg1, int arg2, GoString arg3);

从cgo输入文件复制的任何序言之后,在_cgo_export.h生成的header中找到。具有多个返回值的函数映射到返回结构的函数。

并非所有的Go类型都能以一种有用的方式映射到C类型。不支持Go结构类型;使用C结构体类型。不支持Go数组类型;使用C指针。

如上所述,使用string类型的go function可以使用前面介绍的C类型_GoString_。_GoString_类型将在序言中自动定义。请注意,C代码无法创建这种类型的值。这仅适用于将字符串值从Go传递到C,然后再传递回Go的情况。

在文件中使用// export会限制前导:由于将其复制到两个不同的C输出文件中,因此它不得包含任何定义,而只能包含声明。如果文件同时包含定义和声明,则两个输出文件将产生重复的符号,并且链接器将失败。为避免这种情况,必须将定义放在其他文件或C源文件的前言中。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值