Skip to content

Commit c188072

Browse files
authored
respect global strip config (#3527)
1 parent 00d3e6e commit c188072

File tree

10 files changed

+312
-21
lines changed

10 files changed

+312
-21
lines changed

BUILD.bazel

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,11 @@ go_config(
130130
"//conditions:default": False,
131131
}),
132132
static = "//go/config:static",
133-
strip = "//go/config:strip",
133+
strip = select({
134+
"//go/private:is_strip_always": True,
135+
"//go/private:is_strip_sometimes_fastbuild": True,
136+
"//conditions:default": False,
137+
}),
134138
visibility = ["//visibility:public"],
135139
)
136140

go/config/BUILD.bazel

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
load(
22
"@bazel_skylib//rules:common_settings.bzl",
33
"bool_flag",
4-
"bool_setting",
54
"string_flag",
65
"string_list_flag",
76
)
@@ -34,12 +33,6 @@ bool_flag(
3433
visibility = ["//visibility:public"],
3534
)
3635

37-
bool_setting(
38-
name = "strip",
39-
build_setting_default = False,
40-
visibility = ["//visibility:public"],
41-
)
42-
4336
bool_flag(
4437
name = "debug",
4538
build_setting_default = False,

go/modes.rst

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,6 @@ or using `Bazel configuration transitions`_.
6969
| ``CGO_ENABLED=0``). Packages that contain cgo code may still be built, but |
7070
| the cgo code will be filtered out, and the ``cgo`` build tag will be false. |
7171
+-------------------+---------------------+------------------------------------+
72-
| :param:`strip` | :type:`bool` | :value:`false` |
73-
+-------------------+---------------------+------------------------------------+
74-
| Strips symbols from compiled packages and linked binaries (using the ``-w`` |
75-
| flag). May also be set with the ``--strip`` command line option, which |
76-
| affects C/C++ targets, too. |
77-
+-------------------+---------------------+------------------------------------+
7872
| :param:`debug` | :type:`bool` | :value:`false` |
7973
+-------------------+---------------------+------------------------------------+
8074
| Includes debugging information in compiled packages (using the ``-N`` and |

go/private/BUILD.bazel

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,21 @@ config_setting(
3030
visibility = ["//:__pkg__"],
3131
)
3232

33+
config_setting(
34+
name = "is_strip_always",
35+
values = {"strip": "always"},
36+
visibility = ["//:__pkg__"],
37+
)
38+
39+
config_setting(
40+
name = "is_strip_sometimes_fastbuild",
41+
values = {
42+
"strip": "sometimes",
43+
"compilation_mode": "fastbuild",
44+
},
45+
visibility = ["//:__pkg__"],
46+
)
47+
3348
bzl_library(
3449
name = "context",
3550
srcs = ["context.bzl"],

go/private/actions/link.bzl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ def emit_link(
181181
# Do not remove, somehow this is needed when building for darwin/arm only.
182182
tool_args.add("-buildid=redacted")
183183
if go.mode.strip:
184-
tool_args.add("-w")
184+
tool_args.add("-s", "-w")
185185
tool_args.add_joined("-extldflags", extldflags, join_with = " ")
186186

187187
conflict_err = _check_conflicts(arcs)

go/private/context.bzl

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -830,7 +830,7 @@ def _go_config_impl(ctx):
830830
race = ctx.attr.race[BuildSettingInfo].value,
831831
msan = ctx.attr.msan[BuildSettingInfo].value,
832832
pure = ctx.attr.pure[BuildSettingInfo].value,
833-
strip = ctx.attr.strip[BuildSettingInfo].value,
833+
strip = ctx.attr.strip,
834834
debug = ctx.attr.debug[BuildSettingInfo].value,
835835
linkmode = ctx.attr.linkmode[BuildSettingInfo].value,
836836
gc_linkopts = ctx.attr.gc_linkopts[BuildSettingInfo].value,
@@ -860,10 +860,7 @@ go_config = rule(
860860
mandatory = True,
861861
providers = [BuildSettingInfo],
862862
),
863-
"strip": attr.label(
864-
mandatory = True,
865-
providers = [BuildSettingInfo],
866-
),
863+
"strip": attr.bool(mandatory = True),
867864
"debug": attr.label(
868865
mandatory = True,
869866
providers = [BuildSettingInfo],

go/private/rules/transition.bzl

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,6 @@ _common_reset_transition_dict = dict({
174174
"//go/config:msan": False,
175175
"//go/config:race": False,
176176
"//go/config:pure": False,
177-
"//go/config:strip": False,
178177
"//go/config:debug": False,
179178
"//go/config:linkmode": LINKMODE_NORMAL,
180179
"//go/config:tags": [],

tests/core/strip/BUILD.bazel

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
load("@io_bazel_rules_go//go/tools/bazel_testing:def.bzl", "go_bazel_test")
2+
3+
go_bazel_test(
4+
name = "strip_test",
5+
srcs = ["strip_test.go"],
6+
)

tests/core/strip/README.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
symbol stripping
2+
====================
3+
4+
strip_test
5+
---------
6+
7+
Tests that the global Bazel configuration for stripping are applied to go_binary
8+
targets.
9+
In particular, it tests that stripping is performed iff the bazel flag ``--strip``
10+
is set to ``always`` or ``--strip`` is set to ``sometimes`` and ``--compilation_mode``
11+
is ``fastbuild``.
12+
Additionally, it tests that stack traces still contain the same information when stripping
13+
is enabled.

tests/core/strip/strip_test.go

Lines changed: 270 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,270 @@
1+
// Copyright 2019 The Bazel Authors. All rights reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package strip_test
16+
17+
import (
18+
"bytes"
19+
"errors"
20+
"fmt"
21+
"os/exec"
22+
"strings"
23+
"testing"
24+
25+
"github.com/bazelbuild/rules_go/go/tools/bazel_testing"
26+
)
27+
28+
func TestMain(m *testing.M) {
29+
bazel_testing.TestMain(m, bazel_testing.Args{
30+
Main: `
31+
-- BUILD.bazel --
32+
load("@io_bazel_rules_go//go:def.bzl", "go_binary")
33+
34+
go_binary(
35+
name = "strip",
36+
srcs = ["strip.go"],
37+
)
38+
-- strip.go --
39+
package main
40+
41+
import (
42+
"debug/elf"
43+
"debug/macho"
44+
"debug/pe"
45+
"errors"
46+
"flag"
47+
"fmt"
48+
"io"
49+
"os"
50+
"regexp"
51+
"runtime"
52+
"runtime/debug"
53+
"strings"
54+
)
55+
56+
var wantStrip = flag.Bool("wantstrip", false, "")
57+
58+
func main() {
59+
flag.Parse()
60+
stackTrace, err := panicAndRecover()
61+
if err != nil {
62+
panic(err)
63+
}
64+
gotStackTrace := strings.Split(stackTrace, "\n")
65+
if len(gotStackTrace) != len(wantStackTrace) {
66+
panic(fmt.Sprintf("got %d lines of stack trace, want %d", len(gotStackTrace), len(wantStackTrace)))
67+
}
68+
for i := range gotStackTrace {
69+
expectedLine := regexp.MustCompile(wantStackTrace[i])
70+
if !expectedLine.MatchString(gotStackTrace[i]) {
71+
panic(fmt.Sprintf("got unexpected stack trace line %q at index %d", gotStackTrace[i], i))
72+
}
73+
}
74+
stripped, err := isStripped()
75+
if err != nil {
76+
panic(err)
77+
}
78+
if stripped != *wantStrip {
79+
panic(fmt.Sprintf("got stripped=%t, want stripped=%t", stripped, *wantStrip))
80+
}
81+
}
82+
83+
func panicAndRecover() (stackTrace string, err error) {
84+
defer func() {
85+
if r := recover(); r != nil {
86+
stackTrace = string(debug.Stack())
87+
}
88+
}()
89+
panic("test")
90+
return "", errors.New("should not reach here")
91+
}
92+
93+
func isStripped() (bool, error) {
94+
ownLocation, err := os.Executable()
95+
if err != nil {
96+
return false, err
97+
}
98+
ownBinary, err := os.Open(ownLocation)
99+
if err != nil {
100+
return false, err
101+
}
102+
defer ownBinary.Close()
103+
switch runtime.GOOS {
104+
case "darwin":
105+
return isStrippedMachO(ownBinary)
106+
case "linux":
107+
return isStrippedElf(ownBinary)
108+
case "windows":
109+
return isStrippedPE(ownBinary)
110+
default:
111+
return false, fmt.Errorf("unsupported OS: %s", runtime.GOOS)
112+
}
113+
}
114+
115+
func isStrippedMachO(f io.ReaderAt) (bool, error) {
116+
macho, err := macho.NewFile(f)
117+
if err != nil {
118+
return false, err
119+
}
120+
gotDwarf := macho.Segment("__DWARF") != nil
121+
gotDebugInfo := macho.Section("__zdebug_info") != nil
122+
if gotDwarf != gotDebugInfo {
123+
return false, fmt.Errorf("inconsistent stripping: gotDwarf=%v, gotDebugInfo=%v", gotDwarf, gotDebugInfo)
124+
}
125+
return !gotDwarf, nil
126+
}
127+
128+
func isStrippedElf(f io.ReaderAt) (bool, error) {
129+
elf, err := elf.NewFile(f)
130+
if err != nil {
131+
return false, err
132+
}
133+
var gotSymtab bool
134+
for _, section := range elf.Sections {
135+
if section.Name == ".symtab" {
136+
gotSymtab = true
137+
break
138+
}
139+
}
140+
return !gotSymtab, nil
141+
}
142+
143+
144+
func isStrippedPE(f io.ReaderAt) (bool, error) {
145+
pe, err := pe.NewFile(f)
146+
if err != nil {
147+
return false, err
148+
}
149+
symtab := pe.Section(".symtab")
150+
if symtab == nil {
151+
return false, fmt.Errorf("no .symtab section")
152+
}
153+
emptySymtab := (symtab.VirtualSize <= 4) && (symtab.Size <= 512)
154+
return emptySymtab, nil
155+
}
156+
157+
158+
` + embedWantedStackTraces(),
159+
})
160+
}
161+
162+
func Test(t *testing.T) {
163+
for _, test := range []struct {
164+
desc, stripFlag, compilationMode string
165+
wantStrip bool
166+
}{
167+
{
168+
desc: "run_auto",
169+
wantStrip: true,
170+
},
171+
{
172+
desc: "run_fastbuild",
173+
compilationMode: "fastbuild",
174+
wantStrip: true,
175+
},
176+
{
177+
desc: "run_dbg",
178+
compilationMode: "dbg",
179+
},
180+
{
181+
desc: "run_opt",
182+
compilationMode: "opt",
183+
},
184+
{
185+
desc: "run_always",
186+
stripFlag: "always",
187+
wantStrip: true,
188+
},
189+
{
190+
desc: "run_always_opt",
191+
stripFlag: "always",
192+
compilationMode: "opt",
193+
wantStrip: true,
194+
},
195+
{
196+
desc: "run_never",
197+
stripFlag: "never",
198+
},
199+
{
200+
desc: "run_sometimes_fastbuild",
201+
stripFlag: "sometimes",
202+
compilationMode: "fastbuild",
203+
wantStrip: true,
204+
},
205+
{
206+
desc: "run_sometimes_dbg",
207+
stripFlag: "sometimes",
208+
compilationMode: "dbg",
209+
},
210+
{
211+
desc: "run_sometimes_opt",
212+
stripFlag: "sometimes",
213+
compilationMode: "opt",
214+
},
215+
} {
216+
t.Run(test.desc, func(t *testing.T) {
217+
args := []string{"run"}
218+
if len(test.stripFlag) > 0 {
219+
args = append(args, "--strip", test.stripFlag)
220+
}
221+
if len(test.compilationMode) > 0 {
222+
args = append(args, "--compilation_mode", test.compilationMode)
223+
}
224+
args = append(args, "//:strip", "--", fmt.Sprintf("-wantstrip=%v", test.wantStrip))
225+
cmd := bazel_testing.BazelCmd(args...)
226+
stderr := &bytes.Buffer{}
227+
cmd.Stderr = stderr
228+
t.Logf("running: bazel %s", strings.Join(args, " "))
229+
if err := cmd.Run(); err != nil {
230+
var xerr *exec.ExitError
231+
if !errors.As(err, &xerr) {
232+
t.Fatalf("unexpected error: %v", err)
233+
}
234+
if xerr.ExitCode() == bazel_testing.BUILD_FAILURE {
235+
t.Fatalf("unexpected build failure: %v\nstderr:\n%s", err, stderr.Bytes())
236+
return
237+
} else if xerr.ExitCode() == bazel_testing.TESTS_FAILED {
238+
t.Fatalf("error running %s:\n%s", strings.Join(cmd.Args, " "), stderr.Bytes())
239+
} else {
240+
t.Fatalf("unexpected error: %v\nstderr:\n%s", err, stderr.Bytes())
241+
}
242+
}
243+
})
244+
}
245+
}
246+
247+
var wantStackTrace = []string{
248+
`^goroutine \d+ \[running\]:$`,
249+
`^runtime/debug\.Stack\(\)$`,
250+
`^ GOROOT/src/runtime/debug/stack\.go:\d+ \+0x[0-9a-f]+$`,
251+
`^main\.panicAndRecover\.func1\(\)$`,
252+
`^ strip\.go:\d+ \+0x[0-9a-f]+$`,
253+
`^panic\({0x[0-9a-f]+, 0x[0-9a-f]+}\)$`,
254+
`^ GOROOT/src/runtime/panic\.go:\d+ \+0x[0-9a-f]+$`,
255+
`^main\.panicAndRecover\(\)$`,
256+
`^ strip\.go:\d+ \+0x[0-9a-f]+$`,
257+
`^main\.main\(\)$`,
258+
`^ strip\.go:\d+ \+0x[0-9a-f]+$`,
259+
`^$`,
260+
}
261+
262+
func embedWantedStackTraces() string {
263+
buf := &bytes.Buffer{}
264+
fmt.Fprintln(buf, "var wantStackTrace = []string{")
265+
for _, s := range wantStackTrace {
266+
fmt.Fprintf(buf, "`%s`,\n", s)
267+
}
268+
fmt.Fprintln(buf, "}")
269+
return buf.String()
270+
}

0 commit comments

Comments
 (0)