How to reliably detect os/platform in Go
Asked Answered
H

10

123

Here's what I'm currently using, which I think gets the job done, but there's got to be a better way:

func isWindows() bool {
    return os.PathSeparator == '\\' && os.PathListSeparator == ';'
}

As you can see, in my case all I need to know is how to detect windows but I'd like to know the way to detect any platform/os.

Play:

http://play.golang.org/p/r4lYWDJDxL

Hatred answered 7/11, 2013 at 22:2 Comment(3)
Current versions of Windows will operate just fine using the Posix separator, which is '/'. You only need backslash for bat scripts and old non-Posix versions of Windows.Layoff
Can you define "current"? I've been burned hard-coding '/' just in the last few weeks...Hatred
Windows 95, 98 ME and all earlier version require backslash. Windows 2000, NT and later accept backslash and forward slash as equivalents. Backslash provides compatibility with older versions, whilst forward slash provides Posix compliance.Layoff
L
201

Detection at compile time

If you're doing this to have different implementations depending on the OS, it is more useful to have separate files with the implementation of that feature and add build tags to each of the files. This is used in many places in the standard library, for example in the os package.

These so-called "Build constraints" or "Build tags" are explained here.

Say you have the constant PATH_SEPARATOR and you want that platform-dependent, you would make two files, one for Windows and one for the (UNIX) rest:

/project/path_windows.go
/project/path_unix.go

The code of these files would then be:

path_windows.go

// +build windows

package project

const PATH_SEPARATOR = '\\'

path_unix.go

// +build !windows

package project

const PATH_SEPARATOR = '/'

You can now access PATH_SEPARATOR in your code and have it platform dependant.

Detection at runtime

If you want to determine the operating system at runtime, use the runtime.GOOS variable:

if runtime.GOOS == "windows" {
    fmt.Println("Hello from Windows")
}

While this is compiled into the runtime and therefore ignores the environment, you can nevertheless be relatively certain that the value is correct. The reason for this is that every platform that is worth distinguishing needs rebuilding due to different executable formats and thus has a new GOOS value.

Lucrece answered 7/11, 2013 at 22:19 Comment(6)
I tried to run this but i get some kind of strange error. path_windows.go:4:24: PATH_SEPARATOR redeclared in this block. previous declaration at path_unix.go:4:24 And i just don't get it... Does the compiler not get it?Shall
@RamonJ.A.Smit you'll need to add build constraints to those files like so: path_unix.go should have // +build !windows and path_windows.go should have // +build windows. I edited the answer above to show where they should go. They must come before the package statement and be followed by a blank line so they are not interpreted as documentation for the package.Chiaroscuro
Thanks for the extra input! Will play with this. Thanks :-)Shall
@TimLewis I can't get this to work for whatever reason. I'm on Windows, and my GetData func in data_windows.go is "redeclared" because of GetData in data_unix.go. Both have proper build contraints (data_windows.go has +build windows and data_unix.go has +build !windows) before the package statement and a blank line afterwards but it still won't work. Any ideas?Tocopherol
Oh I see the problem, my command was go build -o ... cli/*.go so it was building all the go files regardless of build constraints. I changed it to go build -o ... ./cli which worked.Tocopherol
Thank you very much! It helped me. I separated my package "get_info" on 3 parts: get_info, get_info_unix, get_info_windows. And it's worked!Chiropody
T
23

Have you looked at the runtime package? It has a GOOS const: http://golang.org/pkg/runtime/#pkg-constants

Tinware answered 7/11, 2013 at 22:13 Comment(2)
GOOS, in the runtime package, gets set at compile time, and is readable without the Go tools being installed.Tinware
@Matt you are thinking of the environment variable. @Tyler is thinging of runtime.GOOS which will work fine, eg: play.golang.org/p/0dDIEoFXfxTuck
P
12

It's 2022 and the correct answer for go 1.18+ is:

At runtime you want:

if runtime.GOOS == "windows" {
  // windows specific code here...
}

If you need to determine the filesystem path separator character

Use: os.PathSeparator

Examples:

  • c:\program files
  • /usr/local/bin

If you need the Path List separator as used by the PATH environment variable

Use: os.PathListSeparator

Examples:

  • /usr/local/bin:/usr/local:
  • "C:\windows";"c:\windows\system32";
Priapitis answered 7/11, 2013 at 22:2 Comment(0)
V
2

Since this is an older question and answer I have found another solution.

You could simply use the constants defined in the os package. This const returns a rune so you would need to use string conversion also.

string(os.PathSeparator)
string(os.PathListSeparator)

Example: https://play.golang.org/p/g6jnF7W5_pJ

Vanzandt answered 29/4, 2021 at 16:4 Comment(1)
This answer does not show how to detect the platform. The question uses os.PathSeparator and os.PathListSeparator to detect Windows.Johnjohna
B
1

I just stumbled on this looking for something else and noticed the age of this post so I'll add a more updated addition. If you're just trying to handle the correct filepath I would use filepath.Join(). Its takes all of the guesswork out of os issues. If there is more you need, other than just filepath, using the runtime constants (runtime.GOOS & runtime.GOARCH) are the way to go: playground example

Bridgeman answered 15/4, 2020 at 16:11 Comment(0)
P
1

I tested in Go 1.17.1 which really worked for me.

package main

import (
        "fmt"
        "runtime"
)
func main(){
        fmt.Println(runtime.GOOS)
}

Output:
darwin
Protease answered 14/12, 2021 at 6:13 Comment(1)
The same answer is here: https://mcmap.net/q/180421/-how-to-reliably-detect-os-platform-in-goHarmonize
I
1

Use path:

package main
  
// Importing fmt and path/filepath
import (
    "fmt"
    "path/filepath"
)
  
// Calling main
func main() {
    fmt.Println(filepath.Join("/", "/")) // out: /
    fmt.Println(filepath.Join(""))// out: 
    fmt.Println(filepath.Join("dirname", "dirsubname")) // out: dirname/subdirname
    fmt.Println(filepath.Join(".")) // out: .
  
}
  • path - Standard library

Or use GOOS:

os := runtime.GOOS
    switch os {
    case "windows":
        fmt.Println("Windows")
    case "darwin":
        fmt.Println("MAC operating system")
    case "linux":
        fmt.Println("Linux")
    default:
        fmt.Printf("%s.\n", os)
    }
Incardinate answered 19/5, 2023 at 13:35 Comment(0)
D
0

With regards to detecting the platform, you can use Distribution Detector project to detect the Linux distribution being run.

Drawee answered 2/1, 2021 at 18:57 Comment(1)
i am missing the cross platform capability. Might this help #57038803Medievalist
P
0

The first answer from @nemo is the most apropiate, i just wanted to point out that if you are currently a user of gopls language server the build tags may not work as intended.

There's no solution or workaround up to now, the most you can do is change your editor's lsp configs (vscode, neovim, emacs, etc) to select a build tag in order to being able to edit the files with that tag without errors. Editing files with another tag will not work, and trying to select multiple tags fails as well. This is the current progress of the issue github@go/x/tools/gopls

Polson answered 11/3, 2022 at 15:5 Comment(0)
B
-1

I found this library, gets the job done. https://github.com/matishsiao/goInfo

   package main

   import (
       "github.com/matishsiao/goInfo"
   )

   func main() {
        gi := goInfo.GetInfo()
        gi.VarDump()
     }

result:

GoOS: linux
Kernel: Linux
Core: 4.4.0
Platform: unknown
OS: GNU/Linux
Hostname: ec4f6b107fa7
CPUs: 8

play: https://go.dev/play/p/SvgfJ7wcltu

Binah answered 4/4 at 11:25 Comment(1)
Kassab, please don't just post some tool or library as an answer. At least demonstrate how it solves the problem in the answer itself.Woermer

© 2022 - 2024 — McMap. All rights reserved.