goarchitecturecross-platform

What is the right approach to encapsulate platform specific code in Go?


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.


Solution

  • 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.