blob: 043fa926f2131e0af438cd8f4b8c939cf5a8b753 [file] [log] [blame]
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +09001// Copyright 2015 Google Inc. All rights reserved
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package kati
16
17import (
18 "crypto/sha1"
Fumitoshi Ukai87586e52015-06-25 17:49:35 +090019 "fmt"
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +090020 "io/ioutil"
Fumitoshi Ukai87586e52015-06-25 17:49:35 +090021 "strings"
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +090022 "time"
23)
24
25type DepGraph struct {
Fumitoshi Ukai0af44522015-06-25 15:26:08 +090026 nodes []*DepNode
27 vars Vars
28 accessedMks []*accessedMakefile
29 exports map[string]bool
30 isCached bool
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +090031}
32
33func (g *DepGraph) Nodes() []*DepNode { return g.nodes }
34func (g *DepGraph) Vars() Vars { return g.vars }
35func (g *DepGraph) Exports() map[string]bool { return g.exports }
36func (g *DepGraph) IsCached() bool { return g.isCached }
37
Fumitoshi Ukai87586e52015-06-25 17:49:35 +090038type LoadReq struct {
39 Makefile string
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +090040 Targets []string
41 CommandLineVars []string
42 EnvironmentVars []string
43 UseCache bool
44}
45
Fumitoshi Ukai87586e52015-06-25 17:49:35 +090046func FromCommandLine(cmdline []string) LoadReq {
47 var vars []string
48 var targets []string
49 for _, arg := range cmdline {
50 if strings.IndexByte(arg, '=') >= 0 {
51 vars = append(vars, arg)
52 continue
53 }
54 targets = append(targets, arg)
55 }
56 return LoadReq{
57 Makefile: defaultMakefile(),
58 Targets: targets,
59 CommandLineVars: vars,
60 }
61}
62
63func initVars(vars Vars, kvlist []string, origin string) error {
64 for _, v := range kvlist {
65 kv := strings.SplitN(v, "=", 2)
66 logf("%s var %q", origin, v)
67 if len(kv) < 2 {
68 return fmt.Errorf("A weird %s variable %q", origin, kv)
69 }
70 vars.Assign(kv[0], &recursiveVar{
71 expr: literal(kv[1]),
72 origin: origin,
73 })
74 }
75 return nil
76}
77
78func Load(req LoadReq) (*DepGraph, error) {
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +090079 startTime := time.Now()
Fumitoshi Ukai87586e52015-06-25 17:49:35 +090080 if req.Makefile == "" {
81 req.Makefile = defaultMakefile()
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +090082 }
83
Fumitoshi Ukai87586e52015-06-25 17:49:35 +090084 if req.UseCache {
Fumitoshi Ukai4bb4cd52015-06-25 18:07:21 +090085 g := loadDepGraphCache(req.Makefile, req.Targets)
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +090086 if g != nil {
87 return g, nil
88 }
89 }
90
Fumitoshi Ukai87586e52015-06-25 17:49:35 +090091 bmk := bootstrapMakefile(req.Targets)
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +090092
Fumitoshi Ukai87586e52015-06-25 17:49:35 +090093 content, err := ioutil.ReadFile(req.Makefile)
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +090094 if err != nil {
95 return nil, err
96 }
Fumitoshi Ukai87586e52015-06-25 17:49:35 +090097 mk, err := parseMakefile(content, req.Makefile)
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +090098 if err != nil {
99 return nil, err
100 }
101
102 for _, stmt := range mk.stmts {
103 stmt.show()
104 }
105
106 mk.stmts = append(bmk.stmts, mk.stmts...)
107
108 vars := make(Vars)
Fumitoshi Ukai87586e52015-06-25 17:49:35 +0900109 err = initVars(vars, req.EnvironmentVars, "environment")
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900110 if err != nil {
111 return nil, err
112 }
Fumitoshi Ukai87586e52015-06-25 17:49:35 +0900113 err = initVars(vars, req.CommandLineVars, "command line")
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900114 if err != nil {
115 return nil, err
116 }
Fumitoshi Ukai87586e52015-06-25 17:49:35 +0900117 er, err := eval(mk, vars, req.UseCache)
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900118 if err != nil {
119 return nil, err
120 }
121 vars.Merge(er.vars)
122
123 LogStats("eval time: %q", time.Since(startTime))
124 LogStats("shell func time: %q %d", shellStats.Duration(), shellStats.Count())
125
126 startTime = time.Now()
Fumitoshi Ukaic9ff91b2015-06-25 15:58:36 +0900127 db := newDepBuilder(er, vars)
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900128 LogStats("dep build prepare time: %q", time.Since(startTime))
129
130 startTime = time.Now()
Fumitoshi Ukai87586e52015-06-25 17:49:35 +0900131 nodes, err := db.Eval(req.Targets)
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900132 if err != nil {
133 return nil, err
134 }
135 LogStats("dep build time: %q", time.Since(startTime))
Fumitoshi Ukai0af44522015-06-25 15:26:08 +0900136 var accessedMks []*accessedMakefile
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900137 // Always put the root Makefile as the first element.
Fumitoshi Ukai0af44522015-06-25 15:26:08 +0900138 accessedMks = append(accessedMks, &accessedMakefile{
Fumitoshi Ukai87586e52015-06-25 17:49:35 +0900139 Filename: req.Makefile,
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900140 Hash: sha1.Sum(content),
Fumitoshi Ukai0af44522015-06-25 15:26:08 +0900141 State: fileExists,
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900142 })
Fumitoshi Ukai0af44522015-06-25 15:26:08 +0900143 accessedMks = append(accessedMks, er.accessedMks...)
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900144 return &DepGraph{
Fumitoshi Ukai0af44522015-06-25 15:26:08 +0900145 nodes: nodes,
146 vars: vars,
147 accessedMks: accessedMks,
148 exports: er.exports,
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900149 }, nil
150}
Fumitoshi Ukai4bb4cd52015-06-25 18:07:21 +0900151
152type Loader interface {
153 Load(string) (*DepGraph, error)
154}
155
156type Saver interface {
157 Save(*DepGraph, string, []string) error
158}
159
160type LoadSaver interface {
161 Loader
162 Saver
163}