|
| 1 | +# Test case to verify that when we have a package that uses CGO in |
| 2 | +# combination with selected "unusual" flags (involving plugins, LTO) |
| 3 | +# that we force external linking. See related |
| 4 | +# issues 58619, 58620, and 58848. |
| 5 | + |
| 6 | +[compiler:gccgo] skip # only external linking for gccgo |
| 7 | + |
| 8 | +# This test requires external linking, so use cgo as a proxy |
| 9 | +[!cgo] skip |
| 10 | + |
| 11 | +# Here we build three program: one with explicit CGO use, one with no |
| 12 | +# CGO use, and one that uses a stdlib package ("runtime/cgo") that has |
| 13 | +# CGO in it. It used to be that only the explicit use of CGO would |
| 14 | +# trigger external linking, and that the program that only used |
| 15 | +# "runtime/cgo" would always be handled with internal linking. This caused |
| 16 | +# issues when users included odd/unusual flags (ex: -fplugin, -flto) |
| 17 | +# in CGO_CFLAGS, causing the Go linker to have to read and interpret |
| 18 | +# non-standard host objects. |
| 19 | +# |
| 20 | +# As of 1.21 we continue to use internal linking for programs whose |
| 21 | +# CGO use comes ony from stdlib packages in the absence of any flag |
| 22 | +# funny business, however if the Go command sees flags that may be suspicious, |
| 23 | +# it signals the Go linker to invoke the external linker. |
| 24 | + |
| 25 | +# The next few tests run builds passing "-n" to the Go command, then |
| 26 | +# checking the output to see if the Go command is trying to pass a |
| 27 | +# "preferlinkext" token to the linker to request external linking. |
| 28 | + |
| 29 | +#----------------------- |
| 30 | + |
| 31 | +# Use a fresh GOCACHE for these next steps, so as to have the real |
| 32 | +# actions for the runtime/cgo package appear in the "-n -x" output. |
| 33 | +env GOCACHE=$WORK/gocache |
| 34 | +mkdir $GOCACHE |
| 35 | + |
| 36 | +# First build: there is no CGO in use, so no token should be present regardless |
| 37 | +# of weird CGO flags. |
| 38 | +go build -x -n -o dummy.exe ./noUseOfCgo |
| 39 | +! stderr preferlinkext |
| 40 | +env CGO_CFLAGS=-flto |
| 41 | +go build -x -n -o dummy.exe ./noUseOfCgo |
| 42 | +! stderr preferlinkext |
| 43 | +env CGO_CFLAGS= |
| 44 | + |
| 45 | +# Second build uses CGO, so we expect to see the token present in the |
| 46 | +# -n output only when strange flags are used. |
| 47 | +go build -x -n -o dummy.exe ./usesInternalCgo |
| 48 | +! stderr preferlinkext |
| 49 | +env CGO_CFLAGS=-flto |
| 50 | +go build -x -n -o dummy.exe ./usesInternalCgo |
| 51 | +stderr preferlinkext |
| 52 | +env CGO_CFLAGS=-fplugin |
| 53 | +go build -x -n -o dummy.exe ./usesInternalCgo |
| 54 | +stderr preferlinkext |
| 55 | +env CGO_CFLAGS=-fprofile-instr-generate |
| 56 | +go build -x -n -o dummy.exe ./usesInternalCgo |
| 57 | +stderr preferlinkext |
| 58 | +env CGO_CFLAGS= |
| 59 | + |
| 60 | +[short] skip |
| 61 | + |
| 62 | +# In the remaining tests below we do actual builds (without -n) to |
| 63 | +# verify that the Go linker is going the right thing in addition to the |
| 64 | +# Go command. Here the idea is to pass "-tmpdir" to the linker, then |
| 65 | +# check after the link is done for the presence of the file |
| 66 | +# <tmpdir>/go.o, which the Go linker creates prior to kicking off the |
| 67 | +# external linker. |
| 68 | + |
| 69 | +mkdir tmp1 |
| 70 | +mkdir tmp2 |
| 71 | +mkdir tmp3 |
| 72 | +mkdir tmp4 |
| 73 | +mkdir tmp5 |
| 74 | + |
| 75 | +# First build: no external linking expected |
| 76 | +go build -ldflags=-tmpdir=tmp1 -o $devnull ./noUseOfCgo & |
| 77 | + |
| 78 | +# Second build: using only "runtime/cgo", expect internal linking. |
| 79 | +go build -ldflags=-tmpdir=tmp2 -o $devnull ./usesInternalCgo & |
| 80 | + |
| 81 | +# Third build: program uses only "runtime/cgo", so we would normally |
| 82 | +# expect internal linking, except that cflags contain suspicious entries |
| 83 | +# (in this case, a flag that does not appear on the allow list). |
| 84 | +env CGO_CFLAGS=-fmerge-all-constants |
| 85 | +env CGO_LDFLAGS=-fmerge-all-constants |
| 86 | +go build -ldflags=-tmpdir=tmp3 -o $devnull ./usesInternalCgo & |
| 87 | +env CGO_CFLAGS= |
| 88 | +env CGO_LDFLAGS= |
| 89 | + |
| 90 | +# Fourth build: explicit CGO, expect external linking. |
| 91 | +go build -ldflags=-tmpdir=tmp4 -o $devnull ./usesExplicitCgo & |
| 92 | + |
| 93 | +# Fifth build: explicit CGO, but we specifically asked for internal linking |
| 94 | +# via a flag, so using internal linking it is. |
| 95 | +[cgolinkext] go list ./usesInternalCgo |
| 96 | +[!cgolinkext] go build '-ldflags=-tmpdir=tmp5 -linkmode=internal' -o $devnull ./usesInternalCgo & |
| 97 | + |
| 98 | +wait |
| 99 | + |
| 100 | +# Check first build: no external linking expected |
| 101 | +! exists tmp1/go.o |
| 102 | + |
| 103 | +# Check second build: using only "runtime/cgo", expect internal linking. |
| 104 | +[!cgolinkext] ! exists tmp2/go.o |
| 105 | +[cgolinkext] exists tmp2/go.o |
| 106 | + |
| 107 | +# Check third build: has suspicious flag. |
| 108 | +exists tmp3/go.o |
| 109 | + |
| 110 | +# Fourth build: explicit CGO, expect external linking. |
| 111 | +exists tmp4/go.o |
| 112 | + |
| 113 | +# Fifth build: explicit CGO, -linkmode=internal. |
| 114 | +! exists tmp5/go.o |
| 115 | + |
| 116 | +-- go.mod -- |
| 117 | + |
| 118 | +module cgo.example |
| 119 | + |
| 120 | +go 1.20 |
| 121 | + |
| 122 | +-- noUseOfCgo/main.go -- |
| 123 | + |
| 124 | +package main |
| 125 | + |
| 126 | +func main() { |
| 127 | + println("clean as a whistle") |
| 128 | +} |
| 129 | + |
| 130 | +-- usesInternalCgo/main.go -- |
| 131 | + |
| 132 | +package main |
| 133 | + |
| 134 | +import ( |
| 135 | + "runtime/cgo" |
| 136 | +) |
| 137 | + |
| 138 | +func main() { |
| 139 | + q := "hello" |
| 140 | + h := cgo.NewHandle(q) |
| 141 | + h.Delete() |
| 142 | +} |
| 143 | + |
| 144 | +-- usesExplicitCgo/main.go -- |
| 145 | + |
| 146 | +package main |
| 147 | + |
| 148 | +/* |
| 149 | +int meaningOfLife() { return 42; } |
| 150 | +*/ |
| 151 | +import "C" |
| 152 | + |
| 153 | +func main() { |
| 154 | + println(C.meaningOfLife()) |
| 155 | +} |
0 commit comments