golang.org/x/tools@v0.21.0/internal/goroot/importcfg.go (about)

     1  // Copyright 2022 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package goroot is a copy of package internal/goroot
     6  // in the main GO repot. It provides a utility to produce
     7  // an importcfg and import path to package file map mapping
     8  // standard library packages to the locations of their export
     9  // data files.
    10  package goroot
    11  
    12  import (
    13  	"bytes"
    14  	"fmt"
    15  	"os/exec"
    16  	"strings"
    17  	"sync"
    18  )
    19  
    20  // Importcfg returns an importcfg file to be passed to the
    21  // Go compiler that contains the cached paths for the .a files for the
    22  // standard library.
    23  func Importcfg() (string, error) {
    24  	var icfg bytes.Buffer
    25  
    26  	m, err := PkgfileMap()
    27  	if err != nil {
    28  		return "", err
    29  	}
    30  	fmt.Fprintf(&icfg, "# import config")
    31  	for importPath, export := range m {
    32  		fmt.Fprintf(&icfg, "\npackagefile %s=%s", importPath, export)
    33  	}
    34  	s := icfg.String()
    35  	return s, nil
    36  }
    37  
    38  var (
    39  	stdlibPkgfileMap map[string]string
    40  	stdlibPkgfileErr error
    41  	once             sync.Once
    42  )
    43  
    44  // PkgfileMap returns a map of package paths to the location on disk
    45  // of the .a file for the package.
    46  // The caller must not modify the map.
    47  func PkgfileMap() (map[string]string, error) {
    48  	once.Do(func() {
    49  		m := make(map[string]string)
    50  		output, err := exec.Command("go", "list", "-export", "-e", "-f", "{{.ImportPath}} {{.Export}}", "std", "cmd").Output()
    51  		if err != nil {
    52  			stdlibPkgfileErr = err
    53  		}
    54  		for _, line := range strings.Split(string(output), "\n") {
    55  			if line == "" {
    56  				continue
    57  			}
    58  			sp := strings.SplitN(line, " ", 2)
    59  			if len(sp) != 2 {
    60  				err = fmt.Errorf("determining pkgfile map: invalid line in go list output: %q", line)
    61  				return
    62  			}
    63  			importPath, export := sp[0], sp[1]
    64  			if export != "" {
    65  				m[importPath] = export
    66  			}
    67  		}
    68  		stdlibPkgfileMap = m
    69  	})
    70  	return stdlibPkgfileMap, stdlibPkgfileErr
    71  }