github.com/dannin/go@v0.0.0-20161031215817-d35dfd405eaa/src/cmd/link/internal/ld/config.go (about)

     1  // Copyright 2016 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 ld
     6  
     7  import (
     8  	"cmd/internal/obj"
     9  	"cmd/internal/sys"
    10  	"fmt"
    11  	"log"
    12  )
    13  
    14  var (
    15  	Linkmode  LinkMode
    16  	Buildmode BuildMode
    17  )
    18  
    19  // A BuildMode indicates the sort of object we are building.
    20  //
    21  // Possible build modes are the same as those for the -buildmode flag
    22  // in cmd/go, and are documented in 'go help buildmode'.
    23  type BuildMode uint8
    24  
    25  const (
    26  	BuildmodeUnset BuildMode = iota
    27  	BuildmodeExe
    28  	BuildmodePIE
    29  	BuildmodeCArchive
    30  	BuildmodeCShared
    31  	BuildmodeShared
    32  	BuildmodePlugin
    33  )
    34  
    35  func (mode *BuildMode) Set(s string) error {
    36  	badmode := func() error {
    37  		return fmt.Errorf("buildmode %s not supported on %s/%s", s, obj.GOOS, obj.GOARCH)
    38  	}
    39  	switch s {
    40  	default:
    41  		return fmt.Errorf("invalid buildmode: %q", s)
    42  	case "exe":
    43  		*mode = BuildmodeExe
    44  	case "pie":
    45  		switch obj.GOOS {
    46  		case "android", "linux":
    47  		default:
    48  			return badmode()
    49  		}
    50  		*mode = BuildmodePIE
    51  	case "c-archive":
    52  		switch obj.GOOS {
    53  		case "darwin", "linux":
    54  		case "windows":
    55  			switch obj.GOARCH {
    56  			case "amd64", "386":
    57  			default:
    58  				return badmode()
    59  			}
    60  		default:
    61  			return badmode()
    62  		}
    63  		*mode = BuildmodeCArchive
    64  	case "c-shared":
    65  		switch obj.GOARCH {
    66  		case "386", "amd64", "arm", "arm64":
    67  		default:
    68  			return badmode()
    69  		}
    70  		*mode = BuildmodeCShared
    71  	case "shared":
    72  		switch obj.GOOS {
    73  		case "linux":
    74  			switch obj.GOARCH {
    75  			case "386", "amd64", "arm", "arm64", "ppc64le", "s390x":
    76  			default:
    77  				return badmode()
    78  			}
    79  		default:
    80  			return badmode()
    81  		}
    82  		*mode = BuildmodeShared
    83  	case "plugin":
    84  		switch obj.GOOS {
    85  		case "linux":
    86  			switch obj.GOARCH {
    87  			case "386", "amd64", "arm", "arm64":
    88  			default:
    89  				return badmode()
    90  			}
    91  		case "darwin":
    92  			switch obj.GOARCH {
    93  			case "amd64":
    94  			default:
    95  				return badmode()
    96  			}
    97  		default:
    98  			return badmode()
    99  		}
   100  		*mode = BuildmodePlugin
   101  	}
   102  	return nil
   103  }
   104  
   105  func (mode *BuildMode) String() string {
   106  	switch *mode {
   107  	case BuildmodeUnset:
   108  		return "" // avoid showing a default in usage message
   109  	case BuildmodeExe:
   110  		return "exe"
   111  	case BuildmodePIE:
   112  		return "pie"
   113  	case BuildmodeCArchive:
   114  		return "c-archive"
   115  	case BuildmodeCShared:
   116  		return "c-shared"
   117  	case BuildmodeShared:
   118  		return "shared"
   119  	case BuildmodePlugin:
   120  		return "plugin"
   121  	}
   122  	return fmt.Sprintf("BuildMode(%d)", uint8(*mode))
   123  }
   124  
   125  // LinkMode indicates whether an external linker is used for the final link.
   126  type LinkMode uint8
   127  
   128  const (
   129  	LinkAuto LinkMode = iota
   130  	LinkInternal
   131  	LinkExternal
   132  )
   133  
   134  func (mode *LinkMode) Set(s string) error {
   135  	switch s {
   136  	default:
   137  		return fmt.Errorf("invalid linkmode: %q", s)
   138  	case "auto":
   139  		*mode = LinkAuto
   140  	case "internal":
   141  		*mode = LinkInternal
   142  	case "external":
   143  		*mode = LinkExternal
   144  	}
   145  	return nil
   146  }
   147  
   148  func (mode *LinkMode) String() string {
   149  	switch *mode {
   150  	case LinkAuto:
   151  		return "auto"
   152  	case LinkInternal:
   153  		return "internal"
   154  	case LinkExternal:
   155  		return "external"
   156  	}
   157  	return fmt.Sprintf("LinkMode(%d)", uint8(*mode))
   158  }
   159  
   160  // mustLinkExternal reports whether the program being linked requires
   161  // the external linker be used to complete the link.
   162  func mustLinkExternal(ctxt *Link) (res bool, reason string) {
   163  	if ctxt.Debugvlog > 1 {
   164  		defer func() {
   165  			if res {
   166  				log.Printf("external linking is forced by: %s\n", reason)
   167  			}
   168  		}()
   169  	}
   170  
   171  	switch obj.GOOS {
   172  	case "android":
   173  		return true, "android"
   174  	case "darwin":
   175  		if SysArch.InFamily(sys.ARM, sys.ARM64) {
   176  			return true, "iOS"
   177  		}
   178  	}
   179  
   180  	if *flagMsan {
   181  		return true, "msan"
   182  	}
   183  
   184  	// Internally linking cgo is incomplete on some architectures.
   185  	// https://golang.org/issue/10373
   186  	// https://golang.org/issue/14449
   187  	if iscgo && SysArch.InFamily(sys.ARM64, sys.MIPS64) {
   188  		return true, obj.GOARCH + " does not support internal cgo"
   189  	}
   190  
   191  	// Some build modes require work the internal linker cannot do (yet).
   192  	switch Buildmode {
   193  	case BuildmodeCArchive:
   194  		return true, "buildmode=c-archive"
   195  	case BuildmodeCShared:
   196  		return true, "buildmode=c-shared"
   197  	case BuildmodePIE:
   198  		switch obj.GOOS + "/" + obj.GOARCH {
   199  		case "linux/amd64":
   200  		default:
   201  			// Internal linking does not support TLS_IE.
   202  			return true, "buildmode=pie"
   203  		}
   204  	case BuildmodePlugin:
   205  		return true, "buildmode=plugin"
   206  	case BuildmodeShared:
   207  		return true, "buildmode=shared"
   208  	}
   209  	if *FlagLinkshared {
   210  		return true, "dynamically linking with a shared library"
   211  	}
   212  
   213  	return false, ""
   214  }
   215  
   216  // determineLinkMode sets Linkmode.
   217  //
   218  // It is called after flags are processed and inputs are processed,
   219  // so the Linkmode variable has an initial value from the -linkmode
   220  // flag and the iscgo externalobj variables are set.
   221  func determineLinkMode(ctxt *Link) {
   222  	switch Linkmode {
   223  	case LinkAuto:
   224  		// The environment variable GO_EXTLINK_ENABLED controls the
   225  		// default value of -linkmode. If it is not set when the
   226  		// linker is called we take the value it was set to when
   227  		// cmd/link was compiled. (See make.bash.)
   228  		switch obj.Getgoextlinkenabled() {
   229  		case "0":
   230  			if needed, reason := mustLinkExternal(ctxt); needed {
   231  				Exitf("internal linking requested via GO_EXTLINK_ENABLED, but external linking required: %s", reason)
   232  			}
   233  			Linkmode = LinkInternal
   234  		case "1":
   235  			Linkmode = LinkExternal
   236  		default:
   237  			if needed, _ := mustLinkExternal(ctxt); needed {
   238  				Linkmode = LinkExternal
   239  			} else if iscgo && externalobj {
   240  				Linkmode = LinkExternal
   241  			} else {
   242  				Linkmode = LinkInternal
   243  			}
   244  		}
   245  	case LinkInternal:
   246  		if needed, reason := mustLinkExternal(ctxt); needed {
   247  			Exitf("internal linking requested but external linking required: %s", reason)
   248  		}
   249  	}
   250  }