github.com/rclone/rclone@v1.66.1-0.20240517100346-7b89735ae726/lib/buildinfo/arch.go (about)

     1  package buildinfo
     2  
     3  import (
     4  	"runtime"
     5  
     6  	"golang.org/x/sys/cpu"
     7  )
     8  
     9  // GetSupportedGOARM returns the ARM compatibility level of the current CPU.
    10  //
    11  // Returns the integer value that can be set for the GOARM variable to
    12  // build with this level as target, a value which normally corresponds to the
    13  // ARM architecture version number, although it is the floating point hardware
    14  // support which is the decicive factor.
    15  //
    16  // Only relevant for 32-bit ARM architectures, where GOARCH=arm, which means
    17  // ARMv7 and lower (ARMv8 is GOARCH=arm64 and GOARM is not considered).
    18  // Highest possible value is therefore 7, while other possible values are
    19  // 6 (for ARMv6) and 5 (for ARMv5, which is the lowest currently supported
    20  // in go. Returns value 0 for anything else.
    21  //
    22  // See also:
    23  //
    24  //	https://go.dev/src/runtime/os_linux_arm.go
    25  //	https://github.com/golang/go/wiki/GoArm
    26  func GetSupportedGOARM() int {
    27  	if runtime.GOARCH == "arm" && cpu.Initialized {
    28  		// This CPU is an ARM (32-bit), and cpu.Initialized true means its
    29  		// features could be retrieved on current GOOS so that we can check
    30  		// for floating point hardware support.
    31  		if cpu.ARM.HasVFPv3 {
    32  			// This CPU has VFPv3 floating point hardware, which means it can
    33  			// run programs built with any GOARM value, 7 and lower.
    34  			return 7
    35  		} else if cpu.ARM.HasVFP {
    36  			// This CPU has VFP floating point hardware, but not VFPv3, which
    37  			// means it can run programs built with GOARM value 6 and lower,
    38  			// but not 7.
    39  			return 6
    40  		}
    41  		// This CPU has no VFP floating point hardware, which means it can
    42  		// only run programs built with GOARM value 5, which is minimum supported.
    43  		// Note that the CPU can still in reality be based on e.g. ARMv7
    44  		// architecture, but simply lack hardfloat support.
    45  		return 5
    46  	}
    47  	return 0
    48  }
    49  
    50  // GetArch tells the rclone executable's architecture target.
    51  func GetArch() string {
    52  	// Get the running program's architecture target.
    53  	arch := runtime.GOARCH
    54  
    55  	// For ARM architectures there are several variants, with different
    56  	// inconsistent and ambiguous naming.
    57  	//
    58  	// The most interesting thing here is which compatibility level of go is
    59  	// used, as controlled by GOARM build variable. We cannot in runtime get
    60  	// the actual value of GOARM used for building this program, but we can
    61  	// check the value supported by the current CPU by calling GetSupportedGOARM.
    62  	// This means we return information about the compatibility level (GOARM
    63  	// value) supported, when the current rclone executable may in reality be
    64  	// built with a lower level.
    65  	//
    66  	// Note that the kernel architecture, as returned by "uname -m", is not
    67  	// considered or included in results here, but it is included in the output
    68  	// from function GetOSVersion. It can have values such as armv6l, armv7l,
    69  	// armv8l, arm64 and aarch64, which may give relevant information. But it
    70  	// can also simply have value "arm", or it can have value "armv7l" for a
    71  	// processor based on ARMv7 but without floating point hardware - which
    72  	// means it in go needs to be built in ARMv5 compatibility mode (GOARM=5).
    73  	if arch == "arm64" {
    74  		// 64-bit ARM architecture, known as AArch64, was introduced with ARMv8.
    75  		// In go this architecture is a specific one, separate from other ARMs.
    76  		arch += " (ARMv8 compatible)"
    77  	} else if arch == "arm" {
    78  		// 32-bit ARM architecture, which is ARMv7 and lower.
    79  		// In go there are different compatibility levels represented by ARM
    80  		// architecture version number (like 5, 6 or 7).
    81  		switch GetSupportedGOARM() {
    82  		case 7:
    83  			arch += " (ARMv7 compatible)"
    84  		case 6:
    85  			arch += " (ARMv6 compatible)"
    86  		case 5:
    87  			arch += " (ARMv5 compatible, no hardfloat)"
    88  		}
    89  	}
    90  	return arch
    91  }