Go Compiler Directives
Go compiler accepts some directives with comments that interacts source code while compiling process. I’d like to talk about some directives I’ve tried before.
go:linkname
Go documents says;
“The//go: linkname directive instructs the compiler to use “importpath.name” as the object file symbol name for the variable or function declared as “localname” in the source code.”
Let’s try with an example, really basic.
example/main.go
package main
import (
"fmt"
"example/ex"
)
func main() {
fmt.Println(ex.MyFunc())
}
Create func.go in ex package.
example/ex/func.go
package ex
import _ "unsafe"//go:linkname myFuncWithBody example/ex.MyFunc
func myFuncWithBody() string {
return "ok"
}func MyFunc() string
Create any empty “*.s” files in ex package’s directory.
touch test.s
go:norace
This directive prevents race condition warning.
package main
var total int
func add (){
total ++
}
func main() {
for i:=0;i<10;i++ {
go add()
}
}
Above the code returns race contidion warning with “go run -race main.go” since we can override this with “go:norace” directive.
package main
var total int
//go:norace
func add (){
total ++
}
func main() {
for i:=0;i<10;i++ {
go add()
}
}
“go run -race main.go” does not returns any warning for race condition.
go:noinline
From Go’s documents:
“It specifies that calls to the function should not be inlined, overriding the compiler’s usual optimization rules.”
Here is the detailed document about Go’s inlining strategy:
https://medium.com/a-journey-with-go/go-inlining-strategy-limitation-6b6d7fc3b1be
Go compiler’s does some optimizations while your code compiling.
For example
package main
func hello() {
print("hello")
}func main() {
hello()
}
And run
go run -gcflags="-m" main.go
Output:
./main.go:4:6: can inline hello
./main.go:8:6: can inline main
./main.go:9:7: inlining call to hello
We can override this inlining with “go:noinline” directive
package main//go:noinline
func hello() {
print("hello")
}func main() {
hello()
}
Output:
./main.go:7:6: can inline main
Above the output, hello function did not inline.
go:noescape
From go’s documents:
“ It specifies that the function does not allow any of the pointers passed as arguments to escape into the heap or into the values returned from the function.”
This directive means “i trust this, so this function will not escape to heap”.
To use this directive, you should have a function not implemented in go.
//go:noescape
func test() *string // implemented in test.x assembly file.
Bonus: build tags
+build
This directive provides conditional build.
Let’s create two go files.
first.go
// +build firstpackage main
import "fmt"
func init() {
fmt.Println("my first program")
}func main(){
fmt.Println("main function triggered")
}
second.go
// +build secondpackage main
import "fmt"
func init() {
fmt.Println("my second program")
}
And build with “first” tag.
go build -tags first && ./example
Output:
my first program
main function triggered
Build with “second” tag.
go build -tags second && ./example
Output:
my second program
Let’s try with two tags.
// +build first second
Now we tell to go build tool “build who has ‘first’ OR ‘second’ tags” (OR condition)
Change build tags for first.go and second.go
// +build first
to
// +build first,second
Now we tell to go build tool “build who has ‘first,second’ tags” (AND condition)
Last example shows how to use NOT condition.
Let’s change build tag like this:
// +build !first
Now we tell to go build tool “do not build who has ‘first’ tag”.
Bonus: go generate tool
go:generate
package main
import (
"fmt"
)
//go:generate echo "my build process"
func main() {
fmt.Println("hello world")
}
And run “go generate” command.
go generate main.go
Output:
my build process