github.com/tiagovtristao/plz@v13.4.0+incompatible/tools/jarcat/ar/ar.go (about) 1 // Package ar provides an ar file archiver. 2 package ar 3 4 import ( 5 "bufio" 6 "io" 7 "os" 8 "path" 9 "runtime" 10 "strings" 11 "time" 12 13 "github.com/peterebden/ar" 14 "gopkg.in/op/go-logging.v1" 15 16 "github.com/thought-machine/please/src/fs" 17 ) 18 19 var log = logging.MustGetLogger("ar") 20 21 // mtime is the time we attach for the modification time of all files. 22 var mtime = time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC) 23 24 // Create creates a new ar archive from the given sources. 25 // If combine is true they are treated as existing ar files and combined. 26 // If rename is true the srcs are renamed as gcc would (i.e. the extension is replaced by .o). 27 func Create(srcs []string, out string, combine, rename bool) error { 28 // Rename the sources as gcc would. 29 if rename { 30 for i, src := range srcs { 31 src = path.Base(src) 32 if ext := path.Ext(src); ext != "" { 33 src = src[:len(src)-len(ext)] + ".o" 34 } 35 srcs[i] = src 36 log.Debug("renamed ar source to %s", src) 37 } 38 } 39 40 log.Debug("Writing ar to %s", out) 41 f, err := os.Create(out) 42 if err != nil { 43 return err 44 } 45 defer f.Close() 46 bw := bufio.NewWriter(f) 47 defer bw.Flush() 48 w := ar.NewWriter(bw) 49 // Write BSD-style names on OSX, GNU-style ones on Linux 50 if runtime.GOOS == "darwin" { 51 if err := w.WriteGlobalHeader(); err != nil { 52 return err 53 } 54 } else { 55 if err := w.WriteGlobalHeaderForLongFiles(allSourceNames(srcs, combine)); err != nil { 56 return err 57 } 58 } 59 for _, src := range srcs { 60 log.Debug("ar source file: %s", src) 61 f, err := os.Open(src) 62 if err != nil { 63 return err 64 } 65 if combine { 66 // Read archive & write its contents in 67 r := ar.NewReader(f) 68 for { 69 hdr, err := r.Next() 70 if err != nil { 71 if err == io.EOF { 72 break 73 } 74 return err 75 } else if hdr.Name == "/" || hdr.Name == "__.SYMDEF SORTED" || hdr.Name == "__.SYMDEF" { 76 log.Debug("skipping symbol table") 77 continue 78 } 79 // Zero things out 80 hdr.ModTime = mtime 81 hdr.Uid = 0 82 hdr.Gid = 0 83 // Fix weird bug about octal numbers (looks like we're prepending 100 multiple times) 84 hdr.Mode &= ^0100000 85 log.Debug("copying '%s' in from %s, mode %x", hdr.Name, src, hdr.Mode) 86 if err := w.WriteHeader(hdr); err != nil { 87 return err 88 } else if _, err = io.Copy(w, r); err != nil { 89 return err 90 } 91 } 92 } else { 93 // Write in individual file 94 info, err := os.Lstat(src) 95 if err != nil { 96 return err 97 } 98 hdr := &ar.Header{ 99 Name: src, 100 ModTime: mtime, 101 Mode: int64(info.Mode()), 102 Size: info.Size(), 103 } 104 log.Debug("creating file %s", hdr.Name) 105 if err := w.WriteHeader(hdr); err != nil { 106 return err 107 } else if _, err := io.Copy(w, f); err != nil { 108 return err 109 } 110 } 111 f.Close() 112 } 113 return nil 114 } 115 116 // Find finds all the .a files under the current directory and returns their names. 117 func Find() ([]string, error) { 118 ret := []string{} 119 return ret, fs.Walk(".", func(name string, isDir bool) error { 120 if strings.HasSuffix(name, ".a") && !isDir { 121 ret = append(ret, name) 122 } 123 return nil 124 }) 125 } 126 127 // allSourceNames returns the name of all source files that we will add to the archive. 128 func allSourceNames(srcs []string, combine bool) []string { 129 if !combine { 130 return srcs 131 } 132 ret := []string{} 133 for _, src := range srcs { 134 f, err := os.Open(src) 135 if err == nil { 136 r := ar.NewReader(f) 137 for { 138 hdr, err := r.Next() 139 if err != nil { 140 break 141 } 142 ret = append(ret, hdr.Name) 143 } 144 } 145 } 146 return ret 147 }