Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(1224)

Delta Between Two Patch Sets: src/pkg/go/build/build.go

Issue 4515180: code review 4515180: goinstall: use go/make package to scan and build packages (Closed)
Left Patch Set: diff -r 1ed4cce53a65 https://go.googlecode.com/hg/ Created 13 years, 10 months ago
Right Patch Set: diff -r 6bf5e0a7d60a https://go.googlecode.com/hg/ Created 13 years, 9 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Right: Side by side diff | Download
« no previous file with change/comment | « src/pkg/Makefile ('k') | src/pkg/go/build/build_test.go » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
(no file at all)
1 // Copyright 2011 The Go Authors. All rights reserved. 1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style 2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file. 3 // license that can be found in the LICENSE file.
4 4
5 // Package build provides tools for building Go packages. 5 // Package build provides tools for building Go packages.
6 package build 6 package build
7 7
8 import ( 8 import (
9 "bytes" 9 "bytes"
10 "exec" 10 "exec"
11 "fmt" 11 "fmt"
12 "os" 12 "os"
13 "path/filepath" 13 "path/filepath"
14 "runtime" 14 "runtime"
15 "strings" 15 "strings"
16 ) 16 )
17 17
18 func (d *DirInfo) Build(targ string) ([]*Cmd, os.Error) { 18 // Build produces a build Script for the given package.
19 » b := &build{obj: "_obj/"} 19 func Build(tree *Tree, pkg string, info *DirInfo) (*Script, os.Error) {
20 » s := &Script{}
21 » b := &build{
22 » » script: s,
23 » » path: filepath.Join(tree.SrcDir(), pkg),
24 » }
25 » b.obj = b.abs("_obj") + "/"
20 26
21 goarch := runtime.GOARCH 27 goarch := runtime.GOARCH
22 if g := os.Getenv("GOARCH"); g != "" { 28 if g := os.Getenv("GOARCH"); g != "" {
23 goarch = g 29 goarch = g
24 } 30 }
25 var err os.Error 31 var err os.Error
26 b.arch, err = ArchChar(goarch) 32 b.arch, err = ArchChar(goarch)
27 if err != nil { 33 if err != nil {
28 return nil, err 34 return nil, err
29 } 35 }
30 36
31 » var gofiles = d.GoFiles // .go files to be built with gc 37 » // .go files to be built with gc
32 » var ofiles []string // *.GOARCH files to be linked or packed 38 » gofiles := b.abss(info.GoFiles...)
39 » s.addInput(gofiles...)
40
41 » var ofiles []string // object files to be linked or packed
33 42
34 // make build directory 43 // make build directory
35 b.mkdir(b.obj) 44 b.mkdir(b.obj)
45 s.addIntermediate(b.obj)
36 46
37 // cgo 47 // cgo
38 » if len(d.CgoFiles) > 0 { 48 » if len(info.CgoFiles) > 0 {
39 » » outGo, outObj := b.cgo(d.CgoFiles) 49 » » cgoFiles := b.abss(info.CgoFiles...)
50 » » s.addInput(cgoFiles...)
51 » » outGo, outObj := b.cgo(cgoFiles)
40 gofiles = append(gofiles, outGo...) 52 gofiles = append(gofiles, outGo...)
41 ofiles = append(ofiles, outObj...) 53 ofiles = append(ofiles, outObj...)
54 s.addIntermediate(outGo...)
55 s.addIntermediate(outObj...)
42 } 56 }
43 57
44 // compile 58 // compile
45 if len(gofiles) > 0 { 59 if len(gofiles) > 0 {
46 ofile := b.obj + "_go_." + b.arch 60 ofile := b.obj + "_go_." + b.arch
47 b.gc(ofile, gofiles...) 61 b.gc(ofile, gofiles...)
48 ofiles = append(ofiles, ofile) 62 ofiles = append(ofiles, ofile)
63 s.addIntermediate(ofile)
49 } 64 }
50 65
51 // assemble 66 // assemble
52 » for _, sfile := range d.SFiles { 67 » for _, sfile := range info.SFiles {
53 ofile := b.obj + sfile[:len(sfile)-1] + b.arch 68 ofile := b.obj + sfile[:len(sfile)-1] + b.arch
69 sfile = b.abs(sfile)
70 s.addInput(sfile)
54 b.asm(ofile, sfile) 71 b.asm(ofile, sfile)
55 ofiles = append(ofiles, ofile) 72 ofiles = append(ofiles, ofile)
73 s.addIntermediate(sfile, ofile)
56 } 74 }
57 75
58 if len(ofiles) == 0 { 76 if len(ofiles) == 0 {
59 return nil, os.NewError("make: no object files to build") 77 return nil, os.NewError("make: no object files to build")
60 } 78 }
61 79
62 » if d.IsCommand() { 80 » // choose target file
81 » var targ string
82 » if info.IsCommand() {
83 » » // use the last part of the import path as binary name
84 » » _, bin := filepath.Split(pkg)
85 » » targ = filepath.Join(tree.BinDir(), bin)
86 » } else {
87 » » targ = filepath.Join(tree.PkgDir(), pkg+".a")
88 » }
89
90 » // make target directory
91 » targDir, _ := filepath.Split(targ)
92 » b.mkdir(targDir)
93
94 » // link binary or pack object
95 » if info.IsCommand() {
63 b.ld(targ, ofiles...) 96 b.ld(targ, ofiles...)
64 } else { 97 } else {
65 b.gopack(targ, ofiles...) 98 b.gopack(targ, ofiles...)
66 } 99 }
67 100 » s.Output = append(s.Output, targ)
68 » return b.cmds, nil 101
69 } 102 » return b.script, nil
70 103 }
104
105 // A Script describes the build process for a Go package.
106 // The Input, Intermediate, and Output fields are lists of absolute paths.
107 type Script struct {
108 » Cmd []*Cmd
109 » Input []string
110 » Intermediate []string
111 » Output []string
112 }
113
114 func (s *Script) addInput(file ...string) {
115 » s.Input = append(s.Input, file...)
116 }
117
118 func (s *Script) addIntermediate(file ...string) {
119 » s.Intermediate = append(s.Intermediate, file...)
120 }
121
122 // Run runs the Script's Cmds in order.
123 func (s *Script) Run() os.Error {
124 » for _, c := range s.Cmd {
125 » » if err := c.Run(); err != nil {
126 » » » return err
127 » » }
128 » }
129 » return nil
130 }
131
132 // Stale returns true if the build's inputs are newer than its outputs.
133 func (s *Script) Stale() bool {
134 » var latest int64
135 » // get latest mtime of outputs
136 » for _, file := range s.Output {
137 » » fi, err := os.Stat(file)
138 » » if err != nil {
139 » » » // any error reading output files means stale
140 » » » return true
141 » » }
142 » » if m := fi.Mtime_ns; m > latest {
143 » » » latest = m
144 » » }
145 » }
146 » for _, file := range s.Input {
147 » » fi, err := os.Stat(file)
148 » » if err != nil || fi.Mtime_ns > latest {
149 » » » // any error reading input files means stale
150 » » » // (attempt to rebuild to figure out why)
151 » » » return true
152 » » }
153 » }
154 » return false
155 }
156
157 // Clean removes the Script's Intermediate files.
158 // It tries to remove every file and returns the first error it encounters.
159 func (s *Script) Clean() (err os.Error) {
160 » for i := len(s.Intermediate) - 1; i >= 0; i-- {
161 » » if e := os.Remove(s.Intermediate[i]); err == nil {
162 » » » err = e
163 » » }
164 » }
165 » return
166 }
167
168 // Clean removes the Script's Intermediate and Output files.
169 // It tries to remove every file and returns the first error it encounters.
170 func (s *Script) Nuke() (err os.Error) {
171 » for i := len(s.Output) - 1; i >= 0; i-- {
172 » » if e := os.Remove(s.Output[i]); err == nil {
173 » » » err = e
174 » » }
175 » }
176 » if e := s.Clean(); err == nil {
177 » » err = e
178 » }
179 » return
180 }
181
182 // A Cmd describes an individual build command.
71 type Cmd struct { 183 type Cmd struct {
72 Args []string // command-line 184 Args []string // command-line
73 Stdout string // write standard output to this file, "" is passthrough 185 Stdout string // write standard output to this file, "" is passthrough
186 Dir string // working directory
74 Input []string // file paths (dependencies) 187 Input []string // file paths (dependencies)
75 Output []string // file paths 188 Output []string // file paths
76 } 189 }
77 190
78 func (c *Cmd) String() string { 191 func (c *Cmd) String() string {
79 return strings.Join(c.Args, " ") 192 return strings.Join(c.Args, " ")
80 } 193 }
81 194
82 func (c *Cmd) Run(dir string) os.Error { 195 // Run executes the Cmd.
196 func (c *Cmd) Run() os.Error {
83 out := new(bytes.Buffer) 197 out := new(bytes.Buffer)
84 cmd := exec.Command(c.Args[0], c.Args[1:]...) 198 cmd := exec.Command(c.Args[0], c.Args[1:]...)
85 » cmd.Dir = dir 199 » cmd.Dir = c.Dir
86 cmd.Stdout = out 200 cmd.Stdout = out
87 cmd.Stderr = out 201 cmd.Stderr = out
88 if c.Stdout != "" { 202 if c.Stdout != "" {
89 » » f, err := os.Create(filepath.Join(dir, c.Stdout)) 203 » » f, err := os.Create(c.Stdout)
90 if err != nil { 204 if err != nil {
91 return err 205 return err
92 } 206 }
93 defer f.Close() 207 defer f.Close()
94 cmd.Stdout = f 208 cmd.Stdout = f
95 } 209 }
96 if err := cmd.Run(); err != nil { 210 if err := cmd.Run(); err != nil {
97 return fmt.Errorf("command %q: %v\n%v", c, err, out) 211 return fmt.Errorf("command %q: %v\n%v", c, err, out)
98 } 212 }
99 return nil 213 return nil
100 }
101
102 func (c *Cmd) Clean(dir string) (err os.Error) {
103 for _, fn := range c.Output {
104 if e := os.RemoveAll(fn); err == nil {
105 err = e
106 }
107 }
108 return
109 } 214 }
110 215
111 // ArchChar returns the architecture character for the given goarch. 216 // ArchChar returns the architecture character for the given goarch.
112 // For example, ArchChar("amd64") returns "6". 217 // For example, ArchChar("amd64") returns "6".
113 func ArchChar(goarch string) (string, os.Error) { 218 func ArchChar(goarch string) (string, os.Error) {
114 switch goarch { 219 switch goarch {
115 case "386": 220 case "386":
116 return "8", nil 221 return "8", nil
117 case "amd64": 222 case "amd64":
118 return "6", nil 223 return "6", nil
119 case "arm": 224 case "arm":
120 return "5", nil 225 return "5", nil
121 } 226 }
122 return "", os.NewError("unsupported GOARCH " + goarch) 227 return "", os.NewError("unsupported GOARCH " + goarch)
123 } 228 }
124 229
125 type build struct { 230 type build struct {
126 » cmds []*Cmd 231 » script *Script
127 » obj string 232 » path string
128 » arch string 233 » obj string
234 » arch string
235 }
236
237 func (b *build) abs(file string) string {
238 » if filepath.IsAbs(file) {
239 » » return file
240 » }
241 » return filepath.Join(b.path, file)
242 }
243
244 func (b *build) abss(file ...string) []string {
245 » s := make([]string, len(file))
246 » for i, f := range file {
247 » » s[i] = b.abs(f)
248 » }
249 » return s
129 } 250 }
130 251
131 func (b *build) add(c Cmd) { 252 func (b *build) add(c Cmd) {
132 » b.cmds = append(b.cmds, &c) 253 » b.script.Cmd = append(b.script.Cmd, &c)
133 } 254 }
134 255
135 func (b *build) mkdir(name string) { 256 func (b *build) mkdir(name string) {
136 b.add(Cmd{ 257 b.add(Cmd{
137 Args: []string{"mkdir", "-p", name}, 258 Args: []string{"mkdir", "-p", name},
138 Output: []string{name}, 259 Output: []string{name},
139 }) 260 })
140 } 261 }
141 262
142 func (b *build) gc(ofile string, gofiles ...string) { 263 func (b *build) gc(ofile string, gofiles ...string) {
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
215 return append([]string{"gcc", m, "-I", ".", "-g", "-fPIC", "-O2"}, args. ..) 336 return append([]string{"gcc", m, "-I", ".", "-g", "-fPIC", "-O2"}, args. ..)
216 } 337 }
217 338
218 func (b *build) cgo(cgofiles []string) (outGo, outObj []string) { 339 func (b *build) cgo(cgofiles []string) (outGo, outObj []string) {
219 // cgo 340 // cgo
220 // TODO(adg): CGOPKGPATH 341 // TODO(adg): CGOPKGPATH
221 // TODO(adg): CGO_FLAGS 342 // TODO(adg): CGO_FLAGS
222 gofiles := []string{b.obj + "_cgo_gotypes.go"} 343 gofiles := []string{b.obj + "_cgo_gotypes.go"}
223 cfiles := []string{b.obj + "_cgo_main.c", b.obj + "_cgo_export.c"} 344 cfiles := []string{b.obj + "_cgo_main.c", b.obj + "_cgo_export.c"}
224 for _, fn := range cgofiles { 345 for _, fn := range cgofiles {
346 fn = filepath.Base(fn)
225 f := b.obj + fn[:len(fn)-2] 347 f := b.obj + fn[:len(fn)-2]
226 gofiles = append(gofiles, f+"cgo1.go") 348 gofiles = append(gofiles, f+"cgo1.go")
227 cfiles = append(cfiles, f+"cgo2.c") 349 cfiles = append(cfiles, f+"cgo2.c")
228 } 350 }
229 defunC := b.obj + "_cgo_defun.c" 351 defunC := b.obj + "_cgo_defun.c"
230 output := append([]string{defunC}, gofiles...) 352 output := append([]string{defunC}, gofiles...)
231 output = append(output, cfiles...) 353 output = append(output, cfiles...)
232 b.add(Cmd{ 354 b.add(Cmd{
233 Args: append([]string{"cgo", "--"}, cgofiles...), 355 Args: append([]string{"cgo", "--"}, cgofiles...),
234 Input: cgofiles, 356 Input: cgofiles,
(...skipping 28 matching lines...) Expand all
263 Output: []string{importC}, 385 Output: []string{importC},
264 }) 386 })
265 387
266 // cc _cgo_import.ARCH 388 // cc _cgo_import.ARCH
267 importObj := b.obj + "_cgo_import." + b.arch 389 importObj := b.obj + "_cgo_import." + b.arch
268 b.cc(importObj, importC) 390 b.cc(importObj, importC)
269 outObj = append(outObj, importObj) 391 outObj = append(outObj, importObj)
270 392
271 return 393 return
272 } 394 }
LEFTRIGHT

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b