xref: /aosp_15_r20/external/swiftshader/tests/regres/llvm/llvm.go (revision 03ce13f70fcc45d86ee91b7ee4cab1936a95046e)
1*03ce13f7SAndroid Build Coastguard Worker// Copyright 2020 The SwiftShader Authors. All Rights Reserved.
2*03ce13f7SAndroid Build Coastguard Worker//
3*03ce13f7SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License");
4*03ce13f7SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License.
5*03ce13f7SAndroid Build Coastguard Worker// You may obtain a copy of the License at
6*03ce13f7SAndroid Build Coastguard Worker//
7*03ce13f7SAndroid Build Coastguard Worker//    http://www.apache.org/licenses/LICENSE-2.0
8*03ce13f7SAndroid Build Coastguard Worker//
9*03ce13f7SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software
10*03ce13f7SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS,
11*03ce13f7SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*03ce13f7SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and
13*03ce13f7SAndroid Build Coastguard Worker// limitations under the License.
14*03ce13f7SAndroid Build Coastguard Worker
15*03ce13f7SAndroid Build Coastguard Worker// Package llvm provides functions and types for locating and using the llvm
16*03ce13f7SAndroid Build Coastguard Worker// toolchains.
17*03ce13f7SAndroid Build Coastguard Workerpackage llvm
18*03ce13f7SAndroid Build Coastguard Worker
19*03ce13f7SAndroid Build Coastguard Workerimport (
20*03ce13f7SAndroid Build Coastguard Worker	"bytes"
21*03ce13f7SAndroid Build Coastguard Worker	"fmt"
22*03ce13f7SAndroid Build Coastguard Worker	"io/ioutil"
23*03ce13f7SAndroid Build Coastguard Worker	"net/http"
24*03ce13f7SAndroid Build Coastguard Worker	"os"
25*03ce13f7SAndroid Build Coastguard Worker	"os/exec"
26*03ce13f7SAndroid Build Coastguard Worker	"path/filepath"
27*03ce13f7SAndroid Build Coastguard Worker	"regexp"
28*03ce13f7SAndroid Build Coastguard Worker	"runtime"
29*03ce13f7SAndroid Build Coastguard Worker	"sort"
30*03ce13f7SAndroid Build Coastguard Worker	"strconv"
31*03ce13f7SAndroid Build Coastguard Worker
32*03ce13f7SAndroid Build Coastguard Worker	"swiftshader.googlesource.com/SwiftShader/tests/regres/util"
33*03ce13f7SAndroid Build Coastguard Worker)
34*03ce13f7SAndroid Build Coastguard Worker
35*03ce13f7SAndroid Build Coastguard Workerconst maxLLVMVersion = 17
36*03ce13f7SAndroid Build Coastguard Worker
37*03ce13f7SAndroid Build Coastguard Worker// Version holds the build version information of an LLVM toolchain.
38*03ce13f7SAndroid Build Coastguard Workertype Version struct {
39*03ce13f7SAndroid Build Coastguard Worker	Major, Minor, Point int
40*03ce13f7SAndroid Build Coastguard Worker}
41*03ce13f7SAndroid Build Coastguard Worker
42*03ce13f7SAndroid Build Coastguard Workerfunc (v Version) String() string {
43*03ce13f7SAndroid Build Coastguard Worker	return fmt.Sprintf("%v.%v.%v", v.Major, v.Minor, v.Point)
44*03ce13f7SAndroid Build Coastguard Worker}
45*03ce13f7SAndroid Build Coastguard Worker
46*03ce13f7SAndroid Build Coastguard Worker// GreaterEqual returns true if v >= rhs.
47*03ce13f7SAndroid Build Coastguard Workerfunc (v Version) GreaterEqual(rhs Version) bool {
48*03ce13f7SAndroid Build Coastguard Worker	if v.Major > rhs.Major {
49*03ce13f7SAndroid Build Coastguard Worker		return true
50*03ce13f7SAndroid Build Coastguard Worker	}
51*03ce13f7SAndroid Build Coastguard Worker	if v.Major < rhs.Major {
52*03ce13f7SAndroid Build Coastguard Worker		return false
53*03ce13f7SAndroid Build Coastguard Worker	}
54*03ce13f7SAndroid Build Coastguard Worker	if v.Minor > rhs.Minor {
55*03ce13f7SAndroid Build Coastguard Worker		return true
56*03ce13f7SAndroid Build Coastguard Worker	}
57*03ce13f7SAndroid Build Coastguard Worker	if v.Minor < rhs.Minor {
58*03ce13f7SAndroid Build Coastguard Worker		return false
59*03ce13f7SAndroid Build Coastguard Worker	}
60*03ce13f7SAndroid Build Coastguard Worker	return v.Point >= rhs.Point
61*03ce13f7SAndroid Build Coastguard Worker}
62*03ce13f7SAndroid Build Coastguard Worker
63*03ce13f7SAndroid Build Coastguard Worker// Download downloads and verifies the LLVM toolchain for the current OS.
64*03ce13f7SAndroid Build Coastguard Workerfunc (v Version) Download() ([]byte, error) {
65*03ce13f7SAndroid Build Coastguard Worker	return v.DownloadForOS(runtime.GOOS)
66*03ce13f7SAndroid Build Coastguard Worker}
67*03ce13f7SAndroid Build Coastguard Worker
68*03ce13f7SAndroid Build Coastguard Worker// DownloadForOS downloads and verifies the LLVM toolchain for the given OS.
69*03ce13f7SAndroid Build Coastguard Workerfunc (v Version) DownloadForOS(osName string) ([]byte, error) {
70*03ce13f7SAndroid Build Coastguard Worker	url, sig, key, err := v.DownloadInfoForOS(osName)
71*03ce13f7SAndroid Build Coastguard Worker	if err != nil {
72*03ce13f7SAndroid Build Coastguard Worker		return nil, err
73*03ce13f7SAndroid Build Coastguard Worker	}
74*03ce13f7SAndroid Build Coastguard Worker
75*03ce13f7SAndroid Build Coastguard Worker	resp, err := http.Get(url)
76*03ce13f7SAndroid Build Coastguard Worker	if err != nil {
77*03ce13f7SAndroid Build Coastguard Worker		return nil, fmt.Errorf("Could not download LLVM from %v: %v", url, err)
78*03ce13f7SAndroid Build Coastguard Worker	}
79*03ce13f7SAndroid Build Coastguard Worker	defer resp.Body.Close()
80*03ce13f7SAndroid Build Coastguard Worker
81*03ce13f7SAndroid Build Coastguard Worker	content, err := ioutil.ReadAll(resp.Body)
82*03ce13f7SAndroid Build Coastguard Worker	if err != nil {
83*03ce13f7SAndroid Build Coastguard Worker		return nil, fmt.Errorf("Could not download LLVM from %v: %v", url, err)
84*03ce13f7SAndroid Build Coastguard Worker	}
85*03ce13f7SAndroid Build Coastguard Worker
86*03ce13f7SAndroid Build Coastguard Worker	if sig != "" {
87*03ce13f7SAndroid Build Coastguard Worker		sigfile, err := os.Open(sig)
88*03ce13f7SAndroid Build Coastguard Worker		if err != nil {
89*03ce13f7SAndroid Build Coastguard Worker			return nil, fmt.Errorf("Couldn't open file '%s': %v", sig, err)
90*03ce13f7SAndroid Build Coastguard Worker		}
91*03ce13f7SAndroid Build Coastguard Worker		defer sigfile.Close()
92*03ce13f7SAndroid Build Coastguard Worker
93*03ce13f7SAndroid Build Coastguard Worker		keyfile, err := os.Open(key)
94*03ce13f7SAndroid Build Coastguard Worker		if err != nil {
95*03ce13f7SAndroid Build Coastguard Worker			return nil, fmt.Errorf("Couldn't open file '%s': %v", key, err)
96*03ce13f7SAndroid Build Coastguard Worker		}
97*03ce13f7SAndroid Build Coastguard Worker		defer keyfile.Close()
98*03ce13f7SAndroid Build Coastguard Worker
99*03ce13f7SAndroid Build Coastguard Worker		if err := util.CheckPGP(bytes.NewReader(content), sigfile, keyfile); err != nil {
100*03ce13f7SAndroid Build Coastguard Worker			return nil, err
101*03ce13f7SAndroid Build Coastguard Worker		}
102*03ce13f7SAndroid Build Coastguard Worker	}
103*03ce13f7SAndroid Build Coastguard Worker	return content, nil
104*03ce13f7SAndroid Build Coastguard Worker}
105*03ce13f7SAndroid Build Coastguard Worker
106*03ce13f7SAndroid Build Coastguard Worker// DownloadInfoForOS returns the download url, signature and key for the given
107*03ce13f7SAndroid Build Coastguard Worker// LLVM version for the given OS.
108*03ce13f7SAndroid Build Coastguard Workerfunc (v Version) DownloadInfoForOS(os string) (url, sig, key string, err error) {
109*03ce13f7SAndroid Build Coastguard Worker	switch v {
110*03ce13f7SAndroid Build Coastguard Worker	case Version{10, 0, 0}:
111*03ce13f7SAndroid Build Coastguard Worker		key = relfile("10.0.0.pub.key")
112*03ce13f7SAndroid Build Coastguard Worker		switch os {
113*03ce13f7SAndroid Build Coastguard Worker		case "linux":
114*03ce13f7SAndroid Build Coastguard Worker			url = "https://github.com/llvm/llvm-project/releases/download/llvmorg-10.0.0/clang+llvm-10.0.0-x86_64-linux-gnu-ubuntu-18.04.tar.xz"
115*03ce13f7SAndroid Build Coastguard Worker			sig = relfile("10.0.0-ubuntu.sig")
116*03ce13f7SAndroid Build Coastguard Worker			return
117*03ce13f7SAndroid Build Coastguard Worker		case "darwin":
118*03ce13f7SAndroid Build Coastguard Worker			url = "https://github.com/llvm/llvm-project/releases/download/llvmorg-10.0.0/clang+llvm-10.0.0-x86_64-apple-darwin.tar.xz"
119*03ce13f7SAndroid Build Coastguard Worker			sig = relfile("10.0.0-darwin.sig")
120*03ce13f7SAndroid Build Coastguard Worker			return
121*03ce13f7SAndroid Build Coastguard Worker		case "windows":
122*03ce13f7SAndroid Build Coastguard Worker			url = "https://github.com/llvm/llvm-project/releases/download/llvmorg-10.0.0/LLVM-10.0.0-win64.exe"
123*03ce13f7SAndroid Build Coastguard Worker			sig = relfile("10.0.0-win64.sig")
124*03ce13f7SAndroid Build Coastguard Worker			return
125*03ce13f7SAndroid Build Coastguard Worker		default:
126*03ce13f7SAndroid Build Coastguard Worker			return "", "", "", fmt.Errorf("Unsupported OS: %v", os)
127*03ce13f7SAndroid Build Coastguard Worker		}
128*03ce13f7SAndroid Build Coastguard Worker	case Version{17, 0, 6}:
129*03ce13f7SAndroid Build Coastguard Worker		switch os {
130*03ce13f7SAndroid Build Coastguard Worker		case "linux":
131*03ce13f7SAndroid Build Coastguard Worker			url = "https://github.com/llvm/llvm-project/releases/download/llvmorg-17.0.6/clang+llvm-17.0.6-x86_64-linux-gnu-ubuntu-22.04.tar.xz"
132*03ce13f7SAndroid Build Coastguard Worker			return
133*03ce13f7SAndroid Build Coastguard Worker		case "darwin":
134*03ce13f7SAndroid Build Coastguard Worker			url = "https://github.com/llvm/llvm-project/releases/download/llvmorg-17.0.6/clang+llvm-17.0.6-arm64-apple-darwin22.0.tar.xz"
135*03ce13f7SAndroid Build Coastguard Worker			return
136*03ce13f7SAndroid Build Coastguard Worker		case "windows":
137*03ce13f7SAndroid Build Coastguard Worker			url = "https://github.com/llvm/llvm-project/releases/download/llvmorg-17.0.6/LLVM-17.0.6-win64.exe"
138*03ce13f7SAndroid Build Coastguard Worker			return
139*03ce13f7SAndroid Build Coastguard Worker		default:
140*03ce13f7SAndroid Build Coastguard Worker			return "", "", "", fmt.Errorf("Unsupported OS: %v", os)
141*03ce13f7SAndroid Build Coastguard Worker		}
142*03ce13f7SAndroid Build Coastguard Worker	default:
143*03ce13f7SAndroid Build Coastguard Worker		return "", "", "", fmt.Errorf("Unknown download for LLVM %v", v)
144*03ce13f7SAndroid Build Coastguard Worker	}
145*03ce13f7SAndroid Build Coastguard Worker}
146*03ce13f7SAndroid Build Coastguard Workerfunc relfile(path string) string {
147*03ce13f7SAndroid Build Coastguard Worker	_, thisFile, _, _ := runtime.Caller(1)
148*03ce13f7SAndroid Build Coastguard Worker	thisDir := filepath.Dir(thisFile)
149*03ce13f7SAndroid Build Coastguard Worker	return filepath.Join(thisDir, path)
150*03ce13f7SAndroid Build Coastguard Worker}
151*03ce13f7SAndroid Build Coastguard Worker
152*03ce13f7SAndroid Build Coastguard Worker// Toolchain holds the paths and version information about an LLVM toolchain.
153*03ce13f7SAndroid Build Coastguard Workertype Toolchain struct {
154*03ce13f7SAndroid Build Coastguard Worker	Version Version
155*03ce13f7SAndroid Build Coastguard Worker	BinDir  string
156*03ce13f7SAndroid Build Coastguard Worker}
157*03ce13f7SAndroid Build Coastguard Worker
158*03ce13f7SAndroid Build Coastguard Worker// Toolchains is a list of Toolchain
159*03ce13f7SAndroid Build Coastguard Workertype Toolchains []Toolchain
160*03ce13f7SAndroid Build Coastguard Worker
161*03ce13f7SAndroid Build Coastguard Worker// Find looks for a toolchain with the specific version.
162*03ce13f7SAndroid Build Coastguard Workerfunc (l Toolchains) Find(v Version) *Toolchain {
163*03ce13f7SAndroid Build Coastguard Worker	for _, t := range l {
164*03ce13f7SAndroid Build Coastguard Worker		if t.Version == v {
165*03ce13f7SAndroid Build Coastguard Worker			return &t
166*03ce13f7SAndroid Build Coastguard Worker		}
167*03ce13f7SAndroid Build Coastguard Worker	}
168*03ce13f7SAndroid Build Coastguard Worker	return nil
169*03ce13f7SAndroid Build Coastguard Worker}
170*03ce13f7SAndroid Build Coastguard Worker
171*03ce13f7SAndroid Build Coastguard Worker// FindAtLeast looks for a toolchain with the given version, returning the highest found version.
172*03ce13f7SAndroid Build Coastguard Workerfunc (l Toolchains) FindAtLeast(v Version) *Toolchain {
173*03ce13f7SAndroid Build Coastguard Worker	out := (*Toolchain)(nil)
174*03ce13f7SAndroid Build Coastguard Worker	for _, t := range l {
175*03ce13f7SAndroid Build Coastguard Worker		if t.Version.GreaterEqual(v) && (out == nil || out.Version.GreaterEqual(t.Version)) {
176*03ce13f7SAndroid Build Coastguard Worker			t := t
177*03ce13f7SAndroid Build Coastguard Worker			out = &t
178*03ce13f7SAndroid Build Coastguard Worker		}
179*03ce13f7SAndroid Build Coastguard Worker	}
180*03ce13f7SAndroid Build Coastguard Worker	return out
181*03ce13f7SAndroid Build Coastguard Worker}
182*03ce13f7SAndroid Build Coastguard Worker
183*03ce13f7SAndroid Build Coastguard Worker// Search looks for llvm toolchains in paths.
184*03ce13f7SAndroid Build Coastguard Worker// If paths is empty, then PATH is searched.
185*03ce13f7SAndroid Build Coastguard Workerfunc Search(paths ...string) Toolchains {
186*03ce13f7SAndroid Build Coastguard Worker	toolchains := map[Version]Toolchain{}
187*03ce13f7SAndroid Build Coastguard Worker	search := func(name string) {
188*03ce13f7SAndroid Build Coastguard Worker		if len(paths) > 0 {
189*03ce13f7SAndroid Build Coastguard Worker			for _, path := range paths {
190*03ce13f7SAndroid Build Coastguard Worker				if util.IsFile(path) {
191*03ce13f7SAndroid Build Coastguard Worker					path = filepath.Dir(path)
192*03ce13f7SAndroid Build Coastguard Worker				}
193*03ce13f7SAndroid Build Coastguard Worker				if t := toolchain(path); t != nil {
194*03ce13f7SAndroid Build Coastguard Worker					toolchains[t.Version] = *t
195*03ce13f7SAndroid Build Coastguard Worker					continue
196*03ce13f7SAndroid Build Coastguard Worker				}
197*03ce13f7SAndroid Build Coastguard Worker				if t := toolchain(filepath.Join(path, "bin")); t != nil {
198*03ce13f7SAndroid Build Coastguard Worker					toolchains[t.Version] = *t
199*03ce13f7SAndroid Build Coastguard Worker					continue
200*03ce13f7SAndroid Build Coastguard Worker				}
201*03ce13f7SAndroid Build Coastguard Worker			}
202*03ce13f7SAndroid Build Coastguard Worker		} else {
203*03ce13f7SAndroid Build Coastguard Worker			path, err := exec.LookPath(name)
204*03ce13f7SAndroid Build Coastguard Worker			if err == nil {
205*03ce13f7SAndroid Build Coastguard Worker				if t := toolchain(filepath.Dir(path)); t != nil {
206*03ce13f7SAndroid Build Coastguard Worker					toolchains[t.Version] = *t
207*03ce13f7SAndroid Build Coastguard Worker				}
208*03ce13f7SAndroid Build Coastguard Worker			}
209*03ce13f7SAndroid Build Coastguard Worker		}
210*03ce13f7SAndroid Build Coastguard Worker	}
211*03ce13f7SAndroid Build Coastguard Worker
212*03ce13f7SAndroid Build Coastguard Worker	search("clang")
213*03ce13f7SAndroid Build Coastguard Worker	for i := 8; i < maxLLVMVersion; i++ {
214*03ce13f7SAndroid Build Coastguard Worker		search(fmt.Sprintf("clang-%d", i))
215*03ce13f7SAndroid Build Coastguard Worker	}
216*03ce13f7SAndroid Build Coastguard Worker
217*03ce13f7SAndroid Build Coastguard Worker	out := make([]Toolchain, 0, len(toolchains))
218*03ce13f7SAndroid Build Coastguard Worker	for _, t := range toolchains {
219*03ce13f7SAndroid Build Coastguard Worker		out = append(out, t)
220*03ce13f7SAndroid Build Coastguard Worker	}
221*03ce13f7SAndroid Build Coastguard Worker	sort.Slice(out, func(i, j int) bool { return out[i].Version.GreaterEqual(out[j].Version) })
222*03ce13f7SAndroid Build Coastguard Worker
223*03ce13f7SAndroid Build Coastguard Worker	return out
224*03ce13f7SAndroid Build Coastguard Worker}
225*03ce13f7SAndroid Build Coastguard Worker
226*03ce13f7SAndroid Build Coastguard Worker// Clang returns the path to the clang executable.
227*03ce13f7SAndroid Build Coastguard Workerfunc (t Toolchain) Clang() string {
228*03ce13f7SAndroid Build Coastguard Worker	return filepath.Join(t.BinDir, "clang"+exeExt())
229*03ce13f7SAndroid Build Coastguard Worker}
230*03ce13f7SAndroid Build Coastguard Worker
231*03ce13f7SAndroid Build Coastguard Worker// ClangXX returns the path to the clang++ executable.
232*03ce13f7SAndroid Build Coastguard Workerfunc (t Toolchain) ClangXX() string {
233*03ce13f7SAndroid Build Coastguard Worker	return filepath.Join(t.BinDir, "clang++"+exeExt())
234*03ce13f7SAndroid Build Coastguard Worker}
235*03ce13f7SAndroid Build Coastguard Worker
236*03ce13f7SAndroid Build Coastguard Worker// Cov returns the path to the llvm-cov executable.
237*03ce13f7SAndroid Build Coastguard Workerfunc (t Toolchain) Cov() string {
238*03ce13f7SAndroid Build Coastguard Worker	return filepath.Join(t.BinDir, "llvm-cov"+exeExt())
239*03ce13f7SAndroid Build Coastguard Worker}
240*03ce13f7SAndroid Build Coastguard Worker
241*03ce13f7SAndroid Build Coastguard Worker// Profdata returns the path to the llvm-profdata executable.
242*03ce13f7SAndroid Build Coastguard Workerfunc (t Toolchain) Profdata() string {
243*03ce13f7SAndroid Build Coastguard Worker	return filepath.Join(t.BinDir, "llvm-profdata"+exeExt())
244*03ce13f7SAndroid Build Coastguard Worker}
245*03ce13f7SAndroid Build Coastguard Worker
246*03ce13f7SAndroid Build Coastguard Workerfunc toolchain(dir string) *Toolchain {
247*03ce13f7SAndroid Build Coastguard Worker	t := Toolchain{BinDir: dir}
248*03ce13f7SAndroid Build Coastguard Worker	if t.resolve() {
249*03ce13f7SAndroid Build Coastguard Worker		return &t
250*03ce13f7SAndroid Build Coastguard Worker	}
251*03ce13f7SAndroid Build Coastguard Worker	return nil
252*03ce13f7SAndroid Build Coastguard Worker}
253*03ce13f7SAndroid Build Coastguard Worker
254*03ce13f7SAndroid Build Coastguard Workerfunc (t *Toolchain) resolve() bool {
255*03ce13f7SAndroid Build Coastguard Worker	if !util.IsFile(t.Profdata()) { // llvm-profdata doesn't have --version flag
256*03ce13f7SAndroid Build Coastguard Worker		return false
257*03ce13f7SAndroid Build Coastguard Worker	}
258*03ce13f7SAndroid Build Coastguard Worker	version, ok := parseVersion(t.Cov())
259*03ce13f7SAndroid Build Coastguard Worker	t.Version = version
260*03ce13f7SAndroid Build Coastguard Worker	return ok
261*03ce13f7SAndroid Build Coastguard Worker}
262*03ce13f7SAndroid Build Coastguard Worker
263*03ce13f7SAndroid Build Coastguard Workerfunc exeExt() string {
264*03ce13f7SAndroid Build Coastguard Worker	switch runtime.GOOS {
265*03ce13f7SAndroid Build Coastguard Worker	case "windows":
266*03ce13f7SAndroid Build Coastguard Worker		return ".exe"
267*03ce13f7SAndroid Build Coastguard Worker	default:
268*03ce13f7SAndroid Build Coastguard Worker		return ""
269*03ce13f7SAndroid Build Coastguard Worker	}
270*03ce13f7SAndroid Build Coastguard Worker}
271*03ce13f7SAndroid Build Coastguard Worker
272*03ce13f7SAndroid Build Coastguard Workervar versionRE = regexp.MustCompile(`(?:clang|LLVM) version ([0-9]+)\.([0-9]+)\.([0-9]+)`)
273*03ce13f7SAndroid Build Coastguard Worker
274*03ce13f7SAndroid Build Coastguard Workerfunc parseVersion(tool string) (Version, bool) {
275*03ce13f7SAndroid Build Coastguard Worker	out, err := exec.Command(tool, "--version").Output()
276*03ce13f7SAndroid Build Coastguard Worker	if err != nil {
277*03ce13f7SAndroid Build Coastguard Worker		return Version{}, false
278*03ce13f7SAndroid Build Coastguard Worker	}
279*03ce13f7SAndroid Build Coastguard Worker	matches := versionRE.FindStringSubmatch(string(out))
280*03ce13f7SAndroid Build Coastguard Worker	if len(matches) < 4 {
281*03ce13f7SAndroid Build Coastguard Worker		return Version{}, false
282*03ce13f7SAndroid Build Coastguard Worker	}
283*03ce13f7SAndroid Build Coastguard Worker	major, majorErr := strconv.Atoi(matches[1])
284*03ce13f7SAndroid Build Coastguard Worker	minor, minorErr := strconv.Atoi(matches[2])
285*03ce13f7SAndroid Build Coastguard Worker	point, pointErr := strconv.Atoi(matches[3])
286*03ce13f7SAndroid Build Coastguard Worker	if majorErr != nil || minorErr != nil || pointErr != nil {
287*03ce13f7SAndroid Build Coastguard Worker		return Version{}, false
288*03ce13f7SAndroid Build Coastguard Worker	}
289*03ce13f7SAndroid Build Coastguard Worker	return Version{major, minor, point}, true
290*03ce13f7SAndroid Build Coastguard Worker}
291