]> Cypherpunks repositories - gostls13.git/commitdiff
goinstall: build with make by default, add -make flag
authorAndrew Gerrand <adg@golang.org>
Fri, 24 Jun 2011 03:01:17 +0000 (13:01 +1000)
committerAndrew Gerrand <adg@golang.org>
Fri, 24 Jun 2011 03:01:17 +0000 (13:01 +1000)
This is a temporary measure until go/build can build cgo packages.

R=golang-dev, r
CC=golang-dev
https://golang.org/cl/4627056

src/cmd/goinstall/Makefile
src/cmd/goinstall/main.go
src/cmd/goinstall/make.go [new file with mode: 0644]

index 399d294adcbdd6d49e5cae0e77bb999f6c439d6e..f61354f39f1e1a5f3d3d20f362203f17ece1fc32 100644 (file)
@@ -8,5 +8,6 @@ TARG=goinstall
 GOFILES=\
        download.go\
        main.go\
+       make.go\
 
 include ../../Make.cmd
index c4383aa077fefca1619acbce4250efe4dab58074..bdf8469a00019021306a92fba075c918a0f8c9a4 100644 (file)
@@ -41,6 +41,7 @@ var (
        doInstall         = flag.Bool("install", true, "build and install")
        clean             = flag.Bool("clean", false, "clean the package directory before installing")
        nuke              = flag.Bool("nuke", false, "clean the package directory and target before installing")
+       useMake           = flag.Bool("make", true, "use make to build and install")
        verbose           = flag.Bool("v", false, "verbose")
 )
 
@@ -211,27 +212,35 @@ func install(pkg, parent string) {
        }
 
        // Install this package.
-       script, err := build.Build(tree, pkg, dirInfo)
-       if err != nil {
-               errorf("%s: install: %v\n", pkg, err)
-               return
-       }
-       if *nuke {
-               printf("%s: nuke\n", pkg)
-               script.Nuke()
-       } else if *clean {
-               printf("%s: clean\n", pkg)
-               script.Clean()
-       }
-       if *doInstall {
-               if script.Stale() {
-                       printf("%s: install\n", pkg)
-                       if err := script.Run(); err != nil {
-                               errorf("%s: install: %v\n", pkg, err)
-                               return
+       if *useMake {
+               err := domake(dir, pkg, tree, dirInfo.IsCommand())
+               if err != nil {
+                       errorf("%s: install: %v\n", pkg, err)
+                       return
+               }
+       } else {
+               script, err := build.Build(tree, pkg, dirInfo)
+               if err != nil {
+                       errorf("%s: install: %v\n", pkg, err)
+                       return
+               }
+               if *nuke {
+                       printf("%s: nuke\n", pkg)
+                       script.Nuke()
+               } else if *clean {
+                       printf("%s: clean\n", pkg)
+                       script.Clean()
+               }
+               if *doInstall {
+                       if script.Stale() {
+                               printf("%s: install\n", pkg)
+                               if err := script.Run(); err != nil {
+                                       errorf("%s: install: %v\n", pkg, err)
+                                       return
+                               }
+                       } else {
+                               printf("%s: up-to-date\n", pkg)
                        }
-               } else {
-                       printf("%s: up-to-date\n", pkg)
                }
        }
        if remote {
diff --git a/src/cmd/goinstall/make.go b/src/cmd/goinstall/make.go
new file mode 100644 (file)
index 0000000..0fd9b02
--- /dev/null
@@ -0,0 +1,180 @@
+// Copyright 2011 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Run "make install" to build package.
+
+package main
+
+import (
+       "bytes"
+       "go/build"
+       "os"
+       "path/filepath"
+       "strings"
+       "template"
+)
+
+// domake builds the package in dir.
+// domake generates a standard Makefile and passes it
+// to make on standard input.
+func domake(dir, pkg string, tree *build.Tree, isCmd bool) (err os.Error) {
+       makefile, err := makeMakefile(dir, pkg, tree, isCmd)
+       if err != nil {
+               return err
+       }
+       cmd := []string{"bash", "gomake", "-f-"}
+       if *nuke {
+               cmd = append(cmd, "nuke")
+       } else if *clean {
+               cmd = append(cmd, "clean")
+       }
+       cmd = append(cmd, "install")
+       return run(dir, makefile, cmd...)
+}
+
+// makeMakefile computes the standard Makefile for the directory dir
+// installing as package pkg.  It includes all *.go files in the directory
+// except those in package main and those ending in _test.go.
+func makeMakefile(dir, pkg string, tree *build.Tree, isCmd bool) ([]byte, os.Error) {
+       if !safeName(pkg) {
+               return nil, os.NewError("unsafe name: " + pkg)
+       }
+       targ := pkg
+       targDir := tree.PkgDir()
+       if isCmd {
+               // use the last part of the package name for targ
+               _, targ = filepath.Split(pkg)
+               targDir = tree.BinDir()
+       }
+       dirInfo, err := build.ScanDir(dir, isCmd)
+       if err != nil {
+               return nil, err
+       }
+
+       cgoFiles := dirInfo.CgoFiles
+       isCgo := make(map[string]bool, len(cgoFiles))
+       for _, file := range cgoFiles {
+               if !safeName(file) {
+                       return nil, os.NewError("bad name: " + file)
+               }
+               isCgo[file] = true
+       }
+
+       goFiles := make([]string, 0, len(dirInfo.GoFiles))
+       for _, file := range dirInfo.GoFiles {
+               if !safeName(file) {
+                       return nil, os.NewError("unsafe name: " + file)
+               }
+               if !isCgo[file] {
+                       goFiles = append(goFiles, file)
+               }
+       }
+
+       oFiles := make([]string, 0, len(dirInfo.CFiles)+len(dirInfo.SFiles))
+       cgoOFiles := make([]string, 0, len(dirInfo.CFiles))
+       for _, file := range dirInfo.CFiles {
+               if !safeName(file) {
+                       return nil, os.NewError("unsafe name: " + file)
+               }
+               // When cgo is in use, C files are compiled with gcc,
+               // otherwise they're compiled with gc.
+               if len(cgoFiles) > 0 {
+                       cgoOFiles = append(cgoOFiles, file[:len(file)-2]+".o")
+               } else {
+                       oFiles = append(oFiles, file[:len(file)-2]+".$O")
+               }
+       }
+
+       for _, file := range dirInfo.SFiles {
+               if !safeName(file) {
+                       return nil, os.NewError("unsafe name: " + file)
+               }
+               oFiles = append(oFiles, file[:len(file)-2]+".$O")
+       }
+
+       var imports []string
+       for _, t := range build.Path {
+               imports = append(imports, t.PkgDir())
+       }
+
+       var buf bytes.Buffer
+       md := makedata{targ, targDir, "pkg", goFiles, oFiles, cgoFiles, cgoOFiles, imports}
+       if isCmd {
+               md.Type = "cmd"
+       }
+       if err := makefileTemplate.Execute(&buf, &md); err != nil {
+               return nil, err
+       }
+       return buf.Bytes(), nil
+}
+
+var safeBytes = []byte("+-./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz")
+
+func safeName(s string) bool {
+       if s == "" {
+               return false
+       }
+       if strings.Contains(s, "..") {
+               return false
+       }
+       for i := 0; i < len(s); i++ {
+               if c := s[i]; c < 0x80 && bytes.IndexByte(safeBytes, c) < 0 {
+                       return false
+               }
+       }
+       return true
+}
+
+// makedata is the data type for the makefileTemplate.
+type makedata struct {
+       Targ      string   // build target
+       TargDir   string   // build target directory
+       Type      string   // build type: "pkg" or "cmd"
+       GoFiles   []string // list of non-cgo .go files
+       OFiles    []string // list of .$O files
+       CgoFiles  []string // list of cgo .go files
+       CgoOFiles []string // list of cgo .o files, without extension
+       Imports   []string // gc/ld import paths
+}
+
+var makefileTemplate = template.MustParse(`
+include $(GOROOT)/src/Make.inc
+
+TARG={Targ}
+TARGDIR={TargDir}
+
+{.section GoFiles}
+GOFILES=\
+{.repeated section @}
+       {@}\
+{.end}
+
+{.end}
+{.section OFiles}
+OFILES=\
+{.repeated section @}
+       {@}\
+{.end}
+
+{.end}
+{.section CgoFiles}
+CGOFILES=\
+{.repeated section @}
+       {@}\
+{.end}
+
+{.end}
+{.section CgoOFiles}
+CGO_OFILES=\
+{.repeated section @}
+       {@}\
+{.end}
+
+{.end}
+GCIMPORTS={.repeated section Imports}-I "{@}" {.end}
+LDIMPORTS={.repeated section Imports}-L "{@}" {.end}
+
+include $(GOROOT)/src/Make.{Type}
+`,
+       nil)