blob: fbcf41eb9f187e9862bcba6a56352716af9ef7c6 [file] [log] [blame]
Shinichiro Hamajib69bf8a2015-06-10 14:52:06 +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
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +090015package kati
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090016
17import (
18 "fmt"
Fumitoshi Ukaiba408a22015-07-09 12:41:32 +090019 "os"
Fumitoshi Ukai49599e52015-06-26 10:10:24 +090020 "time"
Fumitoshi Ukai6450d0f2015-07-10 16:34:06 +090021
22 "github.com/golang/glog"
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090023)
24
Fumitoshi Ukai65c72332015-06-26 21:32:50 +090025// Executor manages execution of makefile rules.
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090026type Executor struct {
Fumitoshi Ukaiadc14442015-06-25 16:10:30 +090027 rules map[string]*rule
28 implicitRules []*rule
29 suffixRules map[string][]*rule
30 firstRule *rule
Shinichiro Hamaji74a66002015-04-27 16:42:30 +090031 // target -> Job, nil means the target is currently being processed.
Fumitoshi Ukaidfb518b2015-06-25 13:19:55 +090032 done map[string]*job
Shinichiro Hamaji74a66002015-04-27 16:42:30 +090033
Fumitoshi Ukaidfb518b2015-06-25 13:19:55 +090034 wm *workerManager
Shinichiro Hamaji110af332015-04-13 19:04:50 +090035
Fumitoshi Ukaia70b4ea2015-06-30 15:31:49 +090036 ctx *execContext
Shinichiro Hamajib0f65482015-04-16 18:28:05 +090037
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +090038 trace []string
39 buildCnt int
40 alreadyDoneCnt int
41 noRuleCnt int
42 upToDateCnt int
43 runCommandCnt int
Shinichiro Hamaji110af332015-04-13 19:04:50 +090044}
45
Fumitoshi Ukaidfb518b2015-06-25 13:19:55 +090046func (ex *Executor) makeJobs(n *DepNode, neededBy *job) error {
Fumitoshi Ukai09fcd522015-07-15 14:31:50 +090047 output, _ := ex.ctx.vpaths.exists(n.Output)
Shinichiro Hamaji74a66002015-04-27 16:42:30 +090048 if neededBy != nil {
Fumitoshi Ukai6450d0f2015-07-10 16:34:06 +090049 glog.V(1).Infof("MakeJob: %s for %s", output, neededBy.n.Output)
Shinichiro Hamaji74a66002015-04-27 16:42:30 +090050 }
Fumitoshi Ukaidd058ff2015-07-03 14:29:41 +090051 n.Output = output
Shinichiro Hamaji294a58b2015-04-14 15:31:52 +090052 ex.buildCnt++
53 if ex.buildCnt%100 == 0 {
54 ex.reportStats()
55 }
56
Shinichiro Hamaji74a66002015-04-27 16:42:30 +090057 j, present := ex.done[output]
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090058
Shinichiro Hamaji74a66002015-04-27 16:42:30 +090059 if present {
60 if j == nil {
61 if !n.IsPhony {
Shinichiro Hamaji69bb7e42015-04-27 17:54:42 +090062 fmt.Printf("Circular %s <- %s dependency dropped.\n", neededBy.n.Output, n.Output)
63 }
64 if neededBy != nil {
65 neededBy.numDeps--
Shinichiro Hamaji74a66002015-04-27 16:42:30 +090066 }
Shinichiro Hamajieb4da7f2015-04-11 20:28:54 +090067 } else {
Fumitoshi Ukai6450d0f2015-07-10 16:34:06 +090068 glog.Infof("%s already done: %d", j.n.Output, j.outputTs)
Shinichiro Hamaji74a66002015-04-27 16:42:30 +090069 if neededBy != nil {
Shinichiro Hamaji55c50bd2015-04-27 21:05:47 +090070 ex.wm.ReportNewDep(j, neededBy)
Shinichiro Hamaji74a66002015-04-27 16:42:30 +090071 }
Shinichiro Hamajieb4da7f2015-04-11 20:28:54 +090072 }
Shinichiro Hamaji74a66002015-04-27 16:42:30 +090073 return nil
Fumitoshi Ukai119dc912015-03-30 16:52:41 +090074 }
Shinichiro Hamaji4e9ab1a2015-04-12 01:31:58 +090075
Fumitoshi Ukaidfb518b2015-06-25 13:19:55 +090076 j = &job{
Shinichiro Hamaji74a66002015-04-27 16:42:30 +090077 n: n,
78 ex: ex,
Fumitoshi Ukaic916ea22015-06-30 09:52:13 +090079 numDeps: len(n.Deps) + len(n.OrderOnlys),
Shinichiro Hamaji74a66002015-04-27 16:42:30 +090080 depsTs: int64(-1),
81 }
82 if neededBy != nil {
83 j.parents = append(j.parents, neededBy)
84 }
85
86 ex.done[output] = nil
Shinichiro Hamaji69bb7e42015-04-27 17:54:42 +090087 // We iterate n.Deps twice. In the first run, we may modify
88 // numDeps. There will be a race if we do so after the first
89 // ex.makeJobs(d, j).
90 var deps []*DepNode
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +090091 for _, d := range n.Deps {
Fumitoshi Ukaic916ea22015-06-30 09:52:13 +090092 deps = append(deps, d)
93 }
94 for _, d := range n.OrderOnlys {
Fumitoshi Ukai09fcd522015-07-15 14:31:50 +090095 if _, ok := ex.ctx.vpaths.exists(d.Output); ok {
Shinichiro Hamaji74a66002015-04-27 16:42:30 +090096 j.numDeps--
Shinichiro Hamaji5c53b572015-04-02 05:36:42 +090097 continue
98 }
Shinichiro Hamaji69bb7e42015-04-27 17:54:42 +090099 deps = append(deps, d)
100 }
Fumitoshi Ukai6450d0f2015-07-10 16:34:06 +0900101 glog.V(1).Infof("new: %s (%d)", j.n.Output, j.numDeps)
Shinichiro Hamaji294a58b2015-04-14 15:31:52 +0900102
Shinichiro Hamaji69bb7e42015-04-27 17:54:42 +0900103 for _, d := range deps {
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900104 ex.trace = append(ex.trace, d.Output)
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900105 err := ex.makeJobs(d, j)
Shinichiro Hamaji294a58b2015-04-14 15:31:52 +0900106 ex.trace = ex.trace[0 : len(ex.trace)-1]
Shinichiro Hamaji5c53b572015-04-02 05:36:42 +0900107 if err != nil {
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900108 return err
Shinichiro Hamaji5c53b572015-04-02 05:36:42 +0900109 }
110 }
111
Shinichiro Hamaji74a66002015-04-27 16:42:30 +0900112 ex.done[output] = j
Fumitoshi Ukai531c5d22015-06-27 00:58:56 +0900113 return ex.wm.PostJob(j)
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900114}
115
Shinichiro Hamaji294a58b2015-04-14 15:31:52 +0900116func (ex *Executor) reportStats() {
Fumitoshi Ukai6450d0f2015-07-10 16:34:06 +0900117 if !PeriodicStatsFlag {
Shinichiro Hamaji294a58b2015-04-14 15:31:52 +0900118 return
119 }
120
Fumitoshi Ukai49599e52015-06-26 10:10:24 +0900121 logStats("build=%d alreadyDone=%d noRule=%d, upToDate=%d runCommand=%d",
Shinichiro Hamaji294a58b2015-04-14 15:31:52 +0900122 ex.buildCnt, ex.alreadyDoneCnt, ex.noRuleCnt, ex.upToDateCnt, ex.runCommandCnt)
Shinichiro Hamaji294a58b2015-04-14 15:31:52 +0900123 if len(ex.trace) > 1 {
Fumitoshi Ukai49599e52015-06-26 10:10:24 +0900124 logStats("trace=%q", ex.trace)
Shinichiro Hamaji294a58b2015-04-14 15:31:52 +0900125 }
126}
127
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900128// ExecutorOpt is an option for Executor.
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900129type ExecutorOpt struct {
Shinichiro Hamaji18287f02015-07-06 14:48:48 +0900130 NumJobs int
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900131}
132
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900133// NewExecutor creates new Executor.
Fumitoshi Ukaiba408a22015-07-09 12:41:32 +0900134func NewExecutor(opt *ExecutorOpt) (*Executor, error) {
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +0900135 if opt == nil {
136 opt = &ExecutorOpt{NumJobs: 1}
137 }
138 if opt.NumJobs < 1 {
139 opt.NumJobs = 1
140 }
Shinichiro Hamaji18287f02015-07-06 14:48:48 +0900141 wm, err := newWorkerManager(opt.NumJobs)
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900142 if err != nil {
143 return nil, err
144 }
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900145 ex := &Executor{
Fumitoshi Ukaiadc14442015-06-25 16:10:30 +0900146 rules: make(map[string]*rule),
147 suffixRules: make(map[string][]*rule),
Fumitoshi Ukaidfb518b2015-06-25 13:19:55 +0900148 done: make(map[string]*job),
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900149 wm: wm,
Shinichiro Hamaji17a8a6e2015-04-20 21:44:42 +0900150 }
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900151 return ex, nil
Shinichiro Hamaji8843a052015-04-13 16:46:56 +0900152}
Shinichiro Hamaji9b7d4622015-04-02 01:37:04 +0900153
Fumitoshi Ukaie4574692015-07-16 16:55:51 +0900154// Exec executes to build targets, or first target in DepGraph.
155func (ex *Executor) Exec(g *DepGraph, targets []string) error {
Fumitoshi Ukai09fcd522015-07-15 14:31:50 +0900156 ex.ctx = newExecContext(g.vars, g.vpaths, false)
Fumitoshi Ukaiba408a22015-07-09 12:41:32 +0900157
158 // TODO: Handle target specific variables.
159 for name, export := range g.exports {
160 if export {
161 v, err := ex.ctx.ev.EvaluateVar(name)
162 if err != nil {
163 return err
164 }
165 os.Setenv(name, v)
166 } else {
167 os.Unsetenv(name)
168 }
169 }
170
Fumitoshi Ukai49599e52015-06-26 10:10:24 +0900171 startTime := time.Now()
Fumitoshi Ukaie4574692015-07-16 16:55:51 +0900172 var nodes []*DepNode
173 if len(targets) == 0 {
174 if len(g.nodes) > 0 {
175 nodes = append(nodes, g.nodes[0])
176 }
177 } else {
178 m := make(map[string]*DepNode)
179 for _, n := range g.nodes {
180 m[n.Output] = n
181 }
182 for _, t := range targets {
183 n := m[t]
184 if n != nil {
185 nodes = append(nodes, n)
186 }
187 }
188 }
189 for _, root := range nodes {
Fumitoshi Ukai531c5d22015-06-27 00:58:56 +0900190 err := ex.makeJobs(root, nil)
191 if err != nil {
192 break
193 }
Shinichiro Hamajib13f3d52015-03-30 19:29:44 +0900194 }
Fumitoshi Ukaia43b96f2015-07-17 19:54:21 +0900195 n, err := ex.wm.Wait()
Fumitoshi Ukai49599e52015-06-26 10:10:24 +0900196 logStats("exec time: %q", time.Since(startTime))
Fumitoshi Ukaia43b96f2015-07-17 19:54:21 +0900197 if n == 0 {
198 for _, root := range nodes {
199 fmt.Printf("kati: Nothing to be done for `%s'.\n", root.Output)
200 }
201 }
Fumitoshi Ukai65c72332015-06-26 21:32:50 +0900202 return err
Fumitoshi Ukai119dc912015-03-30 16:52:41 +0900203}