github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/cmd/internal/goobj/goobj_test.go (about) 1 // Copyright 2017 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package goobj 6 7 import ( 8 "debug/elf" 9 "debug/macho" 10 "debug/pe" 11 "fmt" 12 "github.com/gagliardetto/golang-go/not-internal/testenv" 13 "github.com/gagliardetto/golang-go/not-internal/xcoff" 14 "io" 15 "io/ioutil" 16 "os" 17 "os/exec" 18 "path/filepath" 19 "runtime" 20 "testing" 21 ) 22 23 var ( 24 buildDir string 25 go1obj string 26 go2obj string 27 goarchive string 28 cgoarchive string 29 ) 30 31 func TestMain(m *testing.M) { 32 if !testenv.HasGoBuild() { 33 return 34 } 35 36 if err := buildGoobj(); err != nil { 37 fmt.Println(err) 38 os.RemoveAll(buildDir) 39 os.Exit(1) 40 } 41 42 exit := m.Run() 43 44 os.RemoveAll(buildDir) 45 os.Exit(exit) 46 } 47 48 func copyDir(dst, src string) error { 49 err := os.MkdirAll(dst, 0777) 50 if err != nil { 51 return err 52 } 53 fis, err := ioutil.ReadDir(src) 54 if err != nil { 55 return err 56 } 57 for _, fi := range fis { 58 err = copyFile(filepath.Join(dst, fi.Name()), filepath.Join(src, fi.Name())) 59 if err != nil { 60 return err 61 } 62 } 63 return nil 64 } 65 66 func copyFile(dst, src string) (err error) { 67 var s, d *os.File 68 s, err = os.Open(src) 69 if err != nil { 70 return err 71 } 72 defer s.Close() 73 d, err = os.Create(dst) 74 if err != nil { 75 return err 76 } 77 defer func() { 78 e := d.Close() 79 if err == nil { 80 err = e 81 } 82 }() 83 _, err = io.Copy(d, s) 84 if err != nil { 85 return err 86 } 87 return nil 88 } 89 90 func buildGoobj() error { 91 var err error 92 93 buildDir, err = ioutil.TempDir("", "TestGoobj") 94 if err != nil { 95 return err 96 } 97 98 go1obj = filepath.Join(buildDir, "go1.o") 99 go2obj = filepath.Join(buildDir, "go2.o") 100 goarchive = filepath.Join(buildDir, "go.a") 101 102 gotool, err := testenv.GoTool() 103 if err != nil { 104 return err 105 } 106 107 go1src := filepath.Join("testdata", "go1.go") 108 go2src := filepath.Join("testdata", "go2.go") 109 110 out, err := exec.Command(gotool, "tool", "compile", "-o", go1obj, go1src).CombinedOutput() 111 if err != nil { 112 return fmt.Errorf("go tool compile -o %s %s: %v\n%s", go1obj, go1src, err, out) 113 } 114 out, err = exec.Command(gotool, "tool", "compile", "-o", go2obj, go2src).CombinedOutput() 115 if err != nil { 116 return fmt.Errorf("go tool compile -o %s %s: %v\n%s", go2obj, go2src, err, out) 117 } 118 out, err = exec.Command(gotool, "tool", "pack", "c", goarchive, go1obj, go2obj).CombinedOutput() 119 if err != nil { 120 return fmt.Errorf("go tool pack c %s %s %s: %v\n%s", goarchive, go1obj, go2obj, err, out) 121 } 122 123 if testenv.HasCGO() { 124 gopath := filepath.Join(buildDir, "gopath") 125 err = copyDir(filepath.Join(gopath, "src", "mycgo"), filepath.Join("testdata", "mycgo")) 126 if err == nil { 127 err = ioutil.WriteFile(filepath.Join(gopath, "src", "mycgo", "go.mod"), []byte("module mycgo\n"), 0666) 128 } 129 if err != nil { 130 return err 131 } 132 cmd := exec.Command(gotool, "install", "-gcflags=all="+os.Getenv("GO_GCFLAGS"), "mycgo") 133 cmd.Dir = filepath.Join(gopath, "src", "mycgo") 134 cmd.Env = append(os.Environ(), "GOPATH="+gopath) 135 out, err = cmd.CombinedOutput() 136 if err != nil { 137 return fmt.Errorf("go install mycgo: %v\n%s", err, out) 138 } 139 pat := filepath.Join(gopath, "pkg", "*", "mycgo.a") 140 ms, err := filepath.Glob(pat) 141 if err != nil { 142 return err 143 } 144 if len(ms) == 0 { 145 return fmt.Errorf("cannot found paths for pattern %s", pat) 146 } 147 cgoarchive = ms[0] 148 } 149 150 return nil 151 } 152 153 func TestParseGoobj(t *testing.T) { 154 path := go1obj 155 156 f, err := os.Open(path) 157 if err != nil { 158 t.Fatal(err) 159 } 160 defer f.Close() 161 162 p, err := Parse(f, "mypkg") 163 if err != nil { 164 t.Fatal(err) 165 } 166 if p.Arch != runtime.GOARCH { 167 t.Errorf("%s: got %v, want %v", path, p.Arch, runtime.GOARCH) 168 } 169 var found bool 170 for _, s := range p.Syms { 171 if s.Name == "mypkg.go1" { 172 found = true 173 break 174 } 175 } 176 if !found { 177 t.Errorf(`%s: symbol "mypkg.go1" not found`, path) 178 } 179 } 180 181 func TestParseArchive(t *testing.T) { 182 path := goarchive 183 184 f, err := os.Open(path) 185 if err != nil { 186 t.Fatal(err) 187 } 188 defer f.Close() 189 190 p, err := Parse(f, "mypkg") 191 if err != nil { 192 t.Fatal(err) 193 } 194 if p.Arch != runtime.GOARCH { 195 t.Errorf("%s: got %v, want %v", path, p.Arch, runtime.GOARCH) 196 } 197 var found1 bool 198 var found2 bool 199 for _, s := range p.Syms { 200 if s.Name == "mypkg.go1" { 201 found1 = true 202 } 203 if s.Name == "mypkg.go2" { 204 found2 = true 205 } 206 } 207 if !found1 { 208 t.Errorf(`%s: symbol "mypkg.go1" not found`, path) 209 } 210 if !found2 { 211 t.Errorf(`%s: symbol "mypkg.go2" not found`, path) 212 } 213 } 214 215 func TestParseCGOArchive(t *testing.T) { 216 testenv.MustHaveCGO(t) 217 218 path := cgoarchive 219 220 f, err := os.Open(path) 221 if err != nil { 222 t.Fatal(err) 223 } 224 defer f.Close() 225 226 p, err := Parse(f, "mycgo") 227 if err != nil { 228 t.Fatal(err) 229 } 230 if p.Arch != runtime.GOARCH { 231 t.Errorf("%s: got %v, want %v", path, p.Arch, runtime.GOARCH) 232 } 233 var found1 bool 234 var found2 bool 235 for _, s := range p.Syms { 236 if s.Name == "mycgo.go1" { 237 found1 = true 238 } 239 if s.Name == "mycgo.go2" { 240 found2 = true 241 } 242 } 243 if !found1 { 244 t.Errorf(`%s: symbol "mycgo.go1" not found`, path) 245 } 246 if !found2 { 247 t.Errorf(`%s: symbol "mycgo.go2" not found`, path) 248 } 249 250 c1 := "c1" 251 c2 := "c2" 252 253 found1 = false 254 found2 = false 255 256 switch runtime.GOOS { 257 case "darwin": 258 c1 = "_" + c1 259 c2 = "_" + c2 260 for _, obj := range p.Native { 261 mf, err := macho.NewFile(obj) 262 if err != nil { 263 t.Fatal(err) 264 } 265 if mf.Symtab == nil { 266 continue 267 } 268 for _, s := range mf.Symtab.Syms { 269 switch s.Name { 270 case c1: 271 found1 = true 272 case c2: 273 found2 = true 274 } 275 } 276 } 277 case "windows": 278 if runtime.GOARCH == "386" { 279 c1 = "_" + c1 280 c2 = "_" + c2 281 } 282 for _, obj := range p.Native { 283 pf, err := pe.NewFile(obj) 284 if err != nil { 285 t.Fatal(err) 286 } 287 for _, s := range pf.Symbols { 288 switch s.Name { 289 case c1: 290 found1 = true 291 case c2: 292 found2 = true 293 } 294 } 295 } 296 case "aix": 297 c1 = "." + c1 298 c2 = "." + c2 299 for _, obj := range p.Native { 300 xf, err := xcoff.NewFile(obj) 301 if err != nil { 302 t.Fatal(err) 303 } 304 for _, s := range xf.Symbols { 305 switch s.Name { 306 case c1: 307 found1 = true 308 case c2: 309 found2 = true 310 } 311 } 312 } 313 314 default: 315 for _, obj := range p.Native { 316 ef, err := elf.NewFile(obj) 317 if err != nil { 318 t.Fatal(err) 319 } 320 syms, err := ef.Symbols() 321 if err != nil { 322 t.Fatal(err) 323 } 324 for _, s := range syms { 325 switch s.Name { 326 case c1: 327 found1 = true 328 case c2: 329 found2 = true 330 } 331 } 332 } 333 } 334 335 if !found1 { 336 t.Errorf(`%s: symbol %q not found`, path, c1) 337 } 338 if !found2 { 339 t.Errorf(`%s: symbol %q not found`, path, c2) 340 } 341 }