diff options
-rw-r--r-- | src/cmd/gobuild/Makefile | 21 | ||||
-rw-r--r-- | src/cmd/gobuild/gobuild.go | 50 | ||||
-rw-r--r-- | src/cmd/gobuild/makefile.go | 20 | ||||
-rw-r--r-- | src/cmd/gobuild/util.go | 42 |
4 files changed, 115 insertions, 18 deletions
diff --git a/src/cmd/gobuild/Makefile b/src/cmd/gobuild/Makefile index 28e2a2e03..42c2a072b 100644 --- a/src/cmd/gobuild/Makefile +++ b/src/cmd/gobuild/Makefile @@ -46,14 +46,29 @@ $(O1): newpkg $(O2): a1 $(O3): a2 -gobuild: main.$O gobuild.a +# zzgobuild is a fake target that will always run, even if +# "gobuild" existed at the beginning of the make. +# The problem is that if you "make install" and install +# depends on gobuild and this rule says gobuild, +# and gobuild.a depends on phases, "phases" gets +# run, which cleans everything and then rebuilds +# gobuild.a. So now make thinks gobuild was up to date +# to begin with (and it ran "phases" just for good measure) +# but in fact gobuild is gone ("phases" removed it). +# +# Calling the target zzgobuild instead means that +# make will always run this rule, rebuilding gobuild +# before trying to install it. Sigh. +zzgobuild: main.$O gobuild.a $(LD) -o gobuild main.$O -main.$O: gobuild.a +gobuild: zzgobuild + +main.$O: phases nuke: clean rm -f $(HOME)/bin/gobuild -install: gobuild +install: zzgobuild cp gobuild $(HOME)/bin/gobuild diff --git a/src/cmd/gobuild/gobuild.go b/src/cmd/gobuild/gobuild.go index c28419da2..7622494aa 100644 --- a/src/cmd/gobuild/gobuild.go +++ b/src/cmd/gobuild/gobuild.go @@ -45,6 +45,8 @@ type Phase struct { type Info struct { Args []string; Char string; + Dir string; + ObjDir string; Pkgmap map[string] *Pkg; Packages []*Pkg; Files map[string] *File; @@ -99,6 +101,30 @@ func (a FileArray) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +// If current directory is under $GOROOT/src/lib, return the +// path relative to there. Otherwise return "". +func PkgDir() string { + goroot, err := os.Getenv("GOROOT"); + if err != nil || goroot == "" { + return "" + } + srcroot := path.Clean(goroot + "/src/lib/"); + pwd, err1 := os.Getenv("PWD"); // TODO(rsc): real pwd + if err1 != nil || pwd == "" { + return "" + } + if pwd == srcroot { + return "" + } + n := len(srcroot); + if len(pwd) < n || pwd[n] != '/' || pwd[0:n] != srcroot { + return "" + } + + dir := pwd[n+1:len(pwd)]; + return dir; +} + func ScanFiles(filenames []string) *Info { // Build list of imports, local packages, and files. // Exclude *_test.go and anything in package main. @@ -106,7 +132,9 @@ func ScanFiles(filenames []string) *Info { z := new(Info); z.Args = sys.Args; - z.Char = theChar; + z.Dir = PkgDir(); + z.Char = theChar; // for template + z.ObjDir = ObjDir; // for template z.Pkgmap = make(map[string] *Pkg); z.Files = make(map[string] *File); z.Imports = make(map[string] bool); @@ -114,7 +142,7 @@ func ScanFiles(filenames []string) *Info { // Read Go files to find out packages and imports. var pkg *Pkg; for _, filename := range filenames { - if strings.HasSuffix(filename, "_test.go") { + if strings.Index(filename, "_test.") >= 0 { continue; } f := new(File); @@ -168,6 +196,14 @@ func ScanFiles(filenames []string) *Info { } } + // Update destination directory. + // If destination directory has same + // name as package name, cut it off. + dir, name := path.Split(z.Dir); + if len(z.Packages) == 1 && z.Packages[0].Name == name { + z.Dir = dir; + } + return z; } @@ -176,9 +212,14 @@ func PackageObj(pkg string) string { } func (z *Info) Build() { + // Create empty object directory tree. + RemoveAll(ObjDir); + obj := path.Join(ObjDir, z.Dir) + "/"; + MkdirAll(obj); + // Create empty archives. for pkgname := range z.Pkgmap { - ar := PackageObj(pkgname); + ar := obj + PackageObj(pkgname); os.Remove(ar); Archive(ar, nil); } @@ -239,7 +280,7 @@ func (z *Info) Build() { f.Phase = phase; } if len(arfiles) > 0 { - Archive(pkg.Name + ".a", arfiles); + Archive(obj + pkg.Name + ".a", arfiles); n := len(p.ArCmds); p.ArCmds = p.ArCmds[0:n+1]; @@ -255,6 +296,7 @@ func (z *Info) Build() { } func (z *Info) Clean() { + RemoveAll(ObjDir); for pkgname := range z.Pkgmap { os.Remove(PackageObj(pkgname)); } diff --git a/src/cmd/gobuild/makefile.go b/src/cmd/gobuild/makefile.go index cbdad90c0..229dbe219 100644 --- a/src/cmd/gobuild/makefile.go +++ b/src/cmd/gobuild/makefile.go @@ -16,13 +16,15 @@ var makefileTemplate = "# DO NOT EDIT. Automatically generated by gobuild.\n" "{Args|args} >Makefile\n" "\n" + "D={.section Dir}/{@}{.end}\n" + "\n" "O_arm=5\n" // TODO(rsc): include something here? "O_amd64=6\n" "O_386=8\n" "OS=568vq\n" "\n" "O=$(O_$(GOARCH))\n" - "GC=$(O)g\n" + "GC=$(O)g -I{ObjDir}\n" "CC=$(O)c -FVw\n" "AS=$(O)a\n" "AR=6ar\n" @@ -30,7 +32,7 @@ var makefileTemplate = "default: packages\n" "\n" "clean:\n" - " rm -f *.[$(OS)] *.a [$(OS)].out\n" + " rm -rf *.[$(OS)] *.a [$(OS)].out {ObjDir}\n" "\n" "test: packages\n" " gotest\n" @@ -60,21 +62,22 @@ var makefileTemplate = "\n" "phases:{.repeated section Phases} a{Phase}{.end}\n" "{.repeated section Packages}\n" - "{Name}.a: phases\n" + "{ObjDir}$D/{Name}.a: phases\n" "{.end}\n" "\n" "{.repeated section Phases}\n" "a{Phase}: $(O{Phase})\n" "{.repeated section ArCmds}\n" - " $(AR) grc {.section Pkg}{Name}.a{.end}{.repeated section Files} {Name|basename}.$O{.end}\n" + " $(AR) grc {ObjDir}$D/{.section Pkg}{Name}.a{.end}{.repeated section Files} {Name|basename}.$O{.end}\n" "{.end}\n" " rm -f $(O{Phase})\n" "\n" "{.end}\n" "\n" "newpkg: clean\n" + " mkdir -p {ObjDir}$D\n" "{.repeated section Packages}\n" - " $(AR) grc {Name}.a\n" + " $(AR) grc {ObjDir}$D/{Name}.a\n" "{.end}\n" "\n" "$(O1): newpkg\n" @@ -83,13 +86,14 @@ var makefileTemplate = "{.end}\n" "\n" "nuke: clean\n" - " rm -f{.repeated section Packages} $(GOROOT)/pkg/{Name}.a{.end}\n" + " rm -f{.repeated section Packages} $(GOROOT)/pkg$D/{Name}.a{.end}\n" "\n" - "packages:{.repeated section Packages} {Name}.a{.end}\n" + "packages:{.repeated section Packages} {ObjDir}$D/{Name}.a{.end}\n" "\n" "install: packages\n" + " test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg$D\n" "{.repeated section Packages}\n" - " cp {Name}.a $(GOROOT)/pkg/{Name}.a\n" + " cp {ObjDir}$D/{Name}.a $(GOROOT)/pkg$D/{Name}.a\n" "{.end}\n" func argsFmt(w io.Write, x interface{}, format string) { diff --git a/src/cmd/gobuild/util.go b/src/cmd/gobuild/util.go index 022417289..8f69f39b4 100644 --- a/src/cmd/gobuild/util.go +++ b/src/cmd/gobuild/util.go @@ -6,11 +6,11 @@ package gobuild import ( - "ast"; "exec"; "fmt"; + "go/ast"; + "go/parser"; "os"; - "parser"; "path"; "sort"; "strconv"; @@ -30,6 +30,8 @@ var theChars = map[string] string { "arm": "5" } +const ObjDir = "_obj" + func fatal(args ...) { fmt.Fprintf(os.Stderr, "gobuild: %s\n", fmt.Sprint(args)); sys.Exit(1); @@ -124,7 +126,7 @@ func Archive(pkg string, files []string) { func Compiler(file string) []string { switch { case strings.HasSuffix(file, ".go"): - return []string{ theChar + "g" }; + return []string{ theChar + "g", "-I", ObjDir }; case strings.HasSuffix(file, ".c"): return []string{ theChar + "c", "-FVw" }; case strings.HasSuffix(file, ".s"): @@ -242,3 +244,37 @@ func SourceFiles(dir string) ([]string, *os.Error) { sort.SortStrings(out); return out, nil; } + +// TODO(rsc): Implement these for real as +// os.MkdirAll and os.RemoveAll and then +// make these wrappers that call fatal on error. + +func MkdirAll(name string) { + p, err := exec.Run("/bin/mkdir", []string{"mkdir", "-p", name}, os.Environ(), exec.DevNull, exec.PassThrough, exec.PassThrough); + if err != nil { + fatal("run /bin/mkdir: %v", err); + } + w, err1 := p.Wait(0); + if err1 != nil { + fatal("wait /bin/mkdir: %v", err); + } + if !w.Exited() || w.ExitStatus() != 0 { + fatal("/bin/mkdir: %v", w); + } +} + +func RemoveAll(name string) { + p, err := exec.Run("/bin/rm", []string{"rm", "-rf", name}, os.Environ(), exec.DevNull, exec.PassThrough, exec.PassThrough); + if err != nil { + fatal("run /bin/rm: %v", err); + } + w, err1 := p.Wait(0); + if err1 != nil { + fatal("wait /bin/rm: %v", err); + } + if !w.Exited() || w.ExitStatus() != 0 { + fatal("/bin/rm: %v", w); + } + +} + |