| // 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" // use for import paths |
| "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 = path.Split(pkg) |
| targDir = tree.BinDir() |
| } |
| dirInfo, err := build.ScanDir(dir) |
| 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.Must(template.New("Makefile").Parse(` |
| include $(GOROOT)/src/Make.inc |
| |
| TARG={{.Targ}} |
| TARGDIR={{.TargDir}} |
| |
| {{with .GoFiles}} |
| GOFILES=\ |
| {{range .}} {{.}}\ |
| {{end}} |
| |
| {{end}} |
| {{with .OFiles}} |
| OFILES=\ |
| {{range .}} {{.}}\ |
| {{end}} |
| |
| {{end}} |
| {{with .CgoFiles}} |
| CGOFILES=\ |
| {{range .}} {{.}}\ |
| {{end}} |
| |
| {{end}} |
| {{with .CgoOFiles}} |
| CGO_OFILES=\ |
| {{range .}} {{.}}\ |
| {{end}} |
| |
| {{end}} |
| GCIMPORTS={{range .Imports}}-I "{{.}}" {{end}} |
| LDIMPORTS={{range .Imports}}-L "{{.}}" {{end}} |
| |
| include $(GOROOT)/src/Make.{{.Type}} |
| `)) |