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) {
24
path: filepath.Join(tree.SrcDir(), pkg),
26
b.obj = b.abs("_obj") + string(filepath.Separator)
21
goarch := runtime.GOARCH
28
b.goarch = runtime.GOARCH
22
29
if g := os.Getenv("GOARCH"); g != "" {
26
b.arch, err = ArchChar(goarch)
33
b.arch, err = ArchChar(b.goarch)
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)
47
s.addInput(filepath.Join(t.PkgDir(), p+".a"))
50
// .go files to be built with gc
51
gofiles := b.abss(info.GoFiles...)
52
s.addInput(gofiles...)
54
var ofiles []string // object files to be linked or packed
34
56
// make build directory
58
s.addIntermediate(b.obj)
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...)
46
73
ofile := b.obj + "_go_." + b.arch
47
74
b.gc(ofile, gofiles...)
48
75
ofiles = append(ofiles, ofile)
76
s.addIntermediate(ofile)
52
for _, sfile := range d.SFiles {
80
for _, sfile := range info.SFiles {
53
81
ofile := b.obj + sfile[:len(sfile)-1] + b.arch
54
84
b.asm(ofile, sfile)
55
85
ofiles = append(ofiles, ofile)
86
s.addIntermediate(ofile)
58
89
if len(ofiles) == 0 {
59
90
return nil, os.NewError("make: no object files to build")
96
// use the last part of the import path as binary name
97
_, bin := filepath.Split(pkg)
98
if runtime.GOOS == "windows" {
101
targ = filepath.Join(tree.BinDir(), bin)
103
targ = filepath.Join(tree.PkgDir(), pkg+".a")
106
// make target directory
107
targDir, _ := filepath.Split(targ)
110
// link binary or pack object
111
if info.IsCommand() {
63
112
b.ld(targ, ofiles...)
65
114
b.gopack(targ, ofiles...)
116
s.Output = append(s.Output, targ)
121
// A Script describes the build process for a Go package.
122
// The Input, Intermediate, and Output fields are lists of absolute paths.
126
Intermediate []string
130
func (s *Script) addInput(file ...string) {
131
s.Input = append(s.Input, file...)
134
func (s *Script) addIntermediate(file ...string) {
135
s.Intermediate = append(s.Intermediate, file...)
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 {
148
// Stale returns true if the build's inputs are newer than its outputs.
149
func (s *Script) Stale() bool {
151
// get latest mtime of outputs
152
for _, file := range s.Output {
153
fi, err := os.Stat(file)
155
// any error reading output files means stale
158
if m := fi.Mtime_ns; m > latest {
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)
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 {
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 {
194
if e := s.Clean(); err == nil {
200
// A Cmd describes an individual build command.
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
125
250
type build struct {
258
func (b *build) abs(file string) string {
259
if filepath.IsAbs(file) {
262
return filepath.Join(b.path, file)
265
func (b *build) abss(file ...string) []string {
266
s := make([]string, len(file))
267
for i, f := range file {
131
273
func (b *build) add(c Cmd) {
132
b.cmds = append(b.cmds, &c)
274
b.script.Cmd = append(b.script.Cmd, &c)
135
277
func (b *build) mkdir(name string) {
201
343
func (b *build) gccLink(ofile string, ofiles ...string) {
203
Args: append(gccArgs(b.arch, "-o", ofile), ofiles...),
345
Args: append(b.gccArgs("-o", ofile), ofiles...),
205
347
Output: []string{ofile},
209
func gccArgs(arch string, args ...string) []string {
351
func (b *build) gccArgs(args ...string) []string {
210
352
// TODO(adg): HOST_CC
353
a := []string{"gcc", "-I", b.path, "-g", "-fPIC", "-O2"}
356
a = append(a, "-m32")
358
a = append(a, "-m64")
215
return append([]string{"gcc", m, "-I", ".", "-g", "-fPIC", "-O2"}, args...)
360
return append(a, args...)
363
var cgoRe = regexp.MustCompile(`[/\\:]`)
218
365
func (b *build) cgo(cgofiles []string) (outGo, outObj []string) {
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")
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...)
233
380
Args: append([]string{"cgo", "--"}, cgofiles...),
382
Env: append(os.Environ(), "GOARCH="+b.goarch),
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...)
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)
405
b.script.addIntermediate(ofile)
254
dynObj := b.obj + "_cgo1_.o"
408
dynObj := b.obj + "_cgo_.o"
255
409
b.gccLink(dynObj, linkobj...)
410
b.script.addIntermediate(dynObj)
257
412
// cgo -dynimport
258
413
importC := b.obj + "_cgo_import.c"