I want to develop a small Go application, which shows the used key stroke shortcuts to the audience of a presentation.
To hook into the keyboard events I will have to use some platform specific code. What is the Go way to encapsulate platform specific code? I've been searching for keywords like compiler switch or platform modules, but I couldn't really find something about.
The solution to platform specific code is the build constraints.
Note: Prior to Go 1.17 the syntax was a comment line starting with // +build
, but Go 1.17 introduced the //go:build
pragma which is now the preferred way.
A build constraint, also known as a build tag, is a line comment that begins
//go: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. These rules mean that in Go files a build constraint must appear before the package clause.
So basically each platform specific Go code should go into different files, and you can mark each of these Go files with the target they are intended for.
For example if a file contains Linux specific code (e.g. syscalls), start it with:
//go:build linux
If a file contains Windows specific syscalls, start it with:
//go:build windows
A lot more "options" are available, read the linked docs. For example you can specify constraints to the OS, Architecture, Go version, the compiler being used. You can also specify multiple constraints that will be interpreted with logical OR or AND, or you can use negation (e.g. this code is for every target platform except linux).
You can even mark a .go
file to be ignored with the following constraint:
//go:build ignore
Note that build constraints are compiler specific. If a specific compiler does not recognize a build constraint, the compiler will ignore the file. As an example the Go AppEngine SDK comes with a built-in, modified Go compiler which additionally recognizes the
//go:build appengine
constraint, which means the source file is intended for the Google App Engine Platform only. "Regular" Go compilers will ignore the file, giving you the possibility to not have a bunch of compiler errors if someone tries to build the code without the Go AppEngine SDK.
While @icza's answer is definitely the proper authoritative answer to OP's question about condtional compilation, in this specific case a simpler approach may be worthwhile.
Go is a language designed to compile the same (with the same compiler) on every platform, to encourage cross-platform code and library reuse. Go is not C/C++, for which time must be spent to write explicitly cross-platform code.
Of course, the platform agnosticity only goes as far as Go's runtime, and you're trying to capture keypresses, for which there's no real single platform-agnostic solution.
Thus, my simpler suggestion for this use case resembles the following:
package main
import (
"runtime"
kp "kplib"
)
func main () {
switch runtime.GOOS {
case "windows":
kp.WinKey()
case "darwin":
kp.MacKey()
case "linux":
kp.UnixKey()
default:
kp.TryKey()
}
}
With the implicit assurance the hypothetical kplib
will compile everywhere (just be sure to call the right methods on the given platform!).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With