xref: /aosp_15_r20/build/bazel/mkcompare/mkfile.go (revision 7594170e27e0732bc44b93d1440d87a54b6ffe7c)
1*7594170eSAndroid Build Coastguard Workerpackage mkcompare
2*7594170eSAndroid Build Coastguard Worker
3*7594170eSAndroid Build Coastguard Workerimport (
4*7594170eSAndroid Build Coastguard Worker	"bufio"
5*7594170eSAndroid Build Coastguard Worker	"fmt"
6*7594170eSAndroid Build Coastguard Worker	"github.com/google/go-cmp/cmp"
7*7594170eSAndroid Build Coastguard Worker	"io"
8*7594170eSAndroid Build Coastguard Worker	"regexp"
9*7594170eSAndroid Build Coastguard Worker	"sort"
10*7594170eSAndroid Build Coastguard Worker	"strings"
11*7594170eSAndroid Build Coastguard Worker)
12*7594170eSAndroid Build Coastguard Worker
13*7594170eSAndroid Build Coastguard Workertype MkVariable struct {
14*7594170eSAndroid Build Coastguard Worker	Name  string
15*7594170eSAndroid Build Coastguard Worker	Value string
16*7594170eSAndroid Build Coastguard Worker}
17*7594170eSAndroid Build Coastguard Worker
18*7594170eSAndroid Build Coastguard Workertype MkModule struct {
19*7594170eSAndroid Build Coastguard Worker	Type      string
20*7594170eSAndroid Build Coastguard Worker	Location  int
21*7594170eSAndroid Build Coastguard Worker	Extras    int
22*7594170eSAndroid Build Coastguard Worker	Variables map[string]string
23*7594170eSAndroid Build Coastguard Worker}
24*7594170eSAndroid Build Coastguard Worker
25*7594170eSAndroid Build Coastguard Workertype MkFile struct {
26*7594170eSAndroid Build Coastguard Worker	Path    string
27*7594170eSAndroid Build Coastguard Worker	Modules map[string]*MkModule
28*7594170eSAndroid Build Coastguard Worker}
29*7594170eSAndroid Build Coastguard Worker
30*7594170eSAndroid Build Coastguard Workertype myScanner struct {
31*7594170eSAndroid Build Coastguard Worker	*bufio.Scanner
32*7594170eSAndroid Build Coastguard Worker	lineNo int
33*7594170eSAndroid Build Coastguard Worker}
34*7594170eSAndroid Build Coastguard Worker
35*7594170eSAndroid Build Coastguard Workerfunc (s *myScanner) Scan() bool {
36*7594170eSAndroid Build Coastguard Worker	if s.Scanner.Scan() {
37*7594170eSAndroid Build Coastguard Worker		s.lineNo = s.lineNo + 1
38*7594170eSAndroid Build Coastguard Worker		return true
39*7594170eSAndroid Build Coastguard Worker	}
40*7594170eSAndroid Build Coastguard Worker	return false
41*7594170eSAndroid Build Coastguard Worker}
42*7594170eSAndroid Build Coastguard Worker
43*7594170eSAndroid Build Coastguard Workervar (
44*7594170eSAndroid Build Coastguard Worker	rexEmpty   = regexp.MustCompile("^ *$")
45*7594170eSAndroid Build Coastguard Worker	rexHeader  = regexp.MustCompile("^include +\\Q$(CLEAR_VARS)\\E *(# *(.*))?")
46*7594170eSAndroid Build Coastguard Worker	rexAssign  = regexp.MustCompile("^ *(.*) ([:+])= *(.*)$")
47*7594170eSAndroid Build Coastguard Worker	rexFooter  = regexp.MustCompile("^-?include *(.*)$")
48*7594170eSAndroid Build Coastguard Worker	rexIgnore1 = regexp.MustCompile("\\$\\(call dist-for-goals")
49*7594170eSAndroid Build Coastguard Worker	rexIgnore2 = regexp.MustCompile("\\$\\(LOCAL_INSTALLED_MODULE\\)")
50*7594170eSAndroid Build Coastguard Worker)
51*7594170eSAndroid Build Coastguard Worker
52*7594170eSAndroid Build Coastguard Workerconst (
53*7594170eSAndroid Build Coastguard Worker	rexPairsHeader = 6
54*7594170eSAndroid Build Coastguard Worker	rexPairsAssign = 8
55*7594170eSAndroid Build Coastguard Worker	rexPairsFooter = 4
56*7594170eSAndroid Build Coastguard Worker)
57*7594170eSAndroid Build Coastguard Worker
58*7594170eSAndroid Build Coastguard Workerfunc (mk *MkFile) handleModule(scanner *myScanner, moduleType string) (*MkModule, error) {
59*7594170eSAndroid Build Coastguard Worker	mod := MkModule{Location: scanner.lineNo, Type: moduleType, Variables: make(map[string]string)}
60*7594170eSAndroid Build Coastguard Worker	includePath := ""
61*7594170eSAndroid Build Coastguard Worker	for scanner.Scan() {
62*7594170eSAndroid Build Coastguard Worker		line := scanner.Text()
63*7594170eSAndroid Build Coastguard Worker		if rexEmpty.MatchString(line) {
64*7594170eSAndroid Build Coastguard Worker			break
65*7594170eSAndroid Build Coastguard Worker		}
66*7594170eSAndroid Build Coastguard Worker		if m := rexAssign.FindStringSubmatchIndex(line); len(m) == rexPairsAssign {
67*7594170eSAndroid Build Coastguard Worker			v := line[m[2]:m[3]]
68*7594170eSAndroid Build Coastguard Worker			if line[m[4]:m[5]] == "+" {
69*7594170eSAndroid Build Coastguard Worker				mod.Variables[v] = mod.Variables[v] + line[m[6]:m[7]]
70*7594170eSAndroid Build Coastguard Worker			} else {
71*7594170eSAndroid Build Coastguard Worker				mod.Variables[v] = line[m[6]:m[7]]
72*7594170eSAndroid Build Coastguard Worker			}
73*7594170eSAndroid Build Coastguard Worker		} else if m := rexFooter.FindStringSubmatchIndex(line); len(m) == rexPairsFooter {
74*7594170eSAndroid Build Coastguard Worker			if includePath != "" {
75*7594170eSAndroid Build Coastguard Worker				return nil, fmt.Errorf("%d: second include for module", scanner.lineNo)
76*7594170eSAndroid Build Coastguard Worker			}
77*7594170eSAndroid Build Coastguard Worker			includePath = strings.TrimSpace(line[m[2]:m[3]])
78*7594170eSAndroid Build Coastguard Worker			if mod.Type == "" {
79*7594170eSAndroid Build Coastguard Worker				mod.Type = includePath
80*7594170eSAndroid Build Coastguard Worker			}
81*7594170eSAndroid Build Coastguard Worker		} else if mod.Type != "" {
82*7594170eSAndroid Build Coastguard Worker			mod.Extras = mod.Extras + 1
83*7594170eSAndroid Build Coastguard Worker			continue
84*7594170eSAndroid Build Coastguard Worker		} else if rexIgnore1.MatchString(line) {
85*7594170eSAndroid Build Coastguard Worker			continue
86*7594170eSAndroid Build Coastguard Worker		} else if rexIgnore2.MatchString(line) {
87*7594170eSAndroid Build Coastguard Worker			continue
88*7594170eSAndroid Build Coastguard Worker		} else {
89*7594170eSAndroid Build Coastguard Worker			return nil, fmt.Errorf("%d: unexpected line:\n%s", scanner.lineNo, line)
90*7594170eSAndroid Build Coastguard Worker		}
91*7594170eSAndroid Build Coastguard Worker	}
92*7594170eSAndroid Build Coastguard Worker	return &mod, scanner.Err()
93*7594170eSAndroid Build Coastguard Worker}
94*7594170eSAndroid Build Coastguard Worker
95*7594170eSAndroid Build Coastguard Workerfunc (mk *MkFile) ModulesByType(names []string) (sortedKeys []string, byType map[string][]string) {
96*7594170eSAndroid Build Coastguard Worker	byType = make(map[string][]string)
97*7594170eSAndroid Build Coastguard Worker	for _, name := range names {
98*7594170eSAndroid Build Coastguard Worker		mod, ok := mk.Modules[name]
99*7594170eSAndroid Build Coastguard Worker		if !ok {
100*7594170eSAndroid Build Coastguard Worker			break
101*7594170eSAndroid Build Coastguard Worker		}
102*7594170eSAndroid Build Coastguard Worker		mt := mod.Type
103*7594170eSAndroid Build Coastguard Worker		v, ok := byType[mt]
104*7594170eSAndroid Build Coastguard Worker		if !ok {
105*7594170eSAndroid Build Coastguard Worker			sortedKeys = append(sortedKeys, mt)
106*7594170eSAndroid Build Coastguard Worker		}
107*7594170eSAndroid Build Coastguard Worker		byType[mt] = append(v, name)
108*7594170eSAndroid Build Coastguard Worker	}
109*7594170eSAndroid Build Coastguard Worker	sort.Strings(sortedKeys)
110*7594170eSAndroid Build Coastguard Worker	return
111*7594170eSAndroid Build Coastguard Worker}
112*7594170eSAndroid Build Coastguard Worker
113*7594170eSAndroid Build Coastguard Workerfunc (mk *MkFile) moduleKey(mod *MkModule) (string, error) {
114*7594170eSAndroid Build Coastguard Worker	// Synthesize unique module name.
115*7594170eSAndroid Build Coastguard Worker	name := mod.Variables["LOCAL_MODULE"]
116*7594170eSAndroid Build Coastguard Worker	if name == "" {
117*7594170eSAndroid Build Coastguard Worker		return "", fmt.Errorf("%d: the module above lacks LOCAL_MODULE assignment", mod.Location)
118*7594170eSAndroid Build Coastguard Worker	}
119*7594170eSAndroid Build Coastguard Worker	var buf strings.Builder
120*7594170eSAndroid Build Coastguard Worker	writebuf := func(chunks ...string) {
121*7594170eSAndroid Build Coastguard Worker		for _, s := range chunks {
122*7594170eSAndroid Build Coastguard Worker			buf.WriteString(s)
123*7594170eSAndroid Build Coastguard Worker		}
124*7594170eSAndroid Build Coastguard Worker	}
125*7594170eSAndroid Build Coastguard Worker
126*7594170eSAndroid Build Coastguard Worker	writebuf(name, "|class:", mod.Variables["LOCAL_MODULE_CLASS"])
127*7594170eSAndroid Build Coastguard Worker	if mod.Variables["LOCAL_IS_HOST_MODULE"] == "true" {
128*7594170eSAndroid Build Coastguard Worker		if v, ok := mod.Variables["LOCAL_MODULE_HOST_ARCH"]; ok {
129*7594170eSAndroid Build Coastguard Worker			writebuf("|host_arch:", v)
130*7594170eSAndroid Build Coastguard Worker		}
131*7594170eSAndroid Build Coastguard Worker		if v, ok := mod.Variables["LOCAL_MODULE_HOST_CROSS_ARCH"]; ok {
132*7594170eSAndroid Build Coastguard Worker			writebuf("|cross_arch:", v)
133*7594170eSAndroid Build Coastguard Worker		}
134*7594170eSAndroid Build Coastguard Worker	} else {
135*7594170eSAndroid Build Coastguard Worker		if v, ok := mod.Variables["LOCAL_MODULE_TARGET_ARCH"]; ok {
136*7594170eSAndroid Build Coastguard Worker			writebuf("|target_arch:", v)
137*7594170eSAndroid Build Coastguard Worker		} else {
138*7594170eSAndroid Build Coastguard Worker			writebuf("|target_arch:*")
139*7594170eSAndroid Build Coastguard Worker		}
140*7594170eSAndroid Build Coastguard Worker	}
141*7594170eSAndroid Build Coastguard Worker	return buf.String(), nil
142*7594170eSAndroid Build Coastguard Worker}
143*7594170eSAndroid Build Coastguard Worker
144*7594170eSAndroid Build Coastguard Worker// ParseMkFile parses Android-TARGET.mk file generated by Android build
145*7594170eSAndroid Build Coastguard Workerfunc ParseMkFile(source io.Reader) (*MkFile, error) {
146*7594170eSAndroid Build Coastguard Worker	scanner := &myScanner{bufio.NewScanner(source), 0}
147*7594170eSAndroid Build Coastguard Worker	buffer := make([]byte, 1000000000)
148*7594170eSAndroid Build Coastguard Worker	scanner.Scanner.Buffer(buffer, len(buffer))
149*7594170eSAndroid Build Coastguard Worker	mkFile := &MkFile{Modules: make(map[string]*MkModule)}
150*7594170eSAndroid Build Coastguard Worker
151*7594170eSAndroid Build Coastguard Worker	for scanner.Scan() {
152*7594170eSAndroid Build Coastguard Worker		line := scanner.Text()
153*7594170eSAndroid Build Coastguard Worker		m := rexHeader.FindStringSubmatchIndex(line)
154*7594170eSAndroid Build Coastguard Worker		if len(m) != rexPairsHeader {
155*7594170eSAndroid Build Coastguard Worker			continue
156*7594170eSAndroid Build Coastguard Worker		}
157*7594170eSAndroid Build Coastguard Worker		moduleType := ""
158*7594170eSAndroid Build Coastguard Worker		if m[4] >= 0 {
159*7594170eSAndroid Build Coastguard Worker			moduleType = line[m[4]:m[5]]
160*7594170eSAndroid Build Coastguard Worker		}
161*7594170eSAndroid Build Coastguard Worker		mod, err := mkFile.handleModule(scanner, moduleType)
162*7594170eSAndroid Build Coastguard Worker		if err != nil {
163*7594170eSAndroid Build Coastguard Worker			return mkFile, err
164*7594170eSAndroid Build Coastguard Worker		}
165*7594170eSAndroid Build Coastguard Worker		name, err := mkFile.moduleKey(mod)
166*7594170eSAndroid Build Coastguard Worker		if err != nil {
167*7594170eSAndroid Build Coastguard Worker			return mkFile, err
168*7594170eSAndroid Build Coastguard Worker		}
169*7594170eSAndroid Build Coastguard Worker		if old, found := mkFile.Modules[name]; found {
170*7594170eSAndroid Build Coastguard Worker			return mkFile, fmt.Errorf(":%d: module %s already found, diff: %s", old.Location, name, cmp.Diff(old, mod))
171*7594170eSAndroid Build Coastguard Worker		}
172*7594170eSAndroid Build Coastguard Worker		mkFile.Modules[name] = mod
173*7594170eSAndroid Build Coastguard Worker	}
174*7594170eSAndroid Build Coastguard Worker	return mkFile, scanner.Err()
175*7594170eSAndroid Build Coastguard Worker}
176