@@ -2,10 +2,9 @@ package build
22
33import (
44 "bytes"
5- "encoding/json"
65 "fmt"
6+ "go/build"
77 "os"
8- "os/exec"
98 "path/filepath"
109 "strings"
1110 "sync"
@@ -17,12 +16,9 @@ import (
1716 gllvm "github.com/goplus/llvm"
1817)
1918
20- // compilePkgSFiles translates Go/Plan9 assembly files selected by `go list -json`
21- // for this package/target into LLVM IR, compiles them to .o, and returns the
22- // object files for linking.
23- //
24- // NOTE: golang.org/x/tools/go/packages.Package does not expose SFiles, so we
25- // query `go list -json` here to get the exact filtered set for GOOS/GOARCH.
19+ // compilePkgSFiles translates Go/Plan9 assembly files selected for this
20+ // package/target into LLVM IR, compiles them to .o, and returns the object files
21+ // for linking.
2622func compilePkgSFiles (ctx * context , aPkg * aPackage , pkg * packages.Package , dynimports []cgoImportDynamicDecl , verbose bool ) ([]string , error ) {
2723 sfiles , err := pkgSFiles (ctx , pkg )
2824 if err != nil {
@@ -365,6 +361,21 @@ func plan9asmEnabledByDefault(conf *Config, pkgPath string) bool {
365361 return ! llruntime .HasAltPkg (pkgPath ) || llruntime .HasAdditiveAltPkg (pkgPath )
366362}
367363
364+ func (c * context ) dirHasAsmFile (dir string ) bool {
365+ if c == nil {
366+ return dirHasAsmFile (dir )
367+ }
368+ if c .asmDirCache == nil {
369+ c .asmDirCache = make (map [string ]bool )
370+ }
371+ if has , ok := c .asmDirCache [dir ]; ok {
372+ return has
373+ }
374+ has := dirHasAsmFile (dir )
375+ c .asmDirCache [dir ] = has
376+ return has
377+ }
378+
368379func dirHasAsmFile (dir string ) bool {
369380 f , err := os .Open (dir )
370381 if err != nil {
@@ -400,59 +411,52 @@ func pkgSFiles(ctx *context, pkg *packages.Package) ([]string, error) {
400411 return v , nil
401412 }
402413
403- // Fast path: if directory has no .s/.S at all, skip `go list`.
404- if ! dirHasAsmFile (pkg .Dir ) {
405- ctx .sfilesCache [pkg .ID ] = nil
406- return nil , nil
414+ var metadataSFiles []string
415+ for _ , file := range pkg .OtherFiles {
416+ if strings .HasSuffix (file , ".s" ) || strings .HasSuffix (file , ".S" ) {
417+ metadataSFiles = append (metadataSFiles , file )
418+ }
407419 }
408-
409- args := []string {"list" , "-json" }
410- if ctx .conf != nil && len (ctx .conf .BuildFlags ) > 0 {
411- args = append (args , ctx .conf .BuildFlags ... )
420+ if len (metadataSFiles ) > 0 {
421+ ctx .sfilesCache [pkg .ID ] = metadataSFiles
422+ return metadataSFiles , nil
412423 }
413- args = append (args , pkg .PkgPath )
414424
415- cmd := exec .Command ("go" , args ... )
416- cmd .Dir = pkg .Dir
417- cmd .Env = append (os .Environ (),
418- "GOOS=" + ctx .buildConf .Goos ,
419- "GOARCH=" + ctx .buildConf .Goarch ,
420- )
421- out , err := cmd .Output ()
422- if err != nil {
423- var errBuf bytes.Buffer
424- if ee , ok := err .(* exec.ExitError ); ok && len (ee .Stderr ) > 0 {
425- errBuf .Write (ee .Stderr )
426- }
427- return nil , fmt .Errorf ("go list -json %s failed: %w\n %s" , pkg .PkgPath , err , strings .TrimSpace (errBuf .String ()))
425+ // Fast path: if directory has no .s/.S at all, skip source selection.
426+ if ! ctx .dirHasAsmFile (pkg .Dir ) {
427+ ctx .sfilesCache [pkg .ID ] = nil
428+ return nil , nil
428429 }
429430
430- var lp struct {
431- Dir string `json:"Dir"`
432- SFiles []string `json:"SFiles"`
431+ buildCtx := build .Default
432+ buildCtx .GOOS = ctx .buildConf .Goos
433+ buildCtx .GOARCH = ctx .buildConf .Goarch
434+ if ctx .conf != nil {
435+ buildCtx .BuildTags = parseSourcePatchBuildTags (ctx .conf .BuildFlags )
433436 }
434- if err := json .Unmarshal (out , & lp ); err != nil {
435- return nil , fmt .Errorf ("go list -json %s: parse: %w" , pkg .PkgPath , err )
437+ bp , err := buildCtx .ImportDir (pkg .Dir , 0 )
438+ if err != nil {
439+ return nil , fmt .Errorf ("inspect asm files for %s: %w" , pkg .PkgPath , err )
436440 }
437441
438442 // internal/chacha8rand has highly optimized arch asm on amd64/arm64.
439443 // Until full vector lowering lands, force the generic stub entry, which
440444 // tail-jumps to block_generic and preserves package behavior.
441- if pkg .PkgPath == "internal/chacha8rand" && lp .Dir != "" {
442- stub := filepath .Join (lp .Dir , "chacha8_stub.s" )
445+ if pkg .PkgPath == "internal/chacha8rand" && bp .Dir != "" {
446+ stub := filepath .Join (bp .Dir , "chacha8_stub.s" )
443447 if _ , err := os .Stat (stub ); err == nil {
444448 paths := []string {stub }
445449 ctx .sfilesCache [pkg .ID ] = paths
446450 return paths , nil
447451 }
448452 }
449453
450- paths := make ([]string , 0 , len (lp .SFiles ))
451- for _ , f := range lp .SFiles {
452- if lp .Dir == "" {
454+ paths := make ([]string , 0 , len (bp .SFiles ))
455+ for _ , f := range bp .SFiles {
456+ if bp .Dir == "" {
453457 continue
454458 }
455- paths = append (paths , filepath .Join (lp .Dir , f ))
459+ paths = append (paths , filepath .Join (bp .Dir , f ))
456460 }
457461 ctx .sfilesCache [pkg .ID ] = paths
458462 return paths , nil
0 commit comments