xref: /aosp_15_r20/external/boringssl/src/util/godeps.go (revision 8fb009dc861624b67b6cdb62ea21f0f22d0c584b)
1*8fb009dcSAndroid Build Coastguard Worker// Copyright (c) 2018, Google Inc.
2*8fb009dcSAndroid Build Coastguard Worker//
3*8fb009dcSAndroid Build Coastguard Worker// Permission to use, copy, modify, and/or distribute this software for any
4*8fb009dcSAndroid Build Coastguard Worker// purpose with or without fee is hereby granted, provided that the above
5*8fb009dcSAndroid Build Coastguard Worker// copyright notice and this permission notice appear in all copies.
6*8fb009dcSAndroid Build Coastguard Worker//
7*8fb009dcSAndroid Build Coastguard Worker// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8*8fb009dcSAndroid Build Coastguard Worker// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9*8fb009dcSAndroid Build Coastguard Worker// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10*8fb009dcSAndroid Build Coastguard Worker// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11*8fb009dcSAndroid Build Coastguard Worker// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12*8fb009dcSAndroid Build Coastguard Worker// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13*8fb009dcSAndroid Build Coastguard Worker// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14*8fb009dcSAndroid Build Coastguard Worker
15*8fb009dcSAndroid Build Coastguard Worker//go:build ignore
16*8fb009dcSAndroid Build Coastguard Worker
17*8fb009dcSAndroid Build Coastguard Worker// godeps prints out dependencies of a package in either CMake or Make depfile
18*8fb009dcSAndroid Build Coastguard Worker// format, for incremental rebuilds.
19*8fb009dcSAndroid Build Coastguard Worker//
20*8fb009dcSAndroid Build Coastguard Worker// The depfile format is preferred. It works correctly when new files are added.
21*8fb009dcSAndroid Build Coastguard Worker// However, CMake only supports depfiles for custom commands with Ninja and
22*8fb009dcSAndroid Build Coastguard Worker// starting CMake 3.7. For other configurations, we also support CMake's format,
23*8fb009dcSAndroid Build Coastguard Worker// but CMake must be rerun when file lists change.
24*8fb009dcSAndroid Build Coastguard Workerpackage main
25*8fb009dcSAndroid Build Coastguard Worker
26*8fb009dcSAndroid Build Coastguard Workerimport (
27*8fb009dcSAndroid Build Coastguard Worker	"flag"
28*8fb009dcSAndroid Build Coastguard Worker	"fmt"
29*8fb009dcSAndroid Build Coastguard Worker	"go/build"
30*8fb009dcSAndroid Build Coastguard Worker	"os"
31*8fb009dcSAndroid Build Coastguard Worker	"path/filepath"
32*8fb009dcSAndroid Build Coastguard Worker	"sort"
33*8fb009dcSAndroid Build Coastguard Worker	"strings"
34*8fb009dcSAndroid Build Coastguard Worker)
35*8fb009dcSAndroid Build Coastguard Worker
36*8fb009dcSAndroid Build Coastguard Workervar (
37*8fb009dcSAndroid Build Coastguard Worker	format  = flag.String("format", "cmake", "The format to output to, either 'cmake' or 'depfile'")
38*8fb009dcSAndroid Build Coastguard Worker	mainPkg = flag.String("pkg", "", "The package to print dependencies for")
39*8fb009dcSAndroid Build Coastguard Worker	target  = flag.String("target", "", "The name of the output file")
40*8fb009dcSAndroid Build Coastguard Worker	out     = flag.String("out", "", "The path to write the output to. If unset, this is stdout")
41*8fb009dcSAndroid Build Coastguard Worker)
42*8fb009dcSAndroid Build Coastguard Worker
43*8fb009dcSAndroid Build Coastguard Workerfunc cMakeQuote(in string) string {
44*8fb009dcSAndroid Build Coastguard Worker	// See https://cmake.org/cmake/help/v3.0/manual/cmake-language.7.html#quoted-argument
45*8fb009dcSAndroid Build Coastguard Worker	var b strings.Builder
46*8fb009dcSAndroid Build Coastguard Worker	b.Grow(len(in))
47*8fb009dcSAndroid Build Coastguard Worker	// Iterate over in as bytes.
48*8fb009dcSAndroid Build Coastguard Worker	for i := 0; i < len(in); i++ {
49*8fb009dcSAndroid Build Coastguard Worker		switch c := in[i]; c {
50*8fb009dcSAndroid Build Coastguard Worker		case '\\', '"':
51*8fb009dcSAndroid Build Coastguard Worker			b.WriteByte('\\')
52*8fb009dcSAndroid Build Coastguard Worker			b.WriteByte(c)
53*8fb009dcSAndroid Build Coastguard Worker		case '\t':
54*8fb009dcSAndroid Build Coastguard Worker			b.WriteString("\\t")
55*8fb009dcSAndroid Build Coastguard Worker		case '\r':
56*8fb009dcSAndroid Build Coastguard Worker			b.WriteString("\\r")
57*8fb009dcSAndroid Build Coastguard Worker		case '\n':
58*8fb009dcSAndroid Build Coastguard Worker			b.WriteString("\\n")
59*8fb009dcSAndroid Build Coastguard Worker		default:
60*8fb009dcSAndroid Build Coastguard Worker			b.WriteByte(in[i])
61*8fb009dcSAndroid Build Coastguard Worker		}
62*8fb009dcSAndroid Build Coastguard Worker	}
63*8fb009dcSAndroid Build Coastguard Worker	return b.String()
64*8fb009dcSAndroid Build Coastguard Worker}
65*8fb009dcSAndroid Build Coastguard Worker
66*8fb009dcSAndroid Build Coastguard Workerfunc writeCMake(outFile *os.File, files []string) error {
67*8fb009dcSAndroid Build Coastguard Worker	for i, file := range files {
68*8fb009dcSAndroid Build Coastguard Worker		if i != 0 {
69*8fb009dcSAndroid Build Coastguard Worker			if _, err := outFile.WriteString(";"); err != nil {
70*8fb009dcSAndroid Build Coastguard Worker				return err
71*8fb009dcSAndroid Build Coastguard Worker			}
72*8fb009dcSAndroid Build Coastguard Worker		}
73*8fb009dcSAndroid Build Coastguard Worker		if _, err := outFile.WriteString(cMakeQuote(file)); err != nil {
74*8fb009dcSAndroid Build Coastguard Worker			return err
75*8fb009dcSAndroid Build Coastguard Worker		}
76*8fb009dcSAndroid Build Coastguard Worker	}
77*8fb009dcSAndroid Build Coastguard Worker	return nil
78*8fb009dcSAndroid Build Coastguard Worker}
79*8fb009dcSAndroid Build Coastguard Worker
80*8fb009dcSAndroid Build Coastguard Workerfunc makeQuote(in string) string {
81*8fb009dcSAndroid Build Coastguard Worker	// See https://www.gnu.org/software/make/manual/make.html#Rule-Syntax
82*8fb009dcSAndroid Build Coastguard Worker	var b strings.Builder
83*8fb009dcSAndroid Build Coastguard Worker	b.Grow(len(in))
84*8fb009dcSAndroid Build Coastguard Worker	// Iterate over in as bytes.
85*8fb009dcSAndroid Build Coastguard Worker	for i := 0; i < len(in); i++ {
86*8fb009dcSAndroid Build Coastguard Worker		switch c := in[i]; c {
87*8fb009dcSAndroid Build Coastguard Worker		case '$':
88*8fb009dcSAndroid Build Coastguard Worker			b.WriteString("$$")
89*8fb009dcSAndroid Build Coastguard Worker		case '#', '\\', ' ':
90*8fb009dcSAndroid Build Coastguard Worker			b.WriteByte('\\')
91*8fb009dcSAndroid Build Coastguard Worker			b.WriteByte(c)
92*8fb009dcSAndroid Build Coastguard Worker		default:
93*8fb009dcSAndroid Build Coastguard Worker			b.WriteByte(c)
94*8fb009dcSAndroid Build Coastguard Worker		}
95*8fb009dcSAndroid Build Coastguard Worker	}
96*8fb009dcSAndroid Build Coastguard Worker	return b.String()
97*8fb009dcSAndroid Build Coastguard Worker}
98*8fb009dcSAndroid Build Coastguard Worker
99*8fb009dcSAndroid Build Coastguard Workerfunc writeDepfile(outFile *os.File, files []string) error {
100*8fb009dcSAndroid Build Coastguard Worker	if _, err := fmt.Fprintf(outFile, "%s:", makeQuote(*target)); err != nil {
101*8fb009dcSAndroid Build Coastguard Worker		return err
102*8fb009dcSAndroid Build Coastguard Worker	}
103*8fb009dcSAndroid Build Coastguard Worker	for _, file := range files {
104*8fb009dcSAndroid Build Coastguard Worker		if _, err := fmt.Fprintf(outFile, " %s", makeQuote(file)); err != nil {
105*8fb009dcSAndroid Build Coastguard Worker			return err
106*8fb009dcSAndroid Build Coastguard Worker		}
107*8fb009dcSAndroid Build Coastguard Worker	}
108*8fb009dcSAndroid Build Coastguard Worker	_, err := outFile.WriteString("\n")
109*8fb009dcSAndroid Build Coastguard Worker	return err
110*8fb009dcSAndroid Build Coastguard Worker}
111*8fb009dcSAndroid Build Coastguard Worker
112*8fb009dcSAndroid Build Coastguard Workerfunc appendPrefixed(list, newFiles []string, prefix string) []string {
113*8fb009dcSAndroid Build Coastguard Worker	for _, file := range newFiles {
114*8fb009dcSAndroid Build Coastguard Worker		list = append(list, filepath.Join(prefix, file))
115*8fb009dcSAndroid Build Coastguard Worker	}
116*8fb009dcSAndroid Build Coastguard Worker	return list
117*8fb009dcSAndroid Build Coastguard Worker}
118*8fb009dcSAndroid Build Coastguard Worker
119*8fb009dcSAndroid Build Coastguard Workerfunc main() {
120*8fb009dcSAndroid Build Coastguard Worker	flag.Parse()
121*8fb009dcSAndroid Build Coastguard Worker
122*8fb009dcSAndroid Build Coastguard Worker	if len(*mainPkg) == 0 {
123*8fb009dcSAndroid Build Coastguard Worker		fmt.Fprintf(os.Stderr, "-pkg argument is required.\n")
124*8fb009dcSAndroid Build Coastguard Worker		os.Exit(1)
125*8fb009dcSAndroid Build Coastguard Worker	}
126*8fb009dcSAndroid Build Coastguard Worker
127*8fb009dcSAndroid Build Coastguard Worker	var isDepfile bool
128*8fb009dcSAndroid Build Coastguard Worker	switch *format {
129*8fb009dcSAndroid Build Coastguard Worker	case "depfile":
130*8fb009dcSAndroid Build Coastguard Worker		isDepfile = true
131*8fb009dcSAndroid Build Coastguard Worker	case "cmake":
132*8fb009dcSAndroid Build Coastguard Worker		isDepfile = false
133*8fb009dcSAndroid Build Coastguard Worker	default:
134*8fb009dcSAndroid Build Coastguard Worker		fmt.Fprintf(os.Stderr, "Unknown format: %q\n", *format)
135*8fb009dcSAndroid Build Coastguard Worker		os.Exit(1)
136*8fb009dcSAndroid Build Coastguard Worker	}
137*8fb009dcSAndroid Build Coastguard Worker
138*8fb009dcSAndroid Build Coastguard Worker	if isDepfile && len(*target) == 0 {
139*8fb009dcSAndroid Build Coastguard Worker		fmt.Fprintf(os.Stderr, "-target argument is required for depfile.\n")
140*8fb009dcSAndroid Build Coastguard Worker		os.Exit(1)
141*8fb009dcSAndroid Build Coastguard Worker	}
142*8fb009dcSAndroid Build Coastguard Worker
143*8fb009dcSAndroid Build Coastguard Worker	done := make(map[string]struct{})
144*8fb009dcSAndroid Build Coastguard Worker	var files []string
145*8fb009dcSAndroid Build Coastguard Worker	var recurse func(pkgName string) error
146*8fb009dcSAndroid Build Coastguard Worker	recurse = func(pkgName string) error {
147*8fb009dcSAndroid Build Coastguard Worker		pkg, err := build.Default.Import(pkgName, ".", 0)
148*8fb009dcSAndroid Build Coastguard Worker		if err != nil {
149*8fb009dcSAndroid Build Coastguard Worker			return err
150*8fb009dcSAndroid Build Coastguard Worker		}
151*8fb009dcSAndroid Build Coastguard Worker
152*8fb009dcSAndroid Build Coastguard Worker		// Skip standard packages.
153*8fb009dcSAndroid Build Coastguard Worker		if pkg.Goroot {
154*8fb009dcSAndroid Build Coastguard Worker			return nil
155*8fb009dcSAndroid Build Coastguard Worker		}
156*8fb009dcSAndroid Build Coastguard Worker
157*8fb009dcSAndroid Build Coastguard Worker		// Skip already-visited packages.
158*8fb009dcSAndroid Build Coastguard Worker		if _, ok := done[pkg.Dir]; ok {
159*8fb009dcSAndroid Build Coastguard Worker			return nil
160*8fb009dcSAndroid Build Coastguard Worker		}
161*8fb009dcSAndroid Build Coastguard Worker		done[pkg.Dir] = struct{}{}
162*8fb009dcSAndroid Build Coastguard Worker
163*8fb009dcSAndroid Build Coastguard Worker		files = appendPrefixed(files, pkg.GoFiles, pkg.Dir)
164*8fb009dcSAndroid Build Coastguard Worker		files = appendPrefixed(files, pkg.CgoFiles, pkg.Dir)
165*8fb009dcSAndroid Build Coastguard Worker		// Include ignored Go files. A subsequent change may cause them
166*8fb009dcSAndroid Build Coastguard Worker		// to no longer be ignored.
167*8fb009dcSAndroid Build Coastguard Worker		files = appendPrefixed(files, pkg.IgnoredGoFiles, pkg.Dir)
168*8fb009dcSAndroid Build Coastguard Worker
169*8fb009dcSAndroid Build Coastguard Worker		// Recurse into imports.
170*8fb009dcSAndroid Build Coastguard Worker		for _, importName := range pkg.Imports {
171*8fb009dcSAndroid Build Coastguard Worker			if err := recurse(importName); err != nil {
172*8fb009dcSAndroid Build Coastguard Worker				return err
173*8fb009dcSAndroid Build Coastguard Worker			}
174*8fb009dcSAndroid Build Coastguard Worker		}
175*8fb009dcSAndroid Build Coastguard Worker		return nil
176*8fb009dcSAndroid Build Coastguard Worker	}
177*8fb009dcSAndroid Build Coastguard Worker	if err := recurse(*mainPkg); err != nil {
178*8fb009dcSAndroid Build Coastguard Worker		fmt.Fprintf(os.Stderr, "Error getting dependencies: %s\n", err)
179*8fb009dcSAndroid Build Coastguard Worker		os.Exit(1)
180*8fb009dcSAndroid Build Coastguard Worker	}
181*8fb009dcSAndroid Build Coastguard Worker
182*8fb009dcSAndroid Build Coastguard Worker	sort.Strings(files)
183*8fb009dcSAndroid Build Coastguard Worker
184*8fb009dcSAndroid Build Coastguard Worker	outFile := os.Stdout
185*8fb009dcSAndroid Build Coastguard Worker	if len(*out) != 0 {
186*8fb009dcSAndroid Build Coastguard Worker		var err error
187*8fb009dcSAndroid Build Coastguard Worker		outFile, err = os.Create(*out)
188*8fb009dcSAndroid Build Coastguard Worker		if err != nil {
189*8fb009dcSAndroid Build Coastguard Worker			fmt.Fprintf(os.Stderr, "Error writing output: %s\n", err)
190*8fb009dcSAndroid Build Coastguard Worker			os.Exit(1)
191*8fb009dcSAndroid Build Coastguard Worker		}
192*8fb009dcSAndroid Build Coastguard Worker		defer outFile.Close()
193*8fb009dcSAndroid Build Coastguard Worker	}
194*8fb009dcSAndroid Build Coastguard Worker
195*8fb009dcSAndroid Build Coastguard Worker	var err error
196*8fb009dcSAndroid Build Coastguard Worker	if isDepfile {
197*8fb009dcSAndroid Build Coastguard Worker		err = writeDepfile(outFile, files)
198*8fb009dcSAndroid Build Coastguard Worker	} else {
199*8fb009dcSAndroid Build Coastguard Worker		err = writeCMake(outFile, files)
200*8fb009dcSAndroid Build Coastguard Worker	}
201*8fb009dcSAndroid Build Coastguard Worker	if err != nil {
202*8fb009dcSAndroid Build Coastguard Worker		fmt.Fprintf(os.Stderr, "Error writing output: %s\n", err)
203*8fb009dcSAndroid Build Coastguard Worker		os.Exit(1)
204*8fb009dcSAndroid Build Coastguard Worker	}
205*8fb009dcSAndroid Build Coastguard Worker}
206