github.com/seh/gb@v0.4.4-0.20160724065125-065d2b2b1ba1/install.go (about) 1 package gb 2 3 import ( 4 "os" 5 "path/filepath" 6 "runtime" 7 "time" 8 9 "github.com/constabulary/gb/internal/debug" 10 ) 11 12 // pkgpath returns the destination for object cached for this Package. 13 func pkgpath(pkg *Package) string { 14 importpath := filepath.FromSlash(pkg.ImportPath) + ".a" 15 switch { 16 case pkg.isCrossCompile(): 17 return filepath.Join(pkg.Pkgdir(), importpath) 18 case pkg.Standard && pkg.race: 19 // race enabled standard lib 20 return filepath.Join(runtime.GOROOT(), "pkg", pkg.gotargetos+"_"+pkg.gotargetarch+"_race", importpath) 21 case pkg.Standard: 22 // standard lib 23 return filepath.Join(runtime.GOROOT(), "pkg", pkg.gotargetos+"_"+pkg.gotargetarch, importpath) 24 default: 25 return filepath.Join(pkg.Pkgdir(), importpath) 26 } 27 } 28 29 // installpath returns the distination to cache this package's compiled .a file. 30 // pkgpath and installpath differ in that the former returns the location where you will find 31 // a previously cached .a file, the latter returns the location where an installed file 32 // will be placed. 33 // 34 // The difference is subtle. pkgpath must deal with the possibility that the file is from the 35 // standard library and is previously compiled. installpath will always return a path for the 36 // project's pkg/ directory in the case that the stdlib is out of date, or not compiled for 37 // a specific architecture. 38 func installpath(pkg *Package) string { 39 if pkg.TestScope { 40 panic("installpath called with test scope") 41 } 42 return filepath.Join(pkg.Pkgdir(), filepath.FromSlash(pkg.ImportPath)+".a") 43 } 44 45 // isStale returns true if the source pkg is considered to be stale with 46 // respect to its installed version. 47 func isStale(pkg *Package) bool { 48 switch pkg.ImportPath { 49 case "C", "unsafe": 50 // synthetic packages are never stale 51 return false 52 } 53 54 if !pkg.Standard && pkg.Force { 55 return true 56 } 57 58 // tests are always stale, they are never installed 59 if pkg.TestScope { 60 return true 61 } 62 63 // Package is stale if completely unbuilt. 64 var built time.Time 65 if fi, err := os.Stat(pkgpath(pkg)); err == nil { 66 built = fi.ModTime() 67 } 68 69 if built.IsZero() { 70 debug.Debugf("%s is missing", pkgpath(pkg)) 71 return true 72 } 73 74 olderThan := func(file string) bool { 75 fi, err := os.Stat(file) 76 return err != nil || fi.ModTime().After(built) 77 } 78 79 newerThan := func(file string) bool { 80 fi, err := os.Stat(file) 81 return err != nil || fi.ModTime().Before(built) 82 } 83 84 // As a courtesy to developers installing new versions of the compiler 85 // frequently, define that packages are stale if they are 86 // older than the compiler, and commands if they are older than 87 // the linker. This heuristic will not work if the binaries are 88 // back-dated, as some binary distributions may do, but it does handle 89 // a very common case. 90 if !pkg.Standard { 91 if olderThan(pkg.tc.compiler()) { 92 debug.Debugf("%s is older than %s", pkgpath(pkg), pkg.tc.compiler()) 93 return true 94 } 95 if pkg.isMain() && olderThan(pkg.tc.linker()) { 96 debug.Debugf("%s is older than %s", pkgpath(pkg), pkg.tc.compiler()) 97 return true 98 } 99 } 100 101 if pkg.Standard && !pkg.isCrossCompile() { 102 // if this is a standard lib package, and we are not cross compiling 103 // then assume the package is up to date. This also works around 104 // golang/go#13769. 105 return false 106 } 107 108 // Package is stale if a dependency is newer. 109 for _, p := range pkg.Imports { 110 if p.ImportPath == "C" || p.ImportPath == "unsafe" { 111 continue // ignore stale imports of synthetic packages 112 } 113 if olderThan(pkgpath(p)) { 114 debug.Debugf("%s is older than %s", pkgpath(pkg), pkgpath(p)) 115 return true 116 } 117 } 118 119 // if the main package is up to date but _newer_ than the binary (which 120 // could have been removed), then consider it stale. 121 if pkg.isMain() && newerThan(pkg.Binfile()) { 122 debug.Debugf("%s is newer than %s", pkgpath(pkg), pkg.Binfile()) 123 return true 124 } 125 126 srcs := stringList(pkg.GoFiles, pkg.CFiles, pkg.CXXFiles, pkg.MFiles, pkg.HFiles, pkg.SFiles, pkg.CgoFiles, pkg.SysoFiles, pkg.SwigFiles, pkg.SwigCXXFiles) 127 128 for _, src := range srcs { 129 if olderThan(filepath.Join(pkg.Dir, src)) { 130 debug.Debugf("%s is older than %s", pkgpath(pkg), filepath.Join(pkg.Dir, src)) 131 return true 132 } 133 } 134 135 return false 136 } 137 138 func stringList(args ...[]string) []string { 139 var l []string 140 for _, arg := range args { 141 l = append(l, arg...) 142 } 143 return l 144 }