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