Source file src/cmd/link/internal/ld/config.go

     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  	"fmt"
     9  	"internal/buildcfg"
    10  	"internal/platform"
    11  )
    12  
    13  // A BuildMode indicates the sort of object we are building.
    14  //
    15  // Possible build modes are the same as those for the -buildmode flag
    16  // in cmd/go, and are documented in 'go help buildmode'.
    17  type BuildMode uint8
    18  
    19  const (
    20  	BuildModeUnset BuildMode = iota
    21  	BuildModeExe
    22  	BuildModePIE
    23  	BuildModeCArchive
    24  	BuildModeCShared
    25  	BuildModeShared
    26  	BuildModePlugin
    27  )
    28  
    29  // Set implements flag.Value to set the build mode based on the argument
    30  // to the -buildmode flag.
    31  func (mode *BuildMode) Set(s string) error {
    32  	switch s {
    33  	default:
    34  		return fmt.Errorf("invalid buildmode: %q", s)
    35  	case "exe":
    36  		switch buildcfg.GOOS + "/" + buildcfg.GOARCH {
    37  		case "darwin/arm64", "windows/arm", "windows/arm64": // On these platforms, everything is PIE
    38  			*mode = BuildModePIE
    39  		default:
    40  			*mode = BuildModeExe
    41  		}
    42  	case "pie":
    43  		*mode = BuildModePIE
    44  	case "c-archive":
    45  		*mode = BuildModeCArchive
    46  	case "c-shared":
    47  		*mode = BuildModeCShared
    48  	case "shared":
    49  		*mode = BuildModeShared
    50  	case "plugin":
    51  		*mode = BuildModePlugin
    52  	}
    53  
    54  	if !platform.BuildModeSupported("gc", s, buildcfg.GOOS, buildcfg.GOARCH) {
    55  		return fmt.Errorf("buildmode %s not supported on %s/%s", s, buildcfg.GOOS, buildcfg.GOARCH)
    56  	}
    57  
    58  	return nil
    59  }
    60  
    61  func (mode BuildMode) String() string {
    62  	switch mode {
    63  	case BuildModeUnset:
    64  		return "" // avoid showing a default in usage message
    65  	case BuildModeExe:
    66  		return "exe"
    67  	case BuildModePIE:
    68  		return "pie"
    69  	case BuildModeCArchive:
    70  		return "c-archive"
    71  	case BuildModeCShared:
    72  		return "c-shared"
    73  	case BuildModeShared:
    74  		return "shared"
    75  	case BuildModePlugin:
    76  		return "plugin"
    77  	}
    78  	return fmt.Sprintf("BuildMode(%d)", uint8(mode))
    79  }
    80  
    81  // LinkMode indicates whether an external linker is used for the final link.
    82  type LinkMode uint8
    83  
    84  const (
    85  	LinkAuto LinkMode = iota
    86  	LinkInternal
    87  	LinkExternal
    88  )
    89  
    90  func (mode *LinkMode) Set(s string) error {
    91  	switch s {
    92  	default:
    93  		return fmt.Errorf("invalid linkmode: %q", s)
    94  	case "auto":
    95  		*mode = LinkAuto
    96  	case "internal":
    97  		*mode = LinkInternal
    98  	case "external":
    99  		*mode = LinkExternal
   100  	}
   101  	return nil
   102  }
   103  
   104  func (mode *LinkMode) String() string {
   105  	switch *mode {
   106  	case LinkAuto:
   107  		return "auto"
   108  	case LinkInternal:
   109  		return "internal"
   110  	case LinkExternal:
   111  		return "external"
   112  	}
   113  	return fmt.Sprintf("LinkMode(%d)", uint8(*mode))
   114  }
   115  
   116  // mustLinkExternal reports whether the program being linked requires
   117  // the external linker be used to complete the link.
   118  func mustLinkExternal(ctxt *Link) (res bool, reason string) {
   119  	if ctxt.Debugvlog > 1 {
   120  		defer func() {
   121  			if res {
   122  				ctxt.Logf("external linking is forced by: %s\n", reason)
   123  			}
   124  		}()
   125  	}
   126  
   127  	if platform.MustLinkExternal(buildcfg.GOOS, buildcfg.GOARCH, false) {
   128  		return true, fmt.Sprintf("%s/%s requires external linking", buildcfg.GOOS, buildcfg.GOARCH)
   129  	}
   130  
   131  	if *flagMsan {
   132  		return true, "msan"
   133  	}
   134  
   135  	if *flagAsan {
   136  		return true, "asan"
   137  	}
   138  
   139  	if iscgo && platform.MustLinkExternal(buildcfg.GOOS, buildcfg.GOARCH, true) {
   140  		return true, buildcfg.GOARCH + " does not support internal cgo"
   141  	}
   142  
   143  	// Some build modes require work the internal linker cannot do (yet).
   144  	switch ctxt.BuildMode {
   145  	case BuildModeCArchive:
   146  		return true, "buildmode=c-archive"
   147  	case BuildModeCShared:
   148  		return true, "buildmode=c-shared"
   149  	case BuildModePIE:
   150  		if !platform.InternalLinkPIESupported(buildcfg.GOOS, buildcfg.GOARCH) {
   151  			// Internal linking does not support TLS_IE.
   152  			return true, "buildmode=pie"
   153  		}
   154  	case BuildModePlugin:
   155  		return true, "buildmode=plugin"
   156  	case BuildModeShared:
   157  		return true, "buildmode=shared"
   158  	}
   159  	if ctxt.linkShared {
   160  		return true, "dynamically linking with a shared library"
   161  	}
   162  
   163  	if unknownObjFormat {
   164  		return true, "some input objects have an unrecognized file format"
   165  	}
   166  
   167  	if len(dynimportfail) > 0 {
   168  		// This error means that we were unable to generate
   169  		// the _cgo_import.go file for some packages.
   170  		// This typically means that there are some dependencies
   171  		// that the cgo tool could not figure out.
   172  		// See issue #52863.
   173  		return true, fmt.Sprintf("some packages could not be built to support internal linking (%v)", dynimportfail)
   174  	}
   175  
   176  	return false, ""
   177  }
   178  
   179  // determineLinkMode sets ctxt.LinkMode.
   180  //
   181  // It is called after flags are processed and inputs are processed,
   182  // so the ctxt.LinkMode variable has an initial value from the -linkmode
   183  // flag and the iscgo, externalobj, and unknownObjFormat variables are set.
   184  func determineLinkMode(ctxt *Link) {
   185  	extNeeded, extReason := mustLinkExternal(ctxt)
   186  	via := ""
   187  
   188  	if ctxt.LinkMode == LinkAuto {
   189  		// The environment variable GO_EXTLINK_ENABLED controls the
   190  		// default value of -linkmode. If it is not set when the
   191  		// linker is called we take the value it was set to when
   192  		// cmd/link was compiled. (See make.bash.)
   193  		switch buildcfg.Getgoextlinkenabled() {
   194  		case "0":
   195  			ctxt.LinkMode = LinkInternal
   196  			via = "via GO_EXTLINK_ENABLED "
   197  		case "1":
   198  			ctxt.LinkMode = LinkExternal
   199  			via = "via GO_EXTLINK_ENABLED "
   200  		default:
   201  			preferExternal := len(preferlinkext) != 0
   202  			if preferExternal && ctxt.Debugvlog > 0 {
   203  				ctxt.Logf("external linking prefer list is %v\n", preferlinkext)
   204  			}
   205  			if extNeeded || (iscgo && (externalobj || preferExternal)) {
   206  				ctxt.LinkMode = LinkExternal
   207  			} else {
   208  				ctxt.LinkMode = LinkInternal
   209  			}
   210  		}
   211  	}
   212  
   213  	switch ctxt.LinkMode {
   214  	case LinkInternal:
   215  		if extNeeded {
   216  			Exitf("internal linking requested %sbut external linking required: %s", via, extReason)
   217  		}
   218  	case LinkExternal:
   219  		switch {
   220  		case buildcfg.GOARCH == "ppc64" && buildcfg.GOOS == "linux":
   221  			Exitf("external linking not supported for %s/ppc64", buildcfg.GOOS)
   222  		}
   223  	}
   224  }
   225  

View as plain text