aboutsummaryrefslogtreecommitdiff
path: root/ninja.go
diff options
context:
space:
mode:
authorFumitoshi Ukai <ukai@google.com>2015-07-27 16:50:00 +0900
committerFumitoshi Ukai <ukai@google.com>2015-07-27 16:50:00 +0900
commitd4a016e6d7e6e67d549c9e753494704a9df821a3 (patch)
tree7a003fe14d2a5351b0eee77a4c49627335b7b4da /ninja.go
parent41957e0349f042904a8dd5d7ba74f38c0a215c92 (diff)
[go] backport [C++] ninja file regeneration rules
Diffstat (limited to 'ninja.go')
-rw-r--r--ninja.go117
1 files changed, 101 insertions, 16 deletions
diff --git a/ninja.go b/ninja.go
index 45de622..1203376 100644
--- a/ninja.go
+++ b/ninja.go
@@ -28,10 +28,16 @@ import (
// NinjaGenerator generates ninja build files from DepGraph.
type NinjaGenerator struct {
+ // Args is original arguments to generate the ninja file.
+ Args []string
+ // Suffix is suffix for generated files.
+ Suffix string
// GomaDir is goma directory. If empty, goma will not be used.
GomaDir string
// DetectAndroidEcho detects echo as description.
DetectAndroidEcho bool
+ // ErrorOnEnvChange cause error when env change is detected when run ninja.
+ ErrorOnEnvChange bool
f *os.File
nodes []*DepNode
@@ -447,16 +453,85 @@ func (n *NinjaGenerator) emitNode(node *DepNode) error {
return nil
}
-func (n *NinjaGenerator) shName(suffix string) string {
- return fmt.Sprintf("ninja%s.sh", suffix)
+func (n *NinjaGenerator) emitRegenRules() error {
+ if len(n.Args) == 0 {
+ return nil
+ }
+ mkfiles, err := n.ctx.ev.EvaluateVar("MAKEFILE_LIST")
+ if err != nil {
+ return err
+ }
+ fmt.Fprintf(n.f, `
+rule regen_ninja
+ description = Regenerate ninja files due to dependency
+ generator=1
+ command=%s
+`, strings.Join(n.Args, " "))
+ fmt.Fprintf(n.f, "build %s: regen_ninja %s", n.ninjaName(), mkfiles)
+ // TODO: Add dependencies to directories read by $(wildcard) or
+ // $(shell find).
+ if len(usedEnvs) > 0 {
+ fmt.Fprintf(n.f, " %s", n.envlistName())
+ }
+ fmt.Fprintf(n.f, "\n\n")
+ if len(usedEnvs) == 0 {
+ return nil
+ }
+ fmt.Fprint(n.f, `
+build .always_build: phony
+rule regen_envlist
+ description = Check $out
+ generator = 1
+ restat = 1
+ command = rm -f $out.tmp`)
+ for env := range usedEnvs {
+ fmt.Fprintf(n.f, " && echo %s=$$%s >> $out.tmp", env, env)
+ }
+ if n.ErrorOnEnvChange {
+ fmt.Fprintln(n.f, " && (cmp -s $out.tmp $out || (echo Environment variable changes are detected && diff -u $out $out.tmp))")
+ } else {
+ fmt.Fprintln(n.f, " && (cmp -s $out.tmp $out || mv $out.tmp $out)")
+ }
+
+ fmt.Fprintf(n.f, "build %s: regen_envlist .always_build\n\n", n.envlistName())
+ return nil
+}
+
+func (n *NinjaGenerator) shName() string {
+ return fmt.Sprintf("ninja%s.sh", n.Suffix)
+}
+
+func (n *NinjaGenerator) ninjaName() string {
+ return fmt.Sprintf("build%s.ninja", n.Suffix)
}
-func (n *NinjaGenerator) ninjaName(suffix string) string {
- return fmt.Sprintf("build%s.ninja", suffix)
+func (n *NinjaGenerator) envlistName() string {
+ return fmt.Sprintf(".kati_env%s", n.Suffix)
}
-func (n *NinjaGenerator) generateShell(suffix string) (err error) {
- f, err := os.Create(n.shName(suffix))
+func (n *NinjaGenerator) generateEnvlist() (err error) {
+ f, err := os.Create(n.envlistName())
+ if err != nil {
+ return err
+ }
+ defer func() {
+ cerr := f.Close()
+ if err == nil {
+ err = cerr
+ }
+ }()
+ for k := range usedEnvs {
+ v, err := n.ctx.ev.EvaluateVar(k)
+ if err != nil {
+ return err
+ }
+ fmt.Fprintf(f, "%s=%s\n", k, v)
+ }
+ return nil
+}
+
+func (n *NinjaGenerator) generateShell() (err error) {
+ f, err := os.Create(n.shName())
if err != nil {
return err
}
@@ -471,6 +546,9 @@ func (n *NinjaGenerator) generateShell(suffix string) (err error) {
fmt.Fprintf(f, "# Generated by kati %s\n", gitVersion)
fmt.Fprintln(f)
fmt.Fprintln(f, `cd $(dirname "$0")`)
+ if n.Suffix != "" {
+ fmt.Fprintf(f, "if [ -f %s ]; then\n export $(cat %s)\nfi\n", n.envlistName(), n.envlistName())
+ }
for name, export := range n.exports {
if export {
v, err := n.ctx.ev.EvaluateVar(name)
@@ -483,16 +561,16 @@ func (n *NinjaGenerator) generateShell(suffix string) (err error) {
}
}
if n.GomaDir == "" {
- fmt.Fprintf(f, `exec ninja -f %s "$@"`+"\n", n.ninjaName(suffix))
+ fmt.Fprintf(f, `exec ninja -f %s "$@"`+"\n", n.ninjaName())
} else {
- fmt.Fprintf(f, `exec ninja -f %s -j500 "$@"`+"\n", n.ninjaName(suffix))
+ fmt.Fprintf(f, `exec ninja -f %s -j500 "$@"`+"\n", n.ninjaName())
}
return f.Chmod(0755)
}
-func (n *NinjaGenerator) generateNinja(suffix, defaultTarget string) (err error) {
- f, err := os.Create(n.ninjaName(suffix))
+func (n *NinjaGenerator) generateNinja(defaultTarget string) (err error) {
+ f, err := os.Create(n.ninjaName())
if err != nil {
return err
}
@@ -526,7 +604,12 @@ func (n *NinjaGenerator) generateNinja(suffix, defaultTarget string) (err error)
if n.GomaDir != "" {
fmt.Fprintf(n.f, "pool local_pool\n")
- fmt.Fprintf(n.f, " depth = %d\n", runtime.NumCPU())
+ fmt.Fprintf(n.f, " depth = %d\n\n", runtime.NumCPU())
+ }
+
+ err = n.emitRegenRules()
+ if err != nil {
+ return err
}
// defining $out for $@ and $in for $^ here doesn't work well,
@@ -558,16 +641,18 @@ func (n *NinjaGenerator) generateNinja(suffix, defaultTarget string) (err error)
}
fmt.Fprintf(n.f, "build %s: phony %s\n", name, n.shortNames[name][0])
}
- // TODO(ukai): regenerate build.ninja when Makefile or dir used for
- // wildcard is newer than build.ninja?
return nil
}
// Save generates build.ninja from DepGraph.
-func (n *NinjaGenerator) Save(g *DepGraph, suffix string, targets []string) error {
+func (n *NinjaGenerator) Save(g *DepGraph, name string, targets []string) error {
startTime := time.Now()
n.init(g)
- err := n.generateShell(suffix)
+ err := n.generateEnvlist()
+ if err != nil {
+ return err
+ }
+ err = n.generateShell()
if err != nil {
return err
}
@@ -575,7 +660,7 @@ func (n *NinjaGenerator) Save(g *DepGraph, suffix string, targets []string) erro
if len(targets) == 0 && len(g.nodes) > 0 {
defaultTarget = g.nodes[0].Output
}
- err = n.generateNinja(suffix, defaultTarget)
+ err = n.generateNinja(defaultTarget)
if err != nil {
return err
}