Source file src/pkg/go/build/build.go
1
2
3
4
5 package build
6
7 import (
8 "bytes"
9 "errors"
10 "fmt"
11 "go/ast"
12 "go/doc"
13 "go/parser"
14 "go/token"
15 "io"
16 "io/ioutil"
17 "log"
18 "os"
19 pathpkg "path"
20 "path/filepath"
21 "runtime"
22 "sort"
23 "strconv"
24 "strings"
25 "unicode"
26 )
27
28
29 type Context struct {
30 GOARCH string
31 GOOS string
32 GOROOT string
33 GOPATH string
34 CgoEnabled bool
35 UseAllFiles bool
36 Compiler string
37
38
39
40
41
42
43
44
45 BuildTags []string
46 ReleaseTags []string
47
48
49
50
51
52
53
54 InstallSuffix string
55
56
57
58
59
60
61
62
63
64 JoinPath func(elem ...string) string
65
66
67
68 SplitPathList func(list string) []string
69
70
71
72 IsAbsPath func(path string) bool
73
74
75
76 IsDir func(path string) bool
77
78
79
80
81
82
83
84 HasSubdir func(root, dir string) (rel string, ok bool)
85
86
87
88
89 ReadDir func(dir string) (fi []os.FileInfo, err error)
90
91
92
93 OpenFile func(path string) (r io.ReadCloser, err error)
94 }
95
96
97 func (ctxt *Context) joinPath(elem ...string) string {
98 if f := ctxt.JoinPath; f != nil {
99 return f(elem...)
100 }
101 return filepath.Join(elem...)
102 }
103
104
105 func (ctxt *Context) splitPathList(s string) []string {
106 if f := ctxt.SplitPathList; f != nil {
107 return f(s)
108 }
109 return filepath.SplitList(s)
110 }
111
112
113 func (ctxt *Context) isAbsPath(path string) bool {
114 if f := ctxt.IsAbsPath; f != nil {
115 return f(path)
116 }
117 return filepath.IsAbs(path)
118 }
119
120
121 func (ctxt *Context) isDir(path string) bool {
122 if f := ctxt.IsDir; f != nil {
123 return f(path)
124 }
125 fi, err := os.Stat(path)
126 return err == nil && fi.IsDir()
127 }
128
129
130
131 func (ctxt *Context) hasSubdir(root, dir string) (rel string, ok bool) {
132 if f := ctxt.HasSubdir; f != nil {
133 return f(root, dir)
134 }
135
136
137 if rel, ok = hasSubdir(root, dir); ok {
138 return
139 }
140
141
142
143
144 rootSym, _ := filepath.EvalSymlinks(root)
145 dirSym, _ := filepath.EvalSymlinks(dir)
146
147 if rel, ok = hasSubdir(rootSym, dir); ok {
148 return
149 }
150 if rel, ok = hasSubdir(root, dirSym); ok {
151 return
152 }
153 return hasSubdir(rootSym, dirSym)
154 }
155
156 func hasSubdir(root, dir string) (rel string, ok bool) {
157 const sep = string(filepath.Separator)
158 root = filepath.Clean(root)
159 if !strings.HasSuffix(root, sep) {
160 root += sep
161 }
162 dir = filepath.Clean(dir)
163 if !strings.HasPrefix(dir, root) {
164 return "", false
165 }
166 return filepath.ToSlash(dir[len(root):]), true
167 }
168
169
170 func (ctxt *Context) readDir(path string) ([]os.FileInfo, error) {
171 if f := ctxt.ReadDir; f != nil {
172 return f(path)
173 }
174 return ioutil.ReadDir(path)
175 }
176
177
178 func (ctxt *Context) openFile(path string) (io.ReadCloser, error) {
179 if fn := ctxt.OpenFile; fn != nil {
180 return fn(path)
181 }
182
183 f, err := os.Open(path)
184 if err != nil {
185 return nil, err
186 }
187 return f, nil
188 }
189
190
191
192
193 func (ctxt *Context) isFile(path string) bool {
194 f, err := ctxt.openFile(path)
195 if err != nil {
196 return false
197 }
198 f.Close()
199 return true
200 }
201
202
203 func (ctxt *Context) gopath() []string {
204 var all []string
205 for _, p := range ctxt.splitPathList(ctxt.GOPATH) {
206 if p == "" || p == ctxt.GOROOT {
207
208
209
210
211
212
213 continue
214 }
215 if strings.HasPrefix(p, "~") {
216
217
218
219
220
221
222
223
224
225
226
227
228 continue
229 }
230 all = append(all, p)
231 }
232 return all
233 }
234
235
236
237
238 func (ctxt *Context) SrcDirs() []string {
239 var all []string
240 if ctxt.GOROOT != "" {
241 dir := ctxt.joinPath(ctxt.GOROOT, "src", "pkg")
242 if ctxt.isDir(dir) {
243 all = append(all, dir)
244 }
245 }
246 for _, p := range ctxt.gopath() {
247 dir := ctxt.joinPath(p, "src")
248 if ctxt.isDir(dir) {
249 all = append(all, dir)
250 }
251 }
252 return all
253 }
254
255
256
257
258 var Default Context = defaultContext()
259
260 var cgoEnabled = map[string]bool{
261 "darwin/386": true,
262 "darwin/amd64": true,
263 "freebsd/386": true,
264 "freebsd/amd64": true,
265 "freebsd/arm": true,
266 "linux/386": true,
267 "linux/amd64": true,
268 "linux/arm": true,
269 "netbsd/386": true,
270 "netbsd/amd64": true,
271 "netbsd/arm": true,
272 "openbsd/386": true,
273 "openbsd/amd64": true,
274 "windows/386": true,
275 "windows/amd64": true,
276 }
277
278 func defaultContext() Context {
279 var c Context
280
281 c.GOARCH = envOr("GOARCH", runtime.GOARCH)
282 c.GOOS = envOr("GOOS", runtime.GOOS)
283 c.GOROOT = runtime.GOROOT()
284 c.GOPATH = envOr("GOPATH", "")
285 c.Compiler = runtime.Compiler
286
287
288
289
290
291
292
293
294
295
296 c.ReleaseTags = []string{"go1.1"}
297
298 switch os.Getenv("CGO_ENABLED") {
299 case "1":
300 c.CgoEnabled = true
301 case "0":
302 c.CgoEnabled = false
303 default:
304
305
306 if runtime.GOARCH == c.GOARCH && runtime.GOOS == c.GOOS {
307 c.CgoEnabled = cgoEnabled[c.GOOS+"/"+c.GOARCH]
308 break
309 }
310 c.CgoEnabled = false
311 }
312
313 return c
314 }
315
316 func envOr(name, def string) string {
317 s := os.Getenv(name)
318 if s == "" {
319 return def
320 }
321 return s
322 }
323
324
325 type ImportMode uint
326
327 const (
328
329
330
331 FindOnly ImportMode = 1 << iota
332
333
334
335 AllowBinary
336 )
337
338
339 type Package struct {
340 Dir string
341 Name string
342 Doc string
343 ImportPath string
344 Root string
345 SrcRoot string
346 PkgRoot string
347 BinDir string
348 Goroot bool
349 PkgObj string
350
351
352 GoFiles []string
353 CgoFiles []string
354 IgnoredGoFiles []string
355 CFiles []string
356 HFiles []string
357 SFiles []string
358 SysoFiles []string
359 SwigFiles []string
360 SwigCXXFiles []string
361
362
363 CgoPkgConfig []string
364 CgoCFLAGS []string
365 CgoLDFLAGS []string
366
367
368 Imports []string
369 ImportPos map[string][]token.Position
370
371
372 TestGoFiles []string
373 TestImports []string
374 TestImportPos map[string][]token.Position
375 XTestGoFiles []string
376 XTestImports []string
377 XTestImportPos map[string][]token.Position
378 }
379
380
381
382
383 func (p *Package) IsCommand() bool {
384 return p.Name == "main"
385 }
386
387
388
389 func (ctxt *Context) ImportDir(dir string, mode ImportMode) (*Package, error) {
390 return ctxt.Import(".", dir, mode)
391 }
392
393
394
395 type NoGoError struct {
396 Dir string
397 }
398
399 func (e *NoGoError) Error() string {
400 return "no Go source files in " + e.Dir
401 }
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419 func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Package, error) {
420 p := &Package{
421 ImportPath: path,
422 }
423 if path == "" {
424 return p, fmt.Errorf("import %q: invalid import path", path)
425 }
426
427 var pkga string
428 var pkgerr error
429 switch ctxt.Compiler {
430 case "gccgo":
431 dir, elem := pathpkg.Split(p.ImportPath)
432 pkga = "pkg/gccgo/" + dir + "lib" + elem + ".a"
433 case "gc":
434 suffix := ""
435 if ctxt.InstallSuffix != "" {
436 suffix = "_" + ctxt.InstallSuffix
437 }
438 pkga = "pkg/" + ctxt.GOOS + "_" + ctxt.GOARCH + suffix + "/" + p.ImportPath + ".a"
439 default:
440
441 pkgerr = fmt.Errorf("import %q: unknown compiler %q", path, ctxt.Compiler)
442 }
443
444 binaryOnly := false
445 if IsLocalImport(path) {
446 pkga = ""
447 if srcDir == "" {
448 return p, fmt.Errorf("import %q: import relative to unknown directory", path)
449 }
450 if !ctxt.isAbsPath(path) {
451 p.Dir = ctxt.joinPath(srcDir, path)
452 }
453
454 if ctxt.GOROOT != "" {
455 root := ctxt.joinPath(ctxt.GOROOT, "src", "pkg")
456 if sub, ok := ctxt.hasSubdir(root, p.Dir); ok {
457 p.Goroot = true
458 p.ImportPath = sub
459 p.Root = ctxt.GOROOT
460 goto Found
461 }
462 }
463 all := ctxt.gopath()
464 for i, root := range all {
465 rootsrc := ctxt.joinPath(root, "src")
466 if sub, ok := ctxt.hasSubdir(rootsrc, p.Dir); ok {
467
468
469
470 if ctxt.GOROOT != "" {
471 if dir := ctxt.joinPath(ctxt.GOROOT, "src", "pkg", sub); ctxt.isDir(dir) {
472 goto Found
473 }
474 }
475 for _, earlyRoot := range all[:i] {
476 if dir := ctxt.joinPath(earlyRoot, "src", sub); ctxt.isDir(dir) {
477 goto Found
478 }
479 }
480
481
482
483 p.ImportPath = sub
484 p.Root = root
485 goto Found
486 }
487 }
488
489
490 } else {
491 if strings.HasPrefix(path, "/") {
492 return p, fmt.Errorf("import %q: cannot import absolute path", path)
493 }
494
495
496 var tried struct {
497 goroot string
498 gopath []string
499 }
500
501
502 if ctxt.GOROOT != "" {
503 dir := ctxt.joinPath(ctxt.GOROOT, "src", "pkg", path)
504 isDir := ctxt.isDir(dir)
505 binaryOnly = !isDir && mode&AllowBinary != 0 && pkga != "" && ctxt.isFile(ctxt.joinPath(ctxt.GOROOT, pkga))
506 if isDir || binaryOnly {
507 p.Dir = dir
508 p.Goroot = true
509 p.Root = ctxt.GOROOT
510 goto Found
511 }
512 tried.goroot = dir
513 }
514 for _, root := range ctxt.gopath() {
515 dir := ctxt.joinPath(root, "src", path)
516 isDir := ctxt.isDir(dir)
517 binaryOnly = !isDir && mode&AllowBinary != 0 && pkga != "" && ctxt.isFile(ctxt.joinPath(root, pkga))
518 if isDir || binaryOnly {
519 p.Dir = dir
520 p.Root = root
521 goto Found
522 }
523 tried.gopath = append(tried.gopath, dir)
524 }
525
526
527 var paths []string
528 if tried.goroot != "" {
529 paths = append(paths, fmt.Sprintf("\t%s (from $GOROOT)", tried.goroot))
530 } else {
531 paths = append(paths, "\t($GOROOT not set)")
532 }
533 var i int
534 var format = "\t%s (from $GOPATH)"
535 for ; i < len(tried.gopath); i++ {
536 if i > 0 {
537 format = "\t%s"
538 }
539 paths = append(paths, fmt.Sprintf(format, tried.gopath[i]))
540 }
541 if i == 0 {
542 paths = append(paths, "\t($GOPATH not set)")
543 }
544 return p, fmt.Errorf("cannot find package %q in any of:\n%s", path, strings.Join(paths, "\n"))
545 }
546
547 Found:
548 if p.Root != "" {
549 if p.Goroot {
550 p.SrcRoot = ctxt.joinPath(p.Root, "src", "pkg")
551 } else {
552 p.SrcRoot = ctxt.joinPath(p.Root, "src")
553 }
554 p.PkgRoot = ctxt.joinPath(p.Root, "pkg")
555 p.BinDir = ctxt.joinPath(p.Root, "bin")
556 if pkga != "" {
557 p.PkgObj = ctxt.joinPath(p.Root, pkga)
558 }
559 }
560
561 if mode&FindOnly != 0 {
562 return p, pkgerr
563 }
564 if binaryOnly && (mode&AllowBinary) != 0 {
565 return p, pkgerr
566 }
567
568 dirs, err := ctxt.readDir(p.Dir)
569 if err != nil {
570 return p, err
571 }
572
573 var Sfiles []string
574 var firstFile string
575 imported := make(map[string][]token.Position)
576 testImported := make(map[string][]token.Position)
577 xTestImported := make(map[string][]token.Position)
578 fset := token.NewFileSet()
579 for _, d := range dirs {
580 if d.IsDir() {
581 continue
582 }
583 name := d.Name()
584 if strings.HasPrefix(name, "_") ||
585 strings.HasPrefix(name, ".") {
586 continue
587 }
588
589 i := strings.LastIndex(name, ".")
590 if i < 0 {
591 i = len(name)
592 }
593 ext := name[i:]
594
595 if !ctxt.UseAllFiles && !ctxt.goodOSArchFile(name) {
596 if ext == ".go" {
597 p.IgnoredGoFiles = append(p.IgnoredGoFiles, name)
598 }
599 continue
600 }
601
602 switch ext {
603 case ".go", ".c", ".s", ".h", ".S", ".swig", ".swigcxx":
604
605 case ".syso":
606
607
608
609 p.SysoFiles = append(p.SysoFiles, name)
610 continue
611 default:
612
613 continue
614 }
615
616 filename := ctxt.joinPath(p.Dir, name)
617 f, err := ctxt.openFile(filename)
618 if err != nil {
619 return p, err
620 }
621
622 var data []byte
623 if strings.HasSuffix(filename, ".go") {
624 data, err = readImports(f, false)
625 } else {
626 data, err = readComments(f)
627 }
628 f.Close()
629 if err != nil {
630 return p, fmt.Errorf("read %s: %v", filename, err)
631 }
632
633
634 if !ctxt.UseAllFiles && !ctxt.shouldBuild(data) {
635 if ext == ".go" {
636 p.IgnoredGoFiles = append(p.IgnoredGoFiles, name)
637 }
638 continue
639 }
640
641
642 switch ext {
643 case ".c":
644 p.CFiles = append(p.CFiles, name)
645 continue
646 case ".h":
647 p.HFiles = append(p.HFiles, name)
648 continue
649 case ".s":
650 p.SFiles = append(p.SFiles, name)
651 continue
652 case ".S":
653 Sfiles = append(Sfiles, name)
654 continue
655 case ".swig":
656 p.SwigFiles = append(p.SwigFiles, name)
657 continue
658 case ".swigcxx":
659 p.SwigCXXFiles = append(p.SwigCXXFiles, name)
660 continue
661 }
662
663 pf, err := parser.ParseFile(fset, filename, data, parser.ImportsOnly|parser.ParseComments)
664 if err != nil {
665 return p, err
666 }
667
668 pkg := pf.Name.Name
669 if pkg == "documentation" {
670 p.IgnoredGoFiles = append(p.IgnoredGoFiles, name)
671 continue
672 }
673
674 isTest := strings.HasSuffix(name, "_test.go")
675 isXTest := false
676 if isTest && strings.HasSuffix(pkg, "_test") {
677 isXTest = true
678 pkg = pkg[:len(pkg)-len("_test")]
679 }
680
681 if p.Name == "" {
682 p.Name = pkg
683 firstFile = name
684 } else if pkg != p.Name {
685 return p, fmt.Errorf("found packages %s (%s) and %s (%s) in %s", p.Name, firstFile, pkg, name, p.Dir)
686 }
687 if pf.Doc != nil && p.Doc == "" {
688 p.Doc = doc.Synopsis(pf.Doc.Text())
689 }
690
691
692 isCgo := false
693 for _, decl := range pf.Decls {
694 d, ok := decl.(*ast.GenDecl)
695 if !ok {
696 continue
697 }
698 for _, dspec := range d.Specs {
699 spec, ok := dspec.(*ast.ImportSpec)
700 if !ok {
701 continue
702 }
703 quoted := spec.Path.Value
704 path, err := strconv.Unquote(quoted)
705 if err != nil {
706 log.Panicf("%s: parser returned invalid quoted string: <%s>", filename, quoted)
707 }
708 if isXTest {
709 xTestImported[path] = append(xTestImported[path], fset.Position(spec.Pos()))
710 } else if isTest {
711 testImported[path] = append(testImported[path], fset.Position(spec.Pos()))
712 } else {
713 imported[path] = append(imported[path], fset.Position(spec.Pos()))
714 }
715 if path == "C" {
716 if isTest {
717 return p, fmt.Errorf("use of cgo in test %s not supported", filename)
718 }
719 cg := spec.Doc
720 if cg == nil && len(d.Specs) == 1 {
721 cg = d.Doc
722 }
723 if cg != nil {
724 if err := ctxt.saveCgo(filename, p, cg); err != nil {
725 return p, err
726 }
727 }
728 isCgo = true
729 }
730 }
731 }
732 if isCgo {
733 if ctxt.CgoEnabled {
734 p.CgoFiles = append(p.CgoFiles, name)
735 }
736 } else if isXTest {
737 p.XTestGoFiles = append(p.XTestGoFiles, name)
738 } else if isTest {
739 p.TestGoFiles = append(p.TestGoFiles, name)
740 } else {
741 p.GoFiles = append(p.GoFiles, name)
742 }
743 }
744 if p.Name == "" {
745 return p, &NoGoError{p.Dir}
746 }
747
748 p.Imports, p.ImportPos = cleanImports(imported)
749 p.TestImports, p.TestImportPos = cleanImports(testImported)
750 p.XTestImports, p.XTestImportPos = cleanImports(xTestImported)
751
752
753
754
755 if len(p.CgoFiles) > 0 {
756 p.SFiles = append(p.SFiles, Sfiles...)
757 sort.Strings(p.SFiles)
758 }
759
760 return p, pkgerr
761 }
762
763 func cleanImports(m map[string][]token.Position) ([]string, map[string][]token.Position) {
764 all := make([]string, 0, len(m))
765 for path := range m {
766 all = append(all, path)
767 }
768 sort.Strings(all)
769 return all, m
770 }
771
772
773 func Import(path, srcDir string, mode ImportMode) (*Package, error) {
774 return Default.Import(path, srcDir, mode)
775 }
776
777
778 func ImportDir(dir string, mode ImportMode) (*Package, error) {
779 return Default.ImportDir(dir, mode)
780 }
781
782 var slashslash = []byte("//")
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797 func (ctxt *Context) shouldBuild(content []byte) bool {
798
799
800 end := 0
801 p := content
802 for len(p) > 0 {
803 line := p
804 if i := bytes.IndexByte(line, '\n'); i >= 0 {
805 line, p = line[:i], p[i+1:]
806 } else {
807 p = p[len(p):]
808 }
809 line = bytes.TrimSpace(line)
810 if len(line) == 0 {
811 end = len(content) - len(p)
812 continue
813 }
814 if !bytes.HasPrefix(line, slashslash) {
815 break
816 }
817 }
818 content = content[:end]
819
820
821 p = content
822 for len(p) > 0 {
823 line := p
824 if i := bytes.IndexByte(line, '\n'); i >= 0 {
825 line, p = line[:i], p[i+1:]
826 } else {
827 p = p[len(p):]
828 }
829 line = bytes.TrimSpace(line)
830 if bytes.HasPrefix(line, slashslash) {
831 line = bytes.TrimSpace(line[len(slashslash):])
832 if len(line) > 0 && line[0] == '+' {
833
834 f := strings.Fields(string(line))
835 if f[0] == "+build" {
836 ok := false
837 for _, tok := range f[1:] {
838 if ctxt.match(tok) {
839 ok = true
840 break
841 }
842 }
843 if !ok {
844 return false
845 }
846 }
847 }
848 }
849 }
850 return true
851 }
852
853
854
855
856
857
858
859 func (ctxt *Context) saveCgo(filename string, di *Package, cg *ast.CommentGroup) error {
860 text := cg.Text()
861 for _, line := range strings.Split(text, "\n") {
862 orig := line
863
864
865
866
867 line = strings.TrimSpace(line)
868 if len(line) < 5 || line[:4] != "#cgo" || (line[4] != ' ' && line[4] != '\t') {
869 continue
870 }
871
872
873 line = strings.TrimSpace(line[4:])
874 i := strings.Index(line, ":")
875 if i < 0 {
876 return fmt.Errorf("%s: invalid #cgo line: %s", filename, orig)
877 }
878 line, argstr := line[:i], line[i+1:]
879
880
881 f := strings.Fields(line)
882 if len(f) < 1 {
883 return fmt.Errorf("%s: invalid #cgo line: %s", filename, orig)
884 }
885
886 cond, verb := f[:len(f)-1], f[len(f)-1]
887 if len(cond) > 0 {
888 ok := false
889 for _, c := range cond {
890 if ctxt.match(c) {
891 ok = true
892 break
893 }
894 }
895 if !ok {
896 continue
897 }
898 }
899
900 args, err := splitQuoted(argstr)
901 if err != nil {
902 return fmt.Errorf("%s: invalid #cgo line: %s", filename, orig)
903 }
904 for _, arg := range args {
905 if !safeName(arg) {
906 return fmt.Errorf("%s: malformed #cgo argument: %s", filename, arg)
907 }
908 }
909
910 switch verb {
911 case "CFLAGS":
912 di.CgoCFLAGS = append(di.CgoCFLAGS, args...)
913 case "LDFLAGS":
914 di.CgoLDFLAGS = append(di.CgoLDFLAGS, args...)
915 case "pkg-config":
916 di.CgoPkgConfig = append(di.CgoPkgConfig, args...)
917 default:
918 return fmt.Errorf("%s: invalid #cgo verb: %s", filename, orig)
919 }
920 }
921 return nil
922 }
923
924 var safeBytes = []byte("+-.,/0123456789=ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz:")
925
926 func safeName(s string) bool {
927 if s == "" {
928 return false
929 }
930 for i := 0; i < len(s); i++ {
931 if c := s[i]; c < 0x80 && bytes.IndexByte(safeBytes, c) < 0 {
932 return false
933 }
934 }
935 return true
936 }
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954 func splitQuoted(s string) (r []string, err error) {
955 var args []string
956 arg := make([]rune, len(s))
957 escaped := false
958 quoted := false
959 quote := '\x00'
960 i := 0
961 for _, rune := range s {
962 switch {
963 case escaped:
964 escaped = false
965 case rune == '\\':
966 escaped = true
967 continue
968 case quote != '\x00':
969 if rune == quote {
970 quote = '\x00'
971 continue
972 }
973 case rune == '"' || rune == '\'':
974 quoted = true
975 quote = rune
976 continue
977 case unicode.IsSpace(rune):
978 if quoted || i > 0 {
979 quoted = false
980 args = append(args, string(arg[:i]))
981 i = 0
982 }
983 continue
984 }
985 arg[i] = rune
986 i++
987 }
988 if quoted || i > 0 {
989 args = append(args, string(arg[:i]))
990 }
991 if quote != 0 {
992 err = errors.New("unclosed quote")
993 } else if escaped {
994 err = errors.New("unfinished escaping")
995 }
996 return args, err
997 }
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011 func (ctxt *Context) match(name string) bool {
1012 if name == "" {
1013 return false
1014 }
1015 if i := strings.Index(name, ","); i >= 0 {
1016
1017 return ctxt.match(name[:i]) && ctxt.match(name[i+1:])
1018 }
1019 if strings.HasPrefix(name, "!!") {
1020 return false
1021 }
1022 if strings.HasPrefix(name, "!") {
1023 return len(name) > 1 && !ctxt.match(name[1:])
1024 }
1025
1026
1027
1028 for _, c := range name {
1029 if !unicode.IsLetter(c) && !unicode.IsDigit(c) && c != '_' && c != '.' {
1030 return false
1031 }
1032 }
1033
1034
1035 if ctxt.CgoEnabled && name == "cgo" {
1036 return true
1037 }
1038 if name == ctxt.GOOS || name == ctxt.GOARCH || name == ctxt.Compiler {
1039 return true
1040 }
1041
1042
1043 for _, tag := range ctxt.BuildTags {
1044 if tag == name {
1045 return true
1046 }
1047 }
1048 for _, tag := range ctxt.ReleaseTags {
1049 if tag == name {
1050 return true
1051 }
1052 }
1053
1054 return false
1055 }
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068 func (ctxt *Context) goodOSArchFile(name string) bool {
1069 if dot := strings.Index(name, "."); dot != -1 {
1070 name = name[:dot]
1071 }
1072 l := strings.Split(name, "_")
1073 if n := len(l); n > 0 && l[n-1] == "test" {
1074 l = l[:n-1]
1075 }
1076 n := len(l)
1077 if n >= 2 && knownOS[l[n-2]] && knownArch[l[n-1]] {
1078 return l[n-2] == ctxt.GOOS && l[n-1] == ctxt.GOARCH
1079 }
1080 if n >= 1 && knownOS[l[n-1]] {
1081 return l[n-1] == ctxt.GOOS
1082 }
1083 if n >= 1 && knownArch[l[n-1]] {
1084 return l[n-1] == ctxt.GOARCH
1085 }
1086 return true
1087 }
1088
1089 var knownOS = make(map[string]bool)
1090 var knownArch = make(map[string]bool)
1091
1092 func init() {
1093 for _, v := range strings.Fields(goosList) {
1094 knownOS[v] = true
1095 }
1096 for _, v := range strings.Fields(goarchList) {
1097 knownArch[v] = true
1098 }
1099 }
1100
1101
1102 var ToolDir = filepath.Join(runtime.GOROOT(), "pkg/tool/"+runtime.GOOS+"_"+runtime.GOARCH)
1103
1104
1105
1106 func IsLocalImport(path string) bool {
1107 return path == "." || path == ".." ||
1108 strings.HasPrefix(path, "./") || strings.HasPrefix(path, "../")
1109 }
1110
1111
1112
1113 func ArchChar(goarch string) (string, error) {
1114 switch goarch {
1115 case "386":
1116 return "8", nil
1117 case "amd64":
1118 return "6", nil
1119 case "arm":
1120 return "5", nil
1121 }
1122 return "", errors.New("unsupported GOARCH " + goarch)
1123 }
View as plain text