Back in Chapter 3, Go to the Rescue!, we saw that the Go compiler has built-in support for the conditional inclusion of source files based on a system of environment variables and build tags. As an application adds more functionality, especially from a platform-integration perspective, it is possible that the toolkit you have chosen will not provide all of the functionality you are looking for. When this happens, the code will need to be updated to handle platform-specific functionality. To do so, we will use a variation of the conditional build – using well-named files instead of build tags (as used in Chapter 11, Navigation and Multiple Windows). This is easier to read at the project level and should indicate clearly which files will be compiled for which platform.
Let's create a simple example: we want to show a notification, but our code only has the ability to do so on macOS (darwin). We will set up a simple notify() function that does what we want in the notification_darwin.go file:
package main
import (
"log"
"os/exec"
)
func notify(title, content string) {
cmd := exec.Command("osascript", "-e", "display notification ""+content+
"" with title ""+title+""")
err := cmd.Run()
if err != nil {
log.Printf("Error showing notification: %v", err)
}
}
This simple function calls out to the osascript tool, a command-line application bundled with macOS that allows the execution of system scripts. As this file ends with the name _darwin.go, it will only be compiled when we are building for macOS. To compile correctly when building on other platforms, we need to create another file that will be loaded instead, we will call it notification_other.go:
// +build !darwin
package main
import "log"
func notify(title, content string) {
log.Println("Notifications not supported")
}
In this file, we must specify the build condition, as there is no special filename format for all other platforms; here, // +build !darwin means that the file will be included on any platform other than macOS. The method we provide in this file simply logs that the feature is not supported. Finally, we create a simple application launcher named main.go that will call the notify() function:
package main
func main() {
notify("Email", "A new email arrived")
}
Running this code on macOS will result in the expected notification appearing:
On any other operating system, it will log the fallback error message:
We can handle platform-specific code in a way that should be clear to anyone learning the source code. Another developer could decide to add a notification_windows.go file to add support for notifications on Windows. As long as they also update the build rules in notification_other.go, the application will continue to work as expected but with the addition of Windows-based notifications. The benefit of this approach is that it did not require any modifications of existing code to add this new functionality.