Source file
src/go/build/deps_test.go
1
2
3
4
5
6
7
8 package build
9
10 import (
11 "bytes"
12 "fmt"
13 "go/token"
14 "internal/dag"
15 "internal/testenv"
16 "io/fs"
17 "os"
18 "path/filepath"
19 "runtime"
20 "sort"
21 "strings"
22 "testing"
23 )
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39 var depsRules = `
40 # No dependencies allowed for any of these packages.
41 NONE
42 < cmp, container/list, container/ring,
43 internal/cfg, internal/coverage, internal/coverage/rtcov,
44 internal/coverage/uleb128, internal/coverage/calloc,
45 internal/cpu, internal/goarch, internal/godebugs,
46 internal/goexperiment, internal/goos,
47 internal/goversion, internal/nettrace, internal/platform,
48 internal/trace/traceviewer/format,
49 log/internal,
50 unicode/utf8, unicode/utf16, unicode,
51 unsafe;
52
53 # These packages depend only on internal/goarch and unsafe.
54 internal/goarch, unsafe
55 < internal/abi, internal/chacha8rand;
56
57 unsafe < maps;
58
59 # RUNTIME is the core runtime group of packages, all of them very light-weight.
60 internal/abi,
61 internal/chacha8rand,
62 internal/coverage/rtcov,
63 internal/cpu,
64 internal/goarch,
65 internal/godebugs,
66 internal/goexperiment,
67 internal/goos
68 < internal/bytealg
69 < internal/itoa
70 < internal/unsafeheader
71 < runtime/internal/sys
72 < runtime/internal/syscall
73 < runtime/internal/atomic
74 < runtime/internal/math
75 < runtime
76 < sync/atomic
77 < internal/race
78 < sync
79 < internal/bisect
80 < internal/godebug
81 < internal/reflectlite
82 < errors
83 < internal/oserror, math/bits
84 < RUNTIME;
85
86 internal/race
87 < iter;
88
89 # slices depends on unsafe for overlapping check, cmp for comparison
90 # semantics, and math/bits for # calculating bitlength of numbers.
91 unsafe, cmp, math/bits
92 < slices;
93
94 RUNTIME, slices
95 < sort;
96
97 sort
98 < container/heap;
99
100 RUNTIME
101 < io;
102
103 RUNTIME
104 < arena;
105
106 syscall !< io;
107 reflect !< sort;
108
109 RUNTIME, unicode/utf8
110 < path;
111
112 unicode !< path;
113
114 # SYSCALL is RUNTIME plus the packages necessary for basic system calls.
115 RUNTIME, unicode/utf8, unicode/utf16
116 < internal/syscall/windows/sysdll, syscall/js
117 < syscall
118 < internal/syscall/unix, internal/syscall/windows, internal/syscall/windows/registry
119 < internal/syscall/execenv
120 < SYSCALL;
121
122 # TIME is SYSCALL plus the core packages about time, including context.
123 SYSCALL
124 < time/tzdata
125 < time
126 < context
127 < TIME;
128
129 TIME, io, path, sort
130 < io/fs;
131
132 # MATH is RUNTIME plus the basic math packages.
133 RUNTIME
134 < math
135 < MATH;
136
137 unicode !< math;
138
139 MATH
140 < math/cmplx;
141
142 MATH
143 < math/rand, math/rand/v2;
144
145 MATH
146 < runtime/metrics;
147
148 MATH, unicode/utf8
149 < strconv;
150
151 unicode !< strconv;
152
153 # STR is basic string and buffer manipulation.
154 RUNTIME, io, unicode/utf8, unicode/utf16, unicode
155 < bytes, strings
156 < bufio;
157
158 bufio, path, strconv
159 < STR;
160
161 # OS is basic OS access, including helpers (path/filepath, os/exec, etc).
162 # OS includes string routines, but those must be layered above package os.
163 # OS does not include reflection.
164 io/fs
165 < internal/testlog
166 < internal/poll
167 < internal/safefilepath
168 < os
169 < os/signal;
170
171 io/fs
172 < embed;
173
174 unicode, fmt !< net, os, os/signal;
175
176 os/signal, internal/safefilepath, STR
177 < path/filepath
178 < io/ioutil;
179
180 path/filepath, internal/godebug < os/exec;
181
182 io/ioutil, os/exec, os/signal
183 < OS;
184
185 reflect !< OS;
186
187 OS
188 < golang.org/x/sys/cpu;
189
190 # FMT is OS (which includes string routines) plus reflect and fmt.
191 # It does not include package log, which should be avoided in core packages.
192 arena, strconv, unicode
193 < reflect;
194
195 os, reflect
196 < internal/fmtsort
197 < fmt;
198
199 OS, fmt
200 < FMT;
201
202 log !< FMT;
203
204 # Misc packages needing only FMT.
205 FMT
206 < html,
207 internal/dag,
208 internal/goroot,
209 internal/types/errors,
210 mime/quotedprintable,
211 net/internal/socktest,
212 net/url,
213 runtime/trace,
214 text/scanner,
215 text/tabwriter;
216
217 io, reflect
218 < internal/saferio;
219
220 # encodings
221 # core ones do not use fmt.
222 io, strconv, slices
223 < encoding;
224
225 encoding, reflect
226 < encoding/binary
227 < encoding/base32, encoding/base64;
228
229 FMT, encoding < flag;
230
231 fmt !< encoding/base32, encoding/base64;
232
233 FMT, encoding/base32, encoding/base64, internal/saferio
234 < encoding/ascii85, encoding/csv, encoding/gob, encoding/hex,
235 encoding/json, encoding/pem, encoding/xml, mime;
236
237 # hashes
238 io
239 < hash
240 < hash/adler32, hash/crc32, hash/crc64, hash/fnv;
241
242 # math/big
243 FMT, encoding/binary, math/rand
244 < math/big;
245
246 # compression
247 FMT, encoding/binary, hash/adler32, hash/crc32
248 < compress/bzip2, compress/flate, compress/lzw, internal/zstd
249 < archive/zip, compress/gzip, compress/zlib;
250
251 # templates
252 FMT
253 < text/template/parse;
254
255 net/url, text/template/parse
256 < text/template
257 < internal/lazytemplate;
258
259 # regexp
260 FMT
261 < regexp/syntax
262 < regexp
263 < internal/lazyregexp;
264
265 encoding/json, html, text/template, regexp
266 < html/template;
267
268 # suffix array
269 encoding/binary, regexp
270 < index/suffixarray;
271
272 # executable parsing
273 FMT, encoding/binary, compress/zlib, internal/saferio, internal/zstd
274 < runtime/debug
275 < debug/dwarf
276 < debug/elf, debug/gosym, debug/macho, debug/pe, debug/plan9obj, internal/xcoff
277 < debug/buildinfo
278 < DEBUG;
279
280 # go parser and friends.
281 FMT
282 < internal/gover
283 < go/version
284 < go/token
285 < go/scanner
286 < go/ast
287 < go/internal/typeparams;
288
289 FMT
290 < go/build/constraint, go/doc/comment;
291
292 go/internal/typeparams, go/build/constraint
293 < go/parser;
294
295 go/doc/comment, go/parser, text/tabwriter
296 < go/printer
297 < go/format;
298
299 math/big, go/token
300 < go/constant;
301
302 FMT, internal/goexperiment
303 < internal/buildcfg;
304
305 container/heap, go/constant, go/parser, internal/buildcfg, internal/goversion, internal/types/errors
306 < go/types;
307
308 # The vast majority of standard library packages should not be resorting to regexp.
309 # go/types is a good chokepoint. It shouldn't use regexp, nor should anything
310 # that is low-enough level to be used by go/types.
311 regexp !< go/types;
312
313 go/doc/comment, go/parser, internal/lazyregexp, text/template
314 < go/doc;
315
316 go/build/constraint, go/doc, go/parser, internal/buildcfg, internal/goroot, internal/goversion, internal/platform
317 < go/build;
318
319 # databases
320 FMT
321 < database/sql/internal
322 < database/sql/driver
323 < database/sql;
324
325 # images
326 FMT, compress/lzw, compress/zlib
327 < image/color
328 < image, image/color/palette
329 < image/internal/imageutil
330 < image/draw
331 < image/gif, image/jpeg, image/png;
332
333 # cgo, delayed as long as possible.
334 # If you add a dependency on CGO, you must add the package
335 # to cgoPackages in cmd/dist/test.go as well.
336 RUNTIME
337 < C
338 < runtime/cgo
339 < CGO
340 < runtime/msan, runtime/asan;
341
342 # runtime/race
343 NONE < runtime/race/internal/amd64v1;
344 NONE < runtime/race/internal/amd64v3;
345 CGO, runtime/race/internal/amd64v1, runtime/race/internal/amd64v3 < runtime/race;
346
347 # Bulk of the standard library must not use cgo.
348 # The prohibition stops at net and os/user.
349 C !< fmt, go/types, CRYPTO-MATH, log/slog;
350
351 CGO, OS
352 < plugin;
353
354 CGO, FMT
355 < os/user
356 < archive/tar;
357
358 sync
359 < internal/singleflight;
360
361 os
362 < golang.org/x/net/dns/dnsmessage,
363 golang.org/x/net/lif,
364 golang.org/x/net/route;
365
366 os, runtime, strconv, sync, unsafe,
367 internal/godebug
368 < internal/intern;
369
370 internal/bytealg, internal/intern, internal/itoa, math/bits, sort, strconv
371 < net/netip;
372
373 # net is unavoidable when doing any networking,
374 # so large dependencies must be kept out.
375 # This is a long-looking list but most of these
376 # are small with few dependencies.
377 CGO,
378 golang.org/x/net/dns/dnsmessage,
379 golang.org/x/net/lif,
380 golang.org/x/net/route,
381 internal/godebug,
382 internal/nettrace,
383 internal/poll,
384 internal/singleflight,
385 internal/race,
386 net/netip,
387 os
388 < net;
389
390 fmt, unicode !< net;
391 math/rand !< net; # net uses runtime instead
392
393 # NET is net plus net-helper packages.
394 FMT, net
395 < net/textproto;
396
397 mime, net/textproto, net/url
398 < NET;
399
400 # logging - most packages should not import; http and up is allowed
401 FMT, log/internal
402 < log;
403
404 log, log/slog !< crypto/tls, database/sql, go/importer, testing;
405
406 FMT, log, net
407 < log/syslog;
408
409 RUNTIME
410 < log/slog/internal, log/slog/internal/buffer;
411
412 FMT,
413 encoding, encoding/json,
414 log, log/internal,
415 log/slog/internal, log/slog/internal/buffer,
416 slices
417 < log/slog
418 < log/slog/internal/slogtest, log/slog/internal/benchmarks;
419
420 NET, log
421 < net/mail;
422
423 NONE < crypto/internal/boring/sig, crypto/internal/boring/syso;
424 sync/atomic < crypto/internal/boring/bcache, crypto/internal/boring/fipstls;
425 crypto/internal/boring/sig, crypto/internal/boring/fipstls < crypto/tls/fipsonly;
426
427 # CRYPTO is core crypto algorithms - no cgo, fmt, net.
428 # Unfortunately, stuck with reflect via encoding/binary.
429 crypto/internal/boring/sig,
430 crypto/internal/boring/syso,
431 encoding/binary,
432 golang.org/x/sys/cpu,
433 hash, embed
434 < crypto
435 < crypto/subtle
436 < crypto/internal/alias
437 < crypto/cipher;
438
439 crypto/cipher,
440 crypto/internal/boring/bcache
441 < crypto/internal/boring
442 < crypto/boring;
443
444 crypto/internal/alias
445 < crypto/internal/randutil
446 < crypto/internal/nistec/fiat
447 < crypto/internal/nistec
448 < crypto/internal/edwards25519/field
449 < crypto/internal/edwards25519;
450
451 crypto/boring
452 < crypto/aes, crypto/des, crypto/hmac, crypto/md5, crypto/rc4,
453 crypto/sha1, crypto/sha256, crypto/sha512;
454
455 crypto/boring, crypto/internal/edwards25519/field
456 < crypto/ecdh;
457
458 crypto/aes,
459 crypto/des,
460 crypto/ecdh,
461 crypto/hmac,
462 crypto/internal/edwards25519,
463 crypto/md5,
464 crypto/rc4,
465 crypto/sha1,
466 crypto/sha256,
467 crypto/sha512
468 < CRYPTO;
469
470 CGO, fmt, net !< CRYPTO;
471
472 # CRYPTO-MATH is core bignum-based crypto - no cgo, net; fmt now ok.
473 CRYPTO, FMT, math/big
474 < crypto/internal/boring/bbig
475 < crypto/rand
476 < crypto/ed25519
477 < encoding/asn1
478 < golang.org/x/crypto/cryptobyte/asn1
479 < golang.org/x/crypto/cryptobyte
480 < crypto/internal/bigmod
481 < crypto/dsa, crypto/elliptic, crypto/rsa
482 < crypto/ecdsa
483 < CRYPTO-MATH;
484
485 CGO, net !< CRYPTO-MATH;
486
487 # TLS, Prince of Dependencies.
488 CRYPTO-MATH, NET, container/list, encoding/hex, encoding/pem
489 < golang.org/x/crypto/internal/alias
490 < golang.org/x/crypto/internal/subtle
491 < golang.org/x/crypto/chacha20
492 < golang.org/x/crypto/internal/poly1305
493 < golang.org/x/crypto/chacha20poly1305
494 < golang.org/x/crypto/hkdf
495 < crypto/x509/internal/macos
496 < crypto/x509/pkix;
497
498 crypto/internal/boring/fipstls, crypto/x509/pkix
499 < crypto/x509
500 < crypto/tls;
501
502 # crypto-aware packages
503
504 DEBUG, go/build, go/types, text/scanner, crypto/md5
505 < internal/pkgbits
506 < go/internal/gcimporter, go/internal/gccgoimporter, go/internal/srcimporter
507 < go/importer;
508
509 NET, crypto/rand, mime/quotedprintable
510 < mime/multipart;
511
512 crypto/tls
513 < net/smtp;
514
515 crypto/rand
516 < hash/maphash; # for purego implementation
517
518 # HTTP, King of Dependencies.
519
520 FMT
521 < golang.org/x/net/http2/hpack
522 < net/http/internal, net/http/internal/ascii, net/http/internal/testcert;
523
524 FMT, NET, container/list, encoding/binary, log
525 < golang.org/x/text/transform
526 < golang.org/x/text/unicode/norm
527 < golang.org/x/text/unicode/bidi
528 < golang.org/x/text/secure/bidirule
529 < golang.org/x/net/idna
530 < golang.org/x/net/http/httpguts, golang.org/x/net/http/httpproxy;
531
532 NET, crypto/tls
533 < net/http/httptrace;
534
535 compress/gzip,
536 golang.org/x/net/http/httpguts,
537 golang.org/x/net/http/httpproxy,
538 golang.org/x/net/http2/hpack,
539 net/http/internal,
540 net/http/internal/ascii,
541 net/http/internal/testcert,
542 net/http/httptrace,
543 mime/multipart,
544 log
545 < net/http;
546
547 # HTTP-aware packages
548
549 encoding/json, net/http
550 < expvar;
551
552 net/http, net/http/internal/ascii
553 < net/http/cookiejar, net/http/httputil;
554
555 net/http, flag
556 < net/http/httptest;
557
558 net/http, regexp
559 < net/http/cgi
560 < net/http/fcgi;
561
562 # Profiling
563 FMT, compress/gzip, encoding/binary, text/tabwriter
564 < runtime/pprof;
565
566 OS, compress/gzip, internal/lazyregexp
567 < internal/profile;
568
569 html, internal/profile, net/http, runtime/pprof, runtime/trace
570 < net/http/pprof;
571
572 # RPC
573 encoding/gob, encoding/json, go/token, html/template, net/http
574 < net/rpc
575 < net/rpc/jsonrpc;
576
577 # System Information
578 bufio, bytes, internal/cpu, io, os, strings, sync
579 < internal/sysinfo;
580
581 # Test-only
582 log
583 < testing/iotest
584 < testing/fstest;
585
586 FMT, flag, math/rand
587 < testing/quick;
588
589 FMT, DEBUG, flag, runtime/trace, internal/sysinfo, math/rand
590 < testing;
591
592 log/slog, testing
593 < testing/slogtest;
594
595 FMT, crypto/sha256, encoding/json, go/ast, go/parser, go/token,
596 internal/godebug, math/rand, encoding/hex, crypto/sha256
597 < internal/fuzz;
598
599 internal/fuzz, internal/testlog, runtime/pprof, regexp
600 < testing/internal/testdeps;
601
602 OS, flag, testing, internal/cfg, internal/platform, internal/goroot
603 < internal/testenv;
604
605 OS, encoding/base64
606 < internal/obscuretestdata;
607
608 CGO, OS, fmt
609 < internal/testpty;
610
611 NET, testing, math/rand
612 < golang.org/x/net/nettest;
613
614 syscall
615 < os/exec/internal/fdtest;
616
617 FMT
618 < internal/diff, internal/txtar;
619
620 # v2 execution trace parser.
621 FMT
622 < internal/trace/v2/event;
623
624 internal/trace/v2/event
625 < internal/trace/v2/event/go122;
626
627 FMT, io, internal/trace/v2/event/go122
628 < internal/trace/v2/version;
629
630 FMT, encoding/binary, internal/trace/v2/version
631 < internal/trace/v2/raw;
632
633 FMT, encoding/binary, internal/trace/v2/version
634 < internal/trace/v2;
635
636 regexp, internal/trace/v2, internal/trace/v2/raw, internal/txtar
637 < internal/trace/v2/testtrace;
638
639 regexp, internal/txtar, internal/trace/v2, internal/trace/v2/raw
640 < internal/trace/v2/internal/testgen/go122;
641
642 FMT, container/heap, math/rand, internal/trace/v2
643 < internal/trace;
644
645 # cmd/trace dependencies.
646 FMT,
647 embed,
648 encoding/json,
649 html/template,
650 internal/profile,
651 internal/trace,
652 internal/trace/traceviewer/format,
653 net/http
654 < internal/trace/traceviewer;
655
656 # Coverage.
657 FMT, crypto/md5, encoding/binary, regexp, sort, text/tabwriter, unsafe,
658 internal/coverage, internal/coverage/uleb128
659 < internal/coverage/cmerge,
660 internal/coverage/pods,
661 internal/coverage/slicereader,
662 internal/coverage/slicewriter;
663
664 internal/coverage/slicereader, internal/coverage/slicewriter
665 < internal/coverage/stringtab
666 < internal/coverage/decodecounter, internal/coverage/decodemeta,
667 internal/coverage/encodecounter, internal/coverage/encodemeta;
668
669 internal/coverage/cmerge
670 < internal/coverage/cformat;
671
672 internal/coverage, crypto/sha256, FMT
673 < cmd/internal/cov/covcmd;
674
675 encoding/json,
676 runtime/debug,
677 internal/coverage/calloc,
678 internal/coverage/cformat,
679 internal/coverage/decodecounter, internal/coverage/decodemeta,
680 internal/coverage/encodecounter, internal/coverage/encodemeta,
681 internal/coverage/pods
682 < runtime/coverage;
683 `
684
685
686 func listStdPkgs(goroot string) ([]string, error) {
687
688 var pkgs []string
689
690 src := filepath.Join(goroot, "src") + string(filepath.Separator)
691 walkFn := func(path string, d fs.DirEntry, err error) error {
692 if err != nil || !d.IsDir() || path == src {
693 return nil
694 }
695
696 base := filepath.Base(path)
697 if strings.HasPrefix(base, ".") || strings.HasPrefix(base, "_") || base == "testdata" {
698 return filepath.SkipDir
699 }
700
701 name := filepath.ToSlash(path[len(src):])
702 if name == "builtin" || name == "cmd" {
703 return filepath.SkipDir
704 }
705
706 pkgs = append(pkgs, strings.TrimPrefix(name, "vendor/"))
707 return nil
708 }
709 if err := filepath.WalkDir(src, walkFn); err != nil {
710 return nil, err
711 }
712 return pkgs, nil
713 }
714
715 func TestDependencies(t *testing.T) {
716 if !testenv.HasSrc() {
717
718
719 t.Skipf("skipping on %s/%s, missing full GOROOT", runtime.GOOS, runtime.GOARCH)
720 }
721
722 ctxt := Default
723 all, err := listStdPkgs(ctxt.GOROOT)
724 if err != nil {
725 t.Fatal(err)
726 }
727 sort.Strings(all)
728
729 sawImport := map[string]map[string]bool{}
730 policy := depsPolicy(t)
731
732 for _, pkg := range all {
733 imports, err := findImports(pkg)
734 if err != nil {
735 t.Error(err)
736 continue
737 }
738 if sawImport[pkg] == nil {
739 sawImport[pkg] = map[string]bool{}
740 }
741 var bad []string
742 for _, imp := range imports {
743 sawImport[pkg][imp] = true
744 if !policy.HasEdge(pkg, imp) {
745 bad = append(bad, imp)
746 }
747 }
748 if bad != nil {
749 t.Errorf("unexpected dependency: %s imports %v", pkg, bad)
750 }
751 }
752 }
753
754 var buildIgnore = []byte("\n//go:build ignore")
755
756 func findImports(pkg string) ([]string, error) {
757 vpkg := pkg
758 if strings.HasPrefix(pkg, "golang.org") {
759 vpkg = "vendor/" + pkg
760 }
761 dir := filepath.Join(Default.GOROOT, "src", vpkg)
762 files, err := os.ReadDir(dir)
763 if err != nil {
764 return nil, err
765 }
766 var imports []string
767 var haveImport = map[string]bool{}
768 if pkg == "crypto/internal/boring" {
769 haveImport["C"] = true
770 }
771 fset := token.NewFileSet()
772 for _, file := range files {
773 name := file.Name()
774 if name == "slice_go14.go" || name == "slice_go18.go" {
775
776 continue
777 }
778 if !strings.HasSuffix(name, ".go") || strings.HasSuffix(name, "_test.go") {
779 continue
780 }
781 info := fileInfo{
782 name: filepath.Join(dir, name),
783 fset: fset,
784 }
785 f, err := os.Open(info.name)
786 if err != nil {
787 return nil, err
788 }
789 err = readGoInfo(f, &info)
790 f.Close()
791 if err != nil {
792 return nil, fmt.Errorf("reading %v: %v", name, err)
793 }
794 if info.parsed.Name.Name == "main" {
795 continue
796 }
797 if bytes.Contains(info.header, buildIgnore) {
798 continue
799 }
800 for _, imp := range info.imports {
801 path := imp.path
802 if !haveImport[path] {
803 haveImport[path] = true
804 imports = append(imports, path)
805 }
806 }
807 }
808 sort.Strings(imports)
809 return imports, nil
810 }
811
812
813 func depsPolicy(t *testing.T) *dag.Graph {
814 g, err := dag.Parse(depsRules)
815 if err != nil {
816 t.Fatal(err)
817 }
818 return g
819 }
820
821
822
823 func TestStdlibLowercase(t *testing.T) {
824 if !testenv.HasSrc() {
825 t.Skipf("skipping on %s/%s, missing full GOROOT", runtime.GOOS, runtime.GOARCH)
826 }
827
828 ctxt := Default
829 all, err := listStdPkgs(ctxt.GOROOT)
830 if err != nil {
831 t.Fatal(err)
832 }
833
834 for _, pkgname := range all {
835 if strings.ToLower(pkgname) != pkgname {
836 t.Errorf("package %q should not use upper-case path", pkgname)
837 }
838 }
839 }
840
841
842 func TestFindImports(t *testing.T) {
843 imports, err := findImports("go/build")
844 if err != nil {
845 t.Fatal(err)
846 }
847 t.Logf("go/build imports %q", imports)
848 want := []string{"bytes", "os", "path/filepath", "strings"}
849 wantLoop:
850 for _, w := range want {
851 for _, imp := range imports {
852 if imp == w {
853 continue wantLoop
854 }
855 }
856 t.Errorf("expected to find %q in import list", w)
857 }
858 }
859
View as plain text