Golang conditional compilation

GoBuildGo Build

Go 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 running gofmt -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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionTianran ShenView Question on Stackoverflow
Solution 1 - GoaxwView Answer on Stackoverflow
Solution 2 - GopeterSOView Answer on Stackoverflow
Solution 3 - GoblackgreenView Answer on Stackoverflow
Solution 4 - GooutofplutoView Answer on Stackoverflow
Solution 5 - GofeuvanView Answer on Stackoverflow