| // Copyright 2017 The Bazel Authors. All rights reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| package main |
| |
| import ( |
| "go/build" |
| "io/ioutil" |
| "os" |
| "path/filepath" |
| "regexp" |
| "runtime" |
| "strconv" |
| "strings" |
| ) |
| |
| var ASM_DEFINES = []string{ |
| "-D", "GOOS_" + build.Default.GOOS, |
| "-D", "GOARCH_" + build.Default.GOARCH, |
| "-D", "GOOS_GOARCH_" + build.Default.GOOS + "_" + build.Default.GOARCH, |
| } |
| |
| // buildSymabisFile generates a file from assembly files that is consumed |
| // by the compiler. This is only needed in go1.12+ when there is at least one |
| // .s file. If the symabis file is not needed, no file will be generated, |
| // and "", nil will be returned. |
| func buildSymabisFile(goenv *env, packagePath string, sFiles, hFiles []fileInfo, asmhdr string) (string, error) { |
| if len(sFiles) == 0 { |
| return "", nil |
| } |
| |
| // Check version. The symabis file is only required and can only be built |
| // starting at go1.12. |
| version := runtime.Version() |
| if strings.HasPrefix(version, "go1.") { |
| minor := version[len("go1."):] |
| if i := strings.IndexByte(minor, '.'); i >= 0 { |
| minor = minor[:i] |
| } |
| n, err := strconv.Atoi(minor) |
| if err == nil && n <= 11 { |
| return "", nil |
| } |
| // Fall through if the version can't be parsed. It's probably a newer |
| // development version. |
| } |
| |
| // Create an empty go_asm.h file. The compiler will write this later, but |
| // we need one to exist now. |
| asmhdrFile, err := os.Create(asmhdr) |
| if err != nil { |
| return "", err |
| } |
| if err := asmhdrFile.Close(); err != nil { |
| return "", err |
| } |
| asmhdrDir := filepath.Dir(asmhdr) |
| |
| // Create a temporary output file. The caller is responsible for deleting it. |
| var symabisName string |
| symabisFile, err := ioutil.TempFile("", "symabis") |
| if err != nil { |
| return "", err |
| } |
| symabisName = symabisFile.Name() |
| symabisFile.Close() |
| |
| // Run the assembler. |
| wd, err := os.Getwd() |
| if err != nil { |
| return symabisName, err |
| } |
| asmargs := goenv.goTool("asm") |
| asmargs = append(asmargs, "-trimpath", wd) |
| asmargs = append(asmargs, "-I", wd) |
| asmargs = append(asmargs, "-I", filepath.Join(os.Getenv("GOROOT"), "pkg", "include")) |
| asmargs = append(asmargs, "-I", asmhdrDir) |
| seenHdrDirs := map[string]bool{wd: true, asmhdrDir: true} |
| for _, hFile := range hFiles { |
| hdrDir := filepath.Dir(abs(hFile.filename)) |
| if !seenHdrDirs[hdrDir] { |
| asmargs = append(asmargs, "-I", hdrDir) |
| seenHdrDirs[hdrDir] = true |
| } |
| } |
| // The package path has to be specified as of Go 1.22 or the resulting |
| // object will be unlinkable, but the -p flag is only required in |
| // preparing symabis since Go1.22, however, go build has been |
| // emitting -p for both symabi and actual assembly since at least Go1.19 |
| if packagePath != "" && isGo119OrHigher() { |
| asmargs = append(asmargs, "-p", packagePath) |
| } |
| asmargs = append(asmargs, ASM_DEFINES...) |
| asmargs = append(asmargs, "-gensymabis", "-o", symabisName, "--") |
| for _, sFile := range sFiles { |
| asmargs = append(asmargs, sFile.filename) |
| } |
| |
| err = goenv.runCommand(asmargs) |
| return symabisName, err |
| } |
| |
| func asmFile(goenv *env, srcPath, packagePath string, asmFlags []string, outPath string) error { |
| args := goenv.goTool("asm") |
| args = append(args, asmFlags...) |
| // The package path has to be specified as of Go 1.19 or the resulting |
| // object will be unlinkable, but the -p flag is also only available |
| // since Go 1.19. |
| if packagePath != "" && isGo119OrHigher() { |
| args = append(args, "-p", packagePath) |
| } |
| args = append(args, ASM_DEFINES...) |
| args = append(args, "-trimpath", ".") |
| args = append(args, "-o", outPath) |
| args = append(args, "--", srcPath) |
| absArgs(args, []string{"-I", "-o", "-trimpath"}) |
| return goenv.runCommand(args) |
| } |
| |
| var goMinorVersionRegexp = regexp.MustCompile(`^go1\.(\d+)`) |
| |
| func isGo119OrHigher() bool { |
| match := goMinorVersionRegexp.FindStringSubmatch(runtime.Version()) |
| if match == nil { |
| // Developer version or something with an unparseable version string, |
| // assume Go 1.19 or higher. |
| return true |
| } |
| minorVersion, err := strconv.Atoi(match[1]) |
| if err != nil { |
| return true |
| } |
| return minorVersion >= 19 |
| } |