// Copyright 2017 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.
// Package srcimporter implements importing directly// from source files rather than installed packages.
package srcimporter // import "go/internal/srcimporter"import (_// for go:linkname)// An Importer provides the context for importing packages from source code.typeImporterstruct { ctxt *build.Context fset *token.FileSet sizes types.Sizes packages map[string]*types.Package}// New returns a new Importer for the given context, file set, and map// of packages. The context is used to resolve import paths to package paths,// and identifying the files belonging to the package. If the context provides// non-nil file system functions, they are used instead of the regular package// os functions. The file set is used to track position information of package// files; and imported packages are added to the packages map.func ( *build.Context, *token.FileSet, map[string]*types.Package) *Importer {return &Importer{ctxt: ,fset: ,sizes: types.SizesFor(.Compiler, .GOARCH), // uses go/types default if GOARCH not foundpackages: , }}// Importing is a sentinel taking the place in Importer.packages// for a package that is in the process of being imported.var importing types.Package// Import(path) is a shortcut for ImportFrom(path, ".", 0).func ( *Importer) ( string) (*types.Package, error) {return .ImportFrom(, ".", 0) // use "." rather than "" (see issue #24441)}// ImportFrom imports the package with the given import path resolved from the given srcDir,// adds the new package to the set of packages maintained by the importer, and returns the// package. Package path resolution and file system operations are controlled by the context// maintained with the importer. The import mode must be zero but is otherwise ignored.// Packages that are not comprised entirely of pure Go files may fail to import because the// type checker may not be able to determine all exported entities (e.g. due to cgo dependencies).func ( *Importer) (, string, types.ImportMode) (*types.Package, error) {if != 0 {panic("non-zero import mode") }if , := .absPath(); == nil { // see issue #14282 = } , := .ctxt.Import(, , 0)if != nil {returnnil, // err may be *build.NoGoError - return as is }// package unsafe is known to the type checkerif .ImportPath == "unsafe" {returntypes.Unsafe, nil }// no need to re-import if the package was imported completely before := .packages[.ImportPath]if != nil {if == &importing {returnnil, fmt.Errorf("import cycle through package %q", .ImportPath) }if !.Complete() {// Package exists but is not complete - we cannot handle this // at the moment since the source importer replaces the package // wholesale rather than augmenting it (see #19337 for details). // Return incomplete package with error (see #16088).return , fmt.Errorf("reimported partially imported package %q", .ImportPath) }return , nil } .packages[.ImportPath] = &importingdeferfunc() {// clean up in case of error // TODO(gri) Eventually we may want to leave a (possibly empty) // package in the map in all cases (and use that package to // identify cycles). See also issue 16088.if .packages[.ImportPath] == &importing { .packages[.ImportPath] = nil } }()var []string = append(, .GoFiles...) = append(, .CgoFiles...) , := .parseFiles(.Dir, )if != nil {returnnil, }// type-check package filesvarerror := types.Config{IgnoreFuncBodies: true,// continue type-checking after the first errorError: func( error) {if == nil && !.(types.Error).Soft { = } },Importer: ,Sizes: .sizes, }iflen(.CgoFiles) > 0 {if .ctxt.OpenFile != nil {// cgo, gcc, pkg-config, etc. do not support // build.Context's VFS. .FakeImportC = true } else {setUsesCgo(&) , := .cgo()if != nil {returnnil, fmt.Errorf("error processing cgo for package %q: %w", .ImportPath, ) } = append(, ) } } , = .Check(.ImportPath, .fset, , nil)if != nil {// If there was a hard error it is possibly unsafe // to use the package as it may not be fully populated. // Do not return it (see also #20837, #20855).if != nil { = nil = // give preference to first hard error over any soft error }return , fmt.Errorf("type-checking package %q failed (%v)", .ImportPath, ) }if != nil {// this can only happen if we have a bug in go/typespanic("package is not safe yet no error was returned") } .packages[.ImportPath] = return , nil}func ( *Importer) ( string, []string) ([]*ast.File, error) {// use build.Context's OpenFile if there is one := .ctxt.OpenFileif == nil { = func( string) (io.ReadCloser, error) { returnos.Open() } } := make([]*ast.File, len()) := make([]error, len())varsync.WaitGroup .Add(len())for , := range {gofunc( int, string) {defer .Done() , := ()if != nil { [] = // open provides operation and filename in errorreturn } [], [] = parser.ParseFile(.fset, , , parser.SkipObjectResolution) .Close() // ignore Close error - parsing may have succeeded which is all we need }(, .joinPath(, )) } .Wait()// if there are errors, return the first one for deterministic resultsfor , := range {if != nil {returnnil, } }return , nil}func ( *Importer) ( *build.Package) (*ast.File, error) { , := os.MkdirTemp("", "srcimporter")if != nil {returnnil, }deferos.RemoveAll() := "go"if .ctxt.GOROOT != "" { = filepath.Join(.ctxt.GOROOT, "bin", "go") } := []string{, "tool", "cgo", "-objdir", }if .Goroot {switch .ImportPath {case"runtime/cgo": = append(, "-import_runtime_cgo=false", "-import_syscall=false")case"runtime/race": = append(, "-import_syscall=false") } } = append(, "--") = append(, strings.Fields(os.Getenv("CGO_CPPFLAGS"))...) = append(, .CgoCPPFLAGS...)iflen(.CgoPkgConfig) > 0 { := exec.Command("pkg-config", append([]string{"--cflags"}, .CgoPkgConfig...)...) , := .Output()if != nil {returnnil, fmt.Errorf("pkg-config --cflags: %w", ) } = append(, strings.Fields(string())...) } = append(, "-I", ) = append(, strings.Fields(os.Getenv("CGO_CFLAGS"))...) = append(, .CgoCFLAGS...) = append(, .CgoFiles...) := exec.Command([0], [1:]...) .Dir = .Dirif := .Run(); != nil {returnnil, fmt.Errorf("go tool cgo: %w", ) }returnparser.ParseFile(.fset, filepath.Join(, "_cgo_gotypes.go"), nil, parser.SkipObjectResolution)}// context-controlled file system operationsfunc ( *Importer) ( string) (string, error) {// TODO(gri) This should be using p.ctxt.AbsPath which doesn't // exist but probably should. See also issue #14282.returnfilepath.Abs()}func ( *Importer) ( string) bool {if := .ctxt.IsAbsPath; != nil {return () }returnfilepath.IsAbs()}func ( *Importer) ( ...string) string {if := .ctxt.JoinPath; != nil {return (...) }returnfilepath.Join(...)}//go:linkname setUsesCgo go/types.srcimporter_setUsesCgofunc setUsesCgo( *types.Config)
The pages are generated with Goldsv0.7.0-preview. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.