1
2
3
4
5 package ld
6
7 import (
8 "fmt"
9 "internal/buildcfg"
10 "internal/platform"
11 )
12
13
14
15
16
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
30
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":
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 ""
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
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
117
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
144 switch ctxt.BuildMode {
145 case BuildModeCArchive:
146 return true, "buildmode=c-archive"
147 case BuildModeCShared:
148 if buildcfg.GOARCH == "wasm" {
149 break
150 }
151 return true, "buildmode=c-shared"
152 case BuildModePIE:
153 if !platform.InternalLinkPIESupported(buildcfg.GOOS, buildcfg.GOARCH) {
154
155 return true, "buildmode=pie"
156 }
157 case BuildModePlugin:
158 return true, "buildmode=plugin"
159 case BuildModeShared:
160 return true, "buildmode=shared"
161 }
162 if ctxt.linkShared {
163 return true, "dynamically linking with a shared library"
164 }
165
166 if unknownObjFormat {
167 return true, "some input objects have an unrecognized file format"
168 }
169
170 if len(dynimportfail) > 0 {
171
172
173
174
175
176 return true, fmt.Sprintf("some packages could not be built to support internal linking (%v)", dynimportfail)
177 }
178
179 return false, ""
180 }
181
182
183
184
185
186
187 func determineLinkMode(ctxt *Link) {
188 extNeeded, extReason := mustLinkExternal(ctxt)
189 via := ""
190
191 if ctxt.LinkMode == LinkAuto {
192
193
194
195
196 switch buildcfg.Getgoextlinkenabled() {
197 case "0":
198 ctxt.LinkMode = LinkInternal
199 via = "via GO_EXTLINK_ENABLED "
200 case "1":
201 ctxt.LinkMode = LinkExternal
202 via = "via GO_EXTLINK_ENABLED "
203 default:
204 preferExternal := len(preferlinkext) != 0
205 if preferExternal && ctxt.Debugvlog > 0 {
206 ctxt.Logf("external linking prefer list is %v\n", preferlinkext)
207 }
208 if extNeeded || (iscgo && (externalobj || preferExternal)) {
209 ctxt.LinkMode = LinkExternal
210 } else {
211 ctxt.LinkMode = LinkInternal
212 }
213 }
214 }
215
216 switch ctxt.LinkMode {
217 case LinkInternal:
218 if extNeeded {
219 Exitf("internal linking requested %sbut external linking required: %s", via, extReason)
220 }
221 case LinkExternal:
222 switch {
223 case buildcfg.GOARCH == "ppc64" && buildcfg.GOOS == "linux":
224 Exitf("external linking not supported for %s/ppc64", buildcfg.GOOS)
225 }
226 }
227 }
228
View as plain text