draft design for // +build replacement

381 views
Skip to first unread message

Russ Cox

unread,
Jun 30, 2020, 4:04:45 PM6/30/20
to golang-nuts
Hi all,

I've posted a draft design for replacing // +build lines with //go:build lines that support standard boolean expression syntax. It is a draft design I'm circulating for feedback, not an official proposal. (I certainly hope it will be well received and can be made into a proposal, but that's not where we are today.)

If you are interested, there is a doc and a video, linked below. As an experiment, I'd like to try using Reddit for the discussion, also linked below. The idea is that proper threading support should scale better than GitHub or a single large mail thread here would. But for those who don't do Reddit, I will keep an eye on this thread and reply as best I can.

Thanks!

Best,
Russ

roger peppe

unread,
Jun 30, 2020, 7:11:02 PM6/30/20
to Russ Cox, golang-nuts
LGTM. This is a welcome change. I often need to look up how to spell "// +build" currently :)

One thing I'd really like to see is the eventual deprecation of filename-based build constraints (e.g. file_linux.go).
They make it hard for users (not everyone knows the name of all architectures), hard for tooling (tools
need to maintain a list of current architectures) and potentially compatibility-breaking (adding
a new architecture can change the meaning of existing files). Could we eventually mandate
in-file build constraints instead?

  cheers,
    rog.


--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/CAA8EjDTO1NX%3DacOTqEfD%3D6pumUWzNNcGO%2BsPMrQVYdO0cmWsvQ%40mail.gmail.com.

Axel Wagner

unread,
Jun 30, 2020, 7:36:18 PM6/30/20
to roger peppe, Russ Cox, golang-nuts
On Wed, Jul 1, 2020 at 1:10 AM roger peppe <rogp...@gmail.com> wrote:
LGTM. This is a welcome change. I often need to look up how to spell "// +build" currently :)

One thing I'd really like to see is the eventual deprecation of filename-based build constraints (e.g. file_linux.go).
They make it hard for users (not everyone knows the name of all architectures), hard for tooling (tools
need to maintain a list of current architectures) and potentially compatibility-breaking (adding
a new architecture can change the meaning of existing files). Could we eventually mandate
in-file build constraints instead?

I think *mandating* this could be considered a backwards incompatible change (the only real counter-argument is that it's "just tooling"). AIUI, Russ' design doesn't actually remove `// +build` for this reason, but only deprecates it with automatic re-writing.
Of course, nothing would prevent us from doing the same - deprecating purely filename-based constraints and have `gofmt` actively add build tags. Note that the filenames wouldn't go away anyways; you still need separate files, so you still need separate names. You wouldn't need *these specific* names, but you'd probably end up with very similar ones.

If you'd indeed suggest removing file name based constraints altogether, I'd argue that it should probably happen in this same process (not "eventually" :) ) - it involves touching ~every Go package with constraints anyway, so having to only do this once would probably be preferable.
 

  cheers,
    rog.


On Tue, 30 Jun 2020 at 21:04, Russ Cox <r...@golang.org> wrote:
Hi all,

I've posted a draft design for replacing // +build lines with //go:build lines that support standard boolean expression syntax. It is a draft design I'm circulating for feedback, not an official proposal. (I certainly hope it will be well received and can be made into a proposal, but that's not where we are today.)

If you are interested, there is a doc and a video, linked below. As an experiment, I'd like to try using Reddit for the discussion, also linked below. The idea is that proper threading support should scale better than GitHub or a single large mail thread here would. But for those who don't do Reddit, I will keep an eye on this thread and reply as best I can.

Thanks!

Best,
Russ

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/CAA8EjDTO1NX%3DacOTqEfD%3D6pumUWzNNcGO%2BsPMrQVYdO0cmWsvQ%40mail.gmail.com.

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.

Axel Wagner

unread,
Jun 30, 2020, 7:43:52 PM6/30/20
to roger peppe, Russ Cox, golang-nuts
Hm, though I guess in terms of compatibility, it should be mentioned that according to the design, this currently valid program wouldn't build at go1.(N-1) (and later, unless the `foo` build tag is specified): https://play.golang.org/p/436NUYC7rno
If that's okay, then maybe mandating build tags is too?

ben...@gmail.com

unread,
Jun 30, 2020, 7:54:43 PM6/30/20
to golang-nuts
FWIW, I *like* the filename-based constraints. I can look at the source for the OS package (https://golang.org/src/os/) and immediately go to the _windows.go files to see how they do things on Windows (for example). It's really obvious from the directory listing, and I don't have to dig into the files to see what the build constraint is.

Then again, if Go got rid of filename-based constraints, people could still name their files like that for visibility purposes, but the actual build constraint would be in "// +build" or "//go:build" rules in the file itself.

-Ben

Sam Whited

unread,
Jun 30, 2020, 9:02:14 PM6/30/20
to golan...@googlegroups.com
I agree. I like the filename based constraints, but having both is
annoying and since the comment based constraints are more flexible I
think they'd have to be the ones to stay. I frequently find myself
looking for constraints by grepping for whatever it is I want, but if I
have filename based constraints I have to do a find as well. Having one
or another but not both would make my life easier in a small but
meaningful way.

—Sam

go je

unread,
Jul 1, 2020, 3:57:25 AM7/1/20
to Sam Whited, golang-nuts
This might as well replace makefiles for testing and other tools. or similar formats.

//go:test devenv
func TestFoo(t *testing.T) {}

//go:test devenv -failfast -short -cover ./...
func TestFoo2(t *testing.T) {}

//go:test prod
func TestProduction(t *testing.T) {}

$  go test devenv

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.

Russ Cox

unread,
Jul 1, 2020, 2:07:52 PM7/1/20
to Sam Whited, golang-nuts
For what it's worth, I am (unsurprisingly) a big fan of the filename-based constraints. It's a lightweight convention that has served us incredibly well. I really like being able to see in a directory listing which files go with what. It would be unfortunate if we had to put the redundant info inside files and then hope that the info inside matched the file names and/or introduce consistency checks. A single point of truth always seems better to me than verified redundancy.

But I certainly hear your point about what happens when a new OS comes along (plan10, say) and none of the old Go releases know that foo_plan10.go should be ignored except when GOOS=plan10. If we were going to seriously consider fixing the filename-based constraint ambiguity (probably not today), there are at least three possible paths forward. 

1. Remove the ambiguity by making _foo in a filename never a constraint, as you've proposed. For me, this throws the baby out with the bathwater.

2. Remove the ambiguity by making _foo in a filename always a constraint. If a toolchain doesn't know what foo means, then the constraint is clearly not satisfied. I think this would be too painful to deploy. I ran a scan last night and there are just far too many files using underscores for non-constraints today.

3. Two steps:
3a. Make the go command apply a list based on the go version in go.mod, so that we can say "as of Go 1.16, plan10 is a recognized GOOS". Then when building old code, any existing foo_plan10.go file doesn't get reinterpreted. 
3b. Remove uncertainty in tools by making them ask the go command (perhaps using x/tools/go/packages), which always knows.

I think I would lean more toward 3 than 1 or 2. As someone noted, we're certainly not going to start requiring //go:build test in every *_test.go file - that convention won't go away. But then what happens when the next thing comes along? What if for fuzzing turns out to be very helpful to have a foo_fuzz.go convention? (Probably not, but what about the next thing?) If we get all the tools asking the go command, then that kind of change is easy to deploy. (Similarly, files with import "C" only apply when the cgo tag is set. I don't think it makes sense for tools to be hard-coding that rule, nor would it make sense at this point to require an explicit //go:build cgo. If tools ask the go command instead of trying to rederive these kinds of things themselves, it's no problem at all.)

I would be very interested to hear about which tools can't ask the go command for this info, and why, and what we can do to address that.

Best,
Russ

Bakul Shah

unread,
Jul 1, 2020, 2:21:19 PM7/1/20
to Russ Cox, Sam Whited, golang-nuts
4. Use two underscores for constraints. At least new constraints.

Aside: Are you plantin' an idea about Plan10?

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.

jimmy frasche

unread,
Jul 1, 2020, 2:55:48 PM7/1/20
to Bakul Shah, Russ Cox, Sam Whited, golang-nuts
Running find -name "*_*.go" | xargs grep " +build" on goroot shows a
lot of files with redundant build tags or additional constraints not
present in the file name so they don't seem like much of a single
point of truth.

I'd be fine with removing file names sometimes implying build tags.
Add build tags from the filename to the go:build line and after go1.X
stop getting build tags from the file name.

There would still be special cases like _test and cgo but there would
be fewer special cases. Option 3 looks like a solid plan to handle the
hypothetical _fuzz even if otherwise things converge on go:build.
> To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/443ACF21-0A34-484D-B1E3-273E6226E96C%40iitbombay.org.

Bakul Shah

unread,
Jul 1, 2020, 3:19:16 PM7/1/20
to jimmy frasche, Russ Cox, Sam Whited, golang-nuts
My suggestion was a variation on rsc's #2. Still a simple rule that is easy
for people to remember and doesn't require asking the go command.
Prefer a simple rule compared to any intermediation by a program.

Amnon

unread,
Jul 7, 2020, 2:56:36 AM7/7/20
to golang-nuts
A sensible, well thought out, design.

My main worry is that we will come unstack in places that are using versions of the Go toolchain older than N-2.
Is there any reason for them not to upgrade? No
Should they upgrade? Definitely
But some still haven't.

Perhaps we should force them to upgrade to a supported version.
Perhaps we should say that if they don't upgrade, then any pain they suffer will be their own fault.
But these are decisions that we must consciously take.

Russ Cox

unread,
Jul 7, 2020, 1:35:12 PM7/7/20
to Amnon, golang-nuts
For what it's worth, they need not ever upgrade as long as they keep running old Go code. 

If they do upgrade to newer Go code without also upgrading the Go distribution, there is already the possibility of build breakage due to the new code making use of new standard library functions (breakage = undefined symbols) or language features (breakage = syntax or type error). The new //go:build lines are not that much different: if they are present alone in a file and are not respected, you get a break, not silently wrong behavior (brekage = duplicate definitions for a symbol, almost always). 

Best,
Russ
Reply all
Reply to author
Forward
0 new messages