Source file test/linkobj.go

     1  // run
     2  
     3  //go:build !nacl && !js && gc && !wasip1
     4  
     5  // Copyright 2016 The Go Authors. All rights reserved.
     6  // Use of this source code is governed by a BSD-style
     7  // license that can be found in the LICENSE file.
     8  
     9  // Test the compiler -linkobj flag.
    10  
    11  package main
    12  
    13  import (
    14  	"fmt"
    15  	"io/ioutil"
    16  	"log"
    17  	"os"
    18  	"os/exec"
    19  	"strings"
    20  )
    21  
    22  var pwd, tmpdir string
    23  
    24  func main() {
    25  	dir, err := ioutil.TempDir("", "go-test-linkobj-")
    26  	if err != nil {
    27  		log.Fatal(err)
    28  	}
    29  	pwd, err = os.Getwd()
    30  	if err != nil {
    31  		log.Fatal(err)
    32  	}
    33  	if err := os.Chdir(dir); err != nil {
    34  		os.RemoveAll(dir)
    35  		log.Fatal(err)
    36  	}
    37  	tmpdir = dir
    38  
    39  	writeFile("p1.go", `
    40  		package p1
    41  
    42  		func F() {
    43  			println("hello from p1")
    44  		}
    45  	`)
    46  	writeFile("p2.go", `
    47  		package p2
    48  
    49  		import "./p1"
    50  
    51  		func F() {
    52  			p1.F()
    53  			println("hello from p2")
    54  		}
    55  
    56  		func main() {}
    57  	`)
    58  	writeFile("p3.go", `
    59  		package main
    60  
    61  		import "./p2"
    62  
    63  		func main() {
    64  			p2.F()
    65  			println("hello from main")
    66  		}
    67  	`)
    68  
    69  	stdlibimportcfg, err := os.ReadFile(os.Getenv("STDLIB_IMPORTCFG"))
    70  	if err != nil {
    71  		fatalf("listing stdlib export files: %v", err)
    72  	}
    73  
    74  	// two rounds: once using normal objects, again using .a files (compile -pack).
    75  	for round := 0; round < 2; round++ {
    76  		pkg := "-pack=" + fmt.Sprint(round)
    77  
    78  		// The compiler expects the files being read to have the right suffix.
    79  		o := "o"
    80  		if round == 1 {
    81  			o = "a"
    82  		}
    83  
    84  		importcfg := string(stdlibimportcfg) + "\npackagefile p1=p1." + o + "\npackagefile p2=p2." + o
    85  		os.WriteFile("importcfg", []byte(importcfg), 0644)
    86  
    87  		// inlining is disabled to make sure that the link objects contain needed code.
    88  		run("go", "tool", "compile", "-p=p1", pkg, "-D", ".", "-importcfg=importcfg", "-l", "-o", "p1."+o, "-linkobj", "p1.lo", "p1.go")
    89  		run("go", "tool", "compile", "-p=p2", pkg, "-D", ".", "-importcfg=importcfg", "-l", "-o", "p2."+o, "-linkobj", "p2.lo", "p2.go")
    90  		run("go", "tool", "compile", "-p=main", pkg, "-D", ".", "-importcfg=importcfg", "-l", "-o", "p3."+o, "-linkobj", "p3.lo", "p3.go")
    91  
    92  		cp("p1."+o, "p1.oo")
    93  		cp("p2."+o, "p2.oo")
    94  		cp("p3."+o, "p3.oo")
    95  		cp("p1.lo", "p1."+o)
    96  		cp("p2.lo", "p2."+o)
    97  		cp("p3.lo", "p3."+o)
    98  		out := runFail("go", "tool", "link", "p2."+o)
    99  		if !strings.Contains(out, "not package main") {
   100  			fatalf("link p2.o failed but not for package main:\n%s", out)
   101  		}
   102  
   103  		run("go", "tool", "link", "-importcfg=importcfg", "-o", "a.out.exe", "p3."+o)
   104  		out = run("./a.out.exe")
   105  		if !strings.Contains(out, "hello from p1\nhello from p2\nhello from main\n") {
   106  			fatalf("running main, incorrect output:\n%s", out)
   107  		}
   108  
   109  		// ensure that mistaken future round can't use these
   110  		os.Remove("p1.o")
   111  		os.Remove("a.out.exe")
   112  	}
   113  
   114  	cleanup()
   115  }
   116  
   117  func run(args ...string) string {
   118  	out, err := exec.Command(args[0], args[1:]...).CombinedOutput()
   119  	if err != nil {
   120  		fatalf("run %v: %s\n%s", args, err, out)
   121  	}
   122  	return string(out)
   123  }
   124  
   125  func runFail(args ...string) string {
   126  	out, err := exec.Command(args[0], args[1:]...).CombinedOutput()
   127  	if err == nil {
   128  		fatalf("runFail %v: unexpected success!\n%s", args, err, out)
   129  	}
   130  	return string(out)
   131  }
   132  
   133  func cp(src, dst string) {
   134  	data, err := ioutil.ReadFile(src)
   135  	if err != nil {
   136  		fatalf("%v", err)
   137  	}
   138  	err = ioutil.WriteFile(dst, data, 0666)
   139  	if err != nil {
   140  		fatalf("%v", err)
   141  	}
   142  }
   143  
   144  func writeFile(name, data string) {
   145  	err := ioutil.WriteFile(name, []byte(data), 0666)
   146  	if err != nil {
   147  		fatalf("%v", err)
   148  	}
   149  }
   150  
   151  func cleanup() {
   152  	const debug = false
   153  	if debug {
   154  		println("TMPDIR:", tmpdir)
   155  		return
   156  	}
   157  	os.Chdir(pwd) // get out of tmpdir before removing it
   158  	os.RemoveAll(tmpdir)
   159  }
   160  
   161  func fatalf(format string, args ...interface{}) {
   162  	cleanup()
   163  	log.Fatalf(format, args...)
   164  }
   165  

View as plain text