golang条件编译

可以类比c的#ifndef #define #enif等宏,作用是类似的。

golang条件编译可以用宏(//+build,//go:build。两种写法作用一样,后者适用一些老版本),也可以通过文件名后缀,比如nsenter_linux.go,一个示例。

//go:build linux && !gccgo
// +build linux,!gccgo

package nsenter

/*
#cgo CFLAGS: -Wall
extern void nsexec();
void __attribute__((constructor)) init(void) {
nsexec();
}
*/
import "C"

 1. 多个条件的情况下,","逗号表示and," "空格表示or,"!"表示取反

 2. 注意条件编译指令与packge之间留一个空行。


cgo

通过以上示例可以看到,用cgo或gccgo调用c的方式也挺简单。需要特别关注数据类型的对应关系。


init函数

golang的init函数在main函数之前运行,可以用来做一些初始化工作,规则如下:

1.init函数可以在所有程序执行开始前被调用,并且每个包下可以有多个init函数
2.init函数先于main函数自动执行
3.每个包中可以有多个init函数,每个包中的源文件中也可以有多个init函数
4.init函数没有输入参数、返回值,也未声明,所以无法引用
5.不同包的init函数按照包导入的依赖关系决定执行顺序
6.无论包被导入多少次,init函数只会被调用一次,也就是只执行一次
7.init函数在代码中不能被显示的调用,不能被引用(赋值给函数变量),否则会出现编译错误
8.导入包不要出现循环依赖,这样会导致程序编译失败
9.Go程序仅仅想要用一个package的init执行,我们可以这样使用:import _ “test_xxxx”,导入包的时候加上下划线就ok了
10.包级别的变量初始化、init函数执行,这两个操作都是在同一个goroutine中调用的,按顺序调用,一次一个包
11.init函数不应该依赖任何在main函数里创建的变量,因为init函数的执行是在main函数之前的
12.在init函数中也可以启动goroutine,也就是在初始化的同时启动新的goroutine,这并不会影响初始化顺序
13.复杂逻辑不建议使用init函数,会增加代码的复杂性,可读性也会下降
14.一个源文件下可以有多个init函数,代码比较长时可以考虑分多个init函数
15.编程时不要依赖init的顺序 ​

// main.go
package main

import (
"fmt"
)

func init() {
fmt.Println("init in main")
}

func main() {
fmt.Println("main")
}

// init.go
package main

import (
"fmt"
"os"

_ "eno.com/runc_learn/nsenter"
)

func init() {
fmt.Println("init in init")
if len(os.Args) > 1 && os.Args[1] == "init" {
fmt.Println("init command invoked.")
}
}