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