~john-koepi/ubuntu/trusty/golang/default

« back to all changes in this revision

Viewing changes to src/pkg/go/build/build.go

  • Committer: Bazaar Package Importer
  • Author(s): Ondřej Surý
  • Date: 2011-08-03 17:04:59 UTC
  • mfrom: (14.1.2 sid)
  • Revision ID: james.westby@ubuntu.com-20110803170459-wzd99m3567y80ila
Tags: 1:59-1
* Imported Upstream version 59
* Refresh patches to a new release
* Fix FTBFS on ARM (Closes: #634270)
* Update version.bash to work with Debian packaging and not hg
  repository

Show diffs side-by-side

added added

removed removed

Lines of Context:
11
11
        "fmt"
12
12
        "os"
13
13
        "path/filepath"
 
14
        "regexp"
14
15
        "runtime"
15
16
        "strings"
16
17
)
17
18
 
18
 
func (d *DirInfo) Build(targ string) ([]*Cmd, os.Error) {
19
 
        b := &build{obj: "_obj/"}
 
19
// Build produces a build Script for the given package.
 
20
func Build(tree *Tree, pkg string, info *DirInfo) (*Script, os.Error) {
 
21
        s := &Script{}
 
22
        b := &build{
 
23
                script: s,
 
24
                path:   filepath.Join(tree.SrcDir(), pkg),
 
25
        }
 
26
        b.obj = b.abs("_obj") + string(filepath.Separator)
20
27
 
21
 
        goarch := runtime.GOARCH
 
28
        b.goarch = runtime.GOARCH
22
29
        if g := os.Getenv("GOARCH"); g != "" {
23
 
                goarch = g
 
30
                b.goarch = g
24
31
        }
25
32
        var err os.Error
26
 
        b.arch, err = ArchChar(goarch)
 
33
        b.arch, err = ArchChar(b.goarch)
27
34
        if err != nil {
28
35
                return nil, err
29
36
        }
30
37
 
31
 
        var gofiles = d.GoFiles // .go files to be built with gc
32
 
        var ofiles []string     // *.GOARCH files to be linked or packed
 
38
        // add import object files to list of Inputs
 
39
        for _, pkg := range info.Imports {
 
40
                t, p, err := FindTree(pkg)
 
41
                if err != nil && err != ErrNotFound {
 
42
                        // FindTree should always be able to suggest an import
 
43
                        // path and tree. The path must be malformed
 
44
                        // (for example, an absolute or relative path).
 
45
                        return nil, os.NewError("build: invalid import: " + pkg)
 
46
                }
 
47
                s.addInput(filepath.Join(t.PkgDir(), p+".a"))
 
48
        }
 
49
 
 
50
        // .go files to be built with gc
 
51
        gofiles := b.abss(info.GoFiles...)
 
52
        s.addInput(gofiles...)
 
53
 
 
54
        var ofiles []string // object files to be linked or packed
33
55
 
34
56
        // make build directory
35
57
        b.mkdir(b.obj)
 
58
        s.addIntermediate(b.obj)
36
59
 
37
60
        // cgo
38
 
        if len(d.CgoFiles) > 0 {
39
 
                outGo, outObj := b.cgo(d.CgoFiles)
 
61
        if len(info.CgoFiles) > 0 {
 
62
                cgoFiles := b.abss(info.CgoFiles...)
 
63
                s.addInput(cgoFiles...)
 
64
                outGo, outObj := b.cgo(cgoFiles)
40
65
                gofiles = append(gofiles, outGo...)
41
66
                ofiles = append(ofiles, outObj...)
 
67
                s.addIntermediate(outGo...)
 
68
                s.addIntermediate(outObj...)
42
69
        }
43
70
 
44
71
        // compile
46
73
                ofile := b.obj + "_go_." + b.arch
47
74
                b.gc(ofile, gofiles...)
48
75
                ofiles = append(ofiles, ofile)
 
76
                s.addIntermediate(ofile)
49
77
        }
50
78
 
51
79
        // assemble
52
 
        for _, sfile := range d.SFiles {
 
80
        for _, sfile := range info.SFiles {
53
81
                ofile := b.obj + sfile[:len(sfile)-1] + b.arch
 
82
                sfile = b.abs(sfile)
 
83
                s.addInput(sfile)
54
84
                b.asm(ofile, sfile)
55
85
                ofiles = append(ofiles, ofile)
 
86
                s.addIntermediate(ofile)
56
87
        }
57
88
 
58
89
        if len(ofiles) == 0 {
59
90
                return nil, os.NewError("make: no object files to build")
60
91
        }
61
92
 
62
 
        if d.IsCommand() {
 
93
        // choose target file
 
94
        var targ string
 
95
        if info.IsCommand() {
 
96
                // use the last part of the import path as binary name
 
97
                _, bin := filepath.Split(pkg)
 
98
                if runtime.GOOS == "windows" {
 
99
                        bin += ".exe"
 
100
                }
 
101
                targ = filepath.Join(tree.BinDir(), bin)
 
102
        } else {
 
103
                targ = filepath.Join(tree.PkgDir(), pkg+".a")
 
104
        }
 
105
 
 
106
        // make target directory
 
107
        targDir, _ := filepath.Split(targ)
 
108
        b.mkdir(targDir)
 
109
 
 
110
        // link binary or pack object
 
111
        if info.IsCommand() {
63
112
                b.ld(targ, ofiles...)
64
113
        } else {
65
114
                b.gopack(targ, ofiles...)
66
115
        }
67
 
 
68
 
        return b.cmds, nil
69
 
}
70
 
 
 
116
        s.Output = append(s.Output, targ)
 
117
 
 
118
        return b.script, nil
 
119
}
 
120
 
 
121
// A Script describes the build process for a Go package.
 
122
// The Input, Intermediate, and Output fields are lists of absolute paths.
 
123
type Script struct {
 
124
        Cmd          []*Cmd
 
125
        Input        []string
 
126
        Intermediate []string
 
127
        Output       []string
 
128
}
 
129
 
 
130
func (s *Script) addInput(file ...string) {
 
131
        s.Input = append(s.Input, file...)
 
132
}
 
133
 
 
134
func (s *Script) addIntermediate(file ...string) {
 
135
        s.Intermediate = append(s.Intermediate, file...)
 
136
}
 
137
 
 
138
// Run runs the Script's Cmds in order.
 
139
func (s *Script) Run() os.Error {
 
140
        for _, c := range s.Cmd {
 
141
                if err := c.Run(); err != nil {
 
142
                        return err
 
143
                }
 
144
        }
 
145
        return nil
 
146
}
 
147
 
 
148
// Stale returns true if the build's inputs are newer than its outputs.
 
149
func (s *Script) Stale() bool {
 
150
        var latest int64
 
151
        // get latest mtime of outputs
 
152
        for _, file := range s.Output {
 
153
                fi, err := os.Stat(file)
 
154
                if err != nil {
 
155
                        // any error reading output files means stale
 
156
                        return true
 
157
                }
 
158
                if m := fi.Mtime_ns; m > latest {
 
159
                        latest = m
 
160
                }
 
161
        }
 
162
        for _, file := range s.Input {
 
163
                fi, err := os.Stat(file)
 
164
                if err != nil || fi.Mtime_ns > latest {
 
165
                        // any error reading input files means stale
 
166
                        // (attempt to rebuild to figure out why)
 
167
                        return true
 
168
                }
 
169
        }
 
170
        return false
 
171
}
 
172
 
 
173
// Clean removes the Script's Intermediate files.
 
174
// It tries to remove every file and returns the first error it encounters.
 
175
func (s *Script) Clean() (err os.Error) {
 
176
        // Reverse order so that directories get removed after the files they contain.
 
177
        for i := len(s.Intermediate) - 1; i >= 0; i-- {
 
178
                if e := os.Remove(s.Intermediate[i]); err == nil {
 
179
                        err = e
 
180
                }
 
181
        }
 
182
        return
 
183
}
 
184
 
 
185
// Clean removes the Script's Intermediate and Output files.
 
186
// It tries to remove every file and returns the first error it encounters.
 
187
func (s *Script) Nuke() (err os.Error) {
 
188
        // Reverse order so that directories get removed after the files they contain.
 
189
        for i := len(s.Output) - 1; i >= 0; i-- {
 
190
                if e := os.Remove(s.Output[i]); err == nil {
 
191
                        err = e
 
192
                }
 
193
        }
 
194
        if e := s.Clean(); err == nil {
 
195
                err = e
 
196
        }
 
197
        return
 
198
}
 
199
 
 
200
// A Cmd describes an individual build command.
71
201
type Cmd struct {
72
202
        Args   []string // command-line
73
203
        Stdout string   // write standard output to this file, "" is passthrough
 
204
        Dir    string   // working directory
 
205
        Env    []string // environment
74
206
        Input  []string // file paths (dependencies)
75
207
        Output []string // file paths
76
208
}
79
211
        return strings.Join(c.Args, " ")
80
212
}
81
213
 
82
 
func (c *Cmd) Run(dir string) os.Error {
 
214
// Run executes the Cmd.
 
215
func (c *Cmd) Run() os.Error {
83
216
        out := new(bytes.Buffer)
84
217
        cmd := exec.Command(c.Args[0], c.Args[1:]...)
85
 
        cmd.Dir = dir
 
218
        cmd.Dir = c.Dir
 
219
        cmd.Env = c.Env
86
220
        cmd.Stdout = out
87
221
        cmd.Stderr = out
88
222
        if c.Stdout != "" {
89
 
                f, err := os.Create(filepath.Join(dir, c.Stdout))
 
223
                f, err := os.Create(c.Stdout)
90
224
                if err != nil {
91
225
                        return err
92
226
                }
99
233
        return nil
100
234
}
101
235
 
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
 
}
110
 
 
111
236
// ArchChar returns the architecture character for the given goarch.
112
237
// For example, ArchChar("amd64") returns "6".
113
238
func ArchChar(goarch string) (string, os.Error) {
123
248
}
124
249
 
125
250
type build struct {
126
 
        cmds []*Cmd
127
 
        obj  string
128
 
        arch string
 
251
        script *Script
 
252
        path   string
 
253
        obj    string
 
254
        goarch string
 
255
        arch   string
 
256
}
 
257
 
 
258
func (b *build) abs(file string) string {
 
259
        if filepath.IsAbs(file) {
 
260
                return file
 
261
        }
 
262
        return filepath.Join(b.path, file)
 
263
}
 
264
 
 
265
func (b *build) abss(file ...string) []string {
 
266
        s := make([]string, len(file))
 
267
        for i, f := range file {
 
268
                s[i] = b.abs(f)
 
269
        }
 
270
        return s
129
271
}
130
272
 
131
273
func (b *build) add(c Cmd) {
132
 
        b.cmds = append(b.cmds, &c)
 
274
        b.script.Cmd = append(b.script.Cmd, &c)
133
275
}
134
276
 
135
277
func (b *build) mkdir(name string) {
192
334
 
193
335
func (b *build) gccCompile(ofile, cfile string) {
194
336
        b.add(Cmd{
195
 
                Args:   gccArgs(b.arch, "-o", ofile, "-c", cfile),
 
337
                Args:   b.gccArgs("-o", ofile, "-c", cfile),
196
338
                Input:  []string{cfile},
197
339
                Output: []string{ofile},
198
340
        })
200
342
 
201
343
func (b *build) gccLink(ofile string, ofiles ...string) {
202
344
        b.add(Cmd{
203
 
                Args:   append(gccArgs(b.arch, "-o", ofile), ofiles...),
 
345
                Args:   append(b.gccArgs("-o", ofile), ofiles...),
204
346
                Input:  ofiles,
205
347
                Output: []string{ofile},
206
348
        })
207
349
}
208
350
 
209
 
func gccArgs(arch string, args ...string) []string {
 
351
func (b *build) gccArgs(args ...string) []string {
210
352
        // TODO(adg): HOST_CC
211
 
        m := "-m32"
212
 
        if arch == "6" {
213
 
                m = "-m64"
 
353
        a := []string{"gcc", "-I", b.path, "-g", "-fPIC", "-O2"}
 
354
        switch b.arch {
 
355
        case "8":
 
356
                a = append(a, "-m32")
 
357
        case "6":
 
358
                a = append(a, "-m64")
214
359
        }
215
 
        return append([]string{"gcc", m, "-I", ".", "-g", "-fPIC", "-O2"}, args...)
 
360
        return append(a, args...)
216
361
}
217
362
 
 
363
var cgoRe = regexp.MustCompile(`[/\\:]`)
 
364
 
218
365
func (b *build) cgo(cgofiles []string) (outGo, outObj []string) {
219
366
        // cgo
220
367
        // TODO(adg): CGOPKGPATH
222
369
        gofiles := []string{b.obj + "_cgo_gotypes.go"}
223
370
        cfiles := []string{b.obj + "_cgo_main.c", b.obj + "_cgo_export.c"}
224
371
        for _, fn := range cgofiles {
225
 
                f := b.obj + fn[:len(fn)-2]
 
372
                f := b.obj + cgoRe.ReplaceAllString(fn[:len(fn)-2], "_")
226
373
                gofiles = append(gofiles, f+"cgo1.go")
227
374
                cfiles = append(cfiles, f+"cgo2.c")
228
375
        }
229
376
        defunC := b.obj + "_cgo_defun.c"
230
 
        output := append([]string{defunC}, gofiles...)
231
 
        output = append(output, cfiles...)
 
377
        output := append([]string{defunC}, cfiles...)
 
378
        output = append(output, gofiles...)
232
379
        b.add(Cmd{
233
380
                Args:   append([]string{"cgo", "--"}, cgofiles...),
 
381
                Dir:    b.path,
 
382
                Env:    append(os.Environ(), "GOARCH="+b.goarch),
234
383
                Input:  cgofiles,
235
384
                Output: output,
236
385
        })
237
386
        outGo = append(outGo, gofiles...)
 
387
        exportH := filepath.Join(b.path, "_cgo_export.h")
 
388
        b.script.addIntermediate(defunC, exportH, b.obj+"_cgo_flags")
 
389
        b.script.addIntermediate(cfiles...)
238
390
 
239
391
        // cc _cgo_defun.c
240
392
        defunObj := b.obj + "_cgo_defun." + b.arch
249
401
                linkobj = append(linkobj, ofile)
250
402
                if !strings.HasSuffix(ofile, "_cgo_main.o") {
251
403
                        outObj = append(outObj, ofile)
 
404
                } else {
 
405
                        b.script.addIntermediate(ofile)
252
406
                }
253
407
        }
254
 
        dynObj := b.obj + "_cgo1_.o"
 
408
        dynObj := b.obj + "_cgo_.o"
255
409
        b.gccLink(dynObj, linkobj...)
 
410
        b.script.addIntermediate(dynObj)
256
411
 
257
412
        // cgo -dynimport
258
413
        importC := b.obj + "_cgo_import.c"
262
417
                Input:  []string{dynObj},
263
418
                Output: []string{importC},
264
419
        })
 
420
        b.script.addIntermediate(importC)
265
421
 
266
422
        // cc _cgo_import.ARCH
267
423
        importObj := b.obj + "_cgo_import." + b.arch