blob: 1e3a8ba58df197a814bfc93dd1457db2e406a4c5 [file] [log] [blame]
// 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 (
"flag"
"fmt"
"go/build"
"io/ioutil"
"os"
"path/filepath"
"runtime"
"strconv"
"strings"
)
// asm builds a single .s file with "go tool asm". It is invoked by the
// Go rules as an action.
func asm(args []string) error {
// Parse arguments.
args, _, err := expandParamsFiles(args)
if err != nil {
return err
}
builderArgs, asmFlags := splitArgs(args)
var outPath string
flags := flag.NewFlagSet("GoAsm", flag.ExitOnError)
flags.StringVar(&outPath, "o", "", "The output archive file to write")
goenv := envFlags(flags)
if err := flags.Parse(builderArgs); err != nil {
return err
}
if err := goenv.checkFlags(); err != nil {
return err
}
if flags.NArg() != 1 {
return fmt.Errorf("wanted exactly 1 source file; got %d", flags.NArg())
}
source := flags.Args()[0]
// Filter the input file.
metadata, err := readFileInfo(build.Default, source)
if err != nil {
return err
}
if !metadata.matched {
source = os.DevNull
}
// Build source with the assembler.
return asmFile(goenv, source, asmFlags, outPath)
}
// 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, 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
}
}
// TODO(#1894): define GOOS_goos, GOARCH_goarch, both here and in the
// GoAsm action.
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 string, asmFlags []string, outPath string) error {
args := goenv.goTool("asm")
args = append(args, asmFlags...)
args = append(args, "-trimpath", ".")
args = append(args, "-o", outPath)
args = append(args, "--", srcPath)
absArgs(args, []string{"-I", "-o", "-trimpath"})
return goenv.runCommand(args)
}