Golang conditional compilation
GoBuildGo BuildGo Problem Overview
I've got a trouble with conditional compilation in Go 1.
Here is my test code. Is there anything I misunderstand about the "// +build" constraint and the "-tags" flag?
main1.go
// +build main1
package main
import (
"fmt"
)
func main() {
fmt.Println("This is main 1")
}
main2.go
// +build main2
package main
import (
"fmt"
)
func main() {
fmt.Println("This is main 2")
}
when running "go build", I still got compile error
$ go build -tags 'main1'
# test
./main2.go:8: main redeclared in this block
previous declaration at ./main1.go:8
Go Solutions
Solution 1 - Go
You must follow // +build XXX
with a blank line.
In my brief search, I couldn't find where/if this is documented. But the source clearly calls it out
Solution 2 - Go
> Package build
>
> Build Constraints
>
> A build constraint is a line comment beginning with the directive
> +build
that lists the conditions under which a file should be
> included in the package. Constraints may appear in any kind of source
> file (not just Go), but they must appear near the top of the file,
> preceded only by blank lines and other line comments.
>
> To distinguish build constraints from package documentation, a series
> of build constraints must be followed by a blank line.
Add a blank line after the build constraint. For example,
// +build main1
package main
import (
"fmt"
)
func main() {
fmt.Println("This is main 1")
}
Solution 3 - Go
The // +build
tag, used up to Go 1.17, must be followed by an empty line:
// +build main1
package main
Starting from Go 1.17, conditional build tags are able to use //go:build
lines that support boolean expressions instead of the old // +build
lines.
Main improvement
//go:build
comment format is consistent with other go directives as//go:embed
,//go:generate
,//go:noinline
, etc.- the syntax for boolean expressions between build tags is now standardized, using
&&
and||
operators
Syntax comparison
Expression | // +build |
//go:build |
---|---|---|
OR | // +build foo bar (space-separated) |
`//go:build foo |
AND | // +build foo,bar |
//go:build foo && bar |
NOT (unchanged) | // +build !foo |
//go:build !foo |
Multiline comments
More complex boolean expressions can make use of parenthesis, whereas before it required multiline comments:
From:
// +build foo bar
// +build 386
to:
//go:build (foo || bar) && 386
Additionally, with //go:build
, multiple directives over more than one line are now disallowed.
Automatic formatting
-
running
go fmt
on a source file with a// +build
directive will automatically add the matching//go:build
one. -
running
go fmt
on a source file with a//go:build
directive in the wrong place will automatically fix it. So now your issue would be solved by simply runninggofmt -w main.go
Source: Go 1.17 build constraints draft design. (Currently still a draft even if Go 1.17 is officially released)
Solution 4 - Go
Right, you must leave a blank line, not exactly after // +build XXX
but before package main
because all the comment lines before the line declaring the package are considered to be the description of the package and parsed by godoc
.
Solution 5 - Go
From the Build Constraints docs:
> To distinguish build constraints from package documentation, a series of build constraints must be followed by a blank line.