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