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