Conditional compilation with build tags

suggest change

Build tags allow for limited conditional compilation i.e. compiling different versions of code based on some criteria.

Tags are specified per file, at the top of the file, followed by an empty line and the code.

A typical use case for tags is to provide to implementation of the same functionality and pick the one that is compiled with tags.

For example, if you have 3 files in the directory:

foo_alt.go

// +build alt

package main

func foo() {
	fmt.Printf("This is alternative foo\n")
}

foo.go

// You can have other comments before build tags

// +build !alt

package main

func foo() {
	fmt.Printf("This is regular foo\n")
}

main.go

package main

func main() {
	foo()
}

Compiling without any build tags:

> go build -o main .
> ./main
This is non-alt foo

Compiling with alt build tag:

> go build -tags alt -o main_alt .
> ./main_alt
This is alternative foo

When we specified -tags alt, we compiled foo_alt.go file, because it contains // +build alt directive which tells the build tool to compile the file if build tag alt is provided with -tags option.

We didn't compile foo.go file because it contains // build !alt directive which tells the build to not compile the if build alt is provided.

Similarly, if we didn't specify any build tags for go build command, file foo.go was compiled (because it only says to not compile if alt tag is provided) and foo_alt.go was not compiled.

Argument -tags applies to many commands e..g. go run, go install, go test etc.

Specifying multiple tags

You can specify multiple build constraints (tags):

// +build tag1,tag2 tag3,!tag4
// +build tag5

package foo

This encodes a condition (tag1 AND tag2) OR (tag3 AND (NOT tag4)) AND tag5.

Similarly, for the go command: go build -tags "tag1 tag2".

Ignoring files (excluding from compilation)

// +build ignore

package foo

Predefined build tags

Go toolchain uses several build tags:

Using file name in place of a build tag

An alternative to providing build tag directive in the file is using a file name suffix e.g. foo_windows.go is equivalent of including // +build windows in the file.

Pitfalls

The following doesn't work as expected:

// +build alt
package main

func foo() {
	fmt.Printf("This is alternative foo\n")
}

You need an empty line after build tag line:

// +build alt

package main

Feedback about page:

Feedback:
Optional: your email if you want me to get back to you:



Table Of Contents