Go: proposal: add preprocessing or macro to enable conditional compilation like C

Created on 23 Oct 2019  路  8Comments  路  Source: golang/go

The compiler supports only tags and file suffix for conditional compilation, but this isn't enough to handle complex/partial code modifications. Suppose we're forking an open source project and want to track or disable anything we've made under certain conditions, it is impossible without advanced conditional compilation.

FrozenDueToAge Proposal

Most helpful comment

Go explicitly rejects the complexity of the C preprocessor.
Build tags let you opt whole files in and out of the build to get some conditional compilation.
The reason for working at the file level is so that the individual files are known to contain actual Go code, so that tools like gofmt and goimports and tons of others can pick up source code, work on it on my behalf, and write it back down. Once you put preprocessor conditionals in at line granularity, that all basically goes out the window.

I admit and even apologize for the fact that in certain cases it is more work to use build tags to work at file granularity than it would be to use #ifdefs and work at line granularity. But what we get in return for this occasional nuisance, in terms of readability but especially the ability for tools to help us maintain our programs, more than makes up for it.

This was a day one fundamental decision about Go. We are very unlikely to change this.

All 8 comments

This issue in its current form does not have enough detail to be a proposal.

If you want to describe a general area for improvement, please add an experience report instead.

Otherwise, please describe the specific changes you would like to see, including the motivation or background, syntax or API signatures, and concrete examples (ideally drawn from experience reports).

This is an idea or suggestion yet, basically enhance the build tags to support partial conditional compliation. Would you please give me an example of acceptable proposal?

I have spent a fair amount of time working on C projects that make heavy use of conditional compilation via directives, including doing things like:

if ( (condition1 != 1)
#ifdef ENABLE_COMPONENT_2
  && (condition2 > 3)
#endif
  && (!condition3)) {
    ...  

and I find them absolutely dreadful to deal with.

Code readability in particular is not great, and I've always found hard to parse and understand directive-heavy code, especially when it's used at expression-level (like in the example above).

If you write a proposal, you should specify at what "level" your proposed macros would be allowed.

  • Right now, we have file-level build tags; which are not very flexible, but are also harder to abuse.
  • Function-level directives (i.e. they disable whole functions) are not more powerful than file-level build tags (just group the functions in files and use build tags)
  • Allow directives at statement-level?
  • Allow directives at expression-level (like in the C example above)?

You can always set consts in build-tag conditional files, and then use normal if statements in your unconditional files. That ends up more readable than most preprocessor-using C code anyway.

Thanks all!

I'm opening this issue because I've noticed the build tags are suported in Go to enable file level conditional compilation. But as @ALTree said, the "build tags currently are not very flexible". It currently works as follows:

file linux.go

// +build linux

func Foo()

file windows.go

// +build windows

func Bar()

What I'm proposing is to have the conditional compilation acts as following:

file c.go

type Foobar struct {
// +build windows
    windows uint32
// -build windows

// +build linux
     linux string
// -build linux

    abc string
}

If I build the c.go with tag 'linux', I hope the Foobar struct will be like this:

type Foobar struct {
     linux string
     abc string
}

@bradfitz Having a global const to control the compliation is restricted because it only works within methods.

All in one. I'm propsing to enhance the build tags to enable conditional compilation at the 'statement-level'.

Motivation:

  1. To handle platform specified problems like the 'windows-linux' example in 'c.go' above.
  2. To track our modification to a third party project and we can disbale our improvements at any time temporarily just with a build flag.
  3. To enable flexible logic controls outside methods.

Go explicitly rejects the complexity of the C preprocessor.
Build tags let you opt whole files in and out of the build to get some conditional compilation.
The reason for working at the file level is so that the individual files are known to contain actual Go code, so that tools like gofmt and goimports and tons of others can pick up source code, work on it on my behalf, and write it back down. Once you put preprocessor conditionals in at line granularity, that all basically goes out the window.

I admit and even apologize for the fact that in certain cases it is more work to use build tags to work at file granularity than it would be to use #ifdefs and work at line granularity. But what we get in return for this occasional nuisance, in terms of readability but especially the ability for tools to help us maintain our programs, more than makes up for it.

This was a day one fundamental decision about Go. We are very unlikely to change this.

@rsc I got your idea. I just thought build tags is an enhancement of file suffix conditional compilation so it might conditional compilation in statement-level. I've written a tool for myself to meet my requirements. I'm closing this proposal, thanks.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

dominikh picture dominikh  路  3Comments

OneOfOne picture OneOfOne  路  3Comments

gopherbot picture gopherbot  路  3Comments

michaelsafyan picture michaelsafyan  路  3Comments

mingrammer picture mingrammer  路  3Comments