From 8e73dba9a986f75cda68d50995c3523041f007eb Mon Sep 17 00:00:00 2001 From: Simon Dassow Date: Sun, 11 Oct 2026 00:44:32 +0200 Subject: [PATCH] Change compiler version lookup approach to prevent duplicating flags --- cmd/fyne/internal/commands/build.go | 7 +- cmd/fyne/internal/commands/hardening_flags.go | 84 ++++++++++++++++++- .../internal/commands/hardening_flags_test.go | 28 +++++++ 3 files changed, 114 insertions(+), 5 deletions(-) diff --git a/cmd/fyne/internal/commands/build.go b/cmd/fyne/internal/commands/build.go index a4d7fe19..41a08342 100644 --- a/cmd/fyne/internal/commands/build.go +++ b/cmd/fyne/internal/commands/build.go @@ -362,7 +362,12 @@ func (b *Builder) applyCAndLDFlags(env *[]string, os string) { } arch := targetArch() - cflagsHardening := hardeningCFlagsLookup(ccVersion(), os, arch) + ccVer, err := ccVersionAndDefaultFlags() + if err != nil { + fyne.LogError("failed to get compiler version and default flags", err) + ccVer = ccVersion() + } + cflagsHardening := hardeningCFlagsLookup(ccVer, os, arch) if cflagsHardening != "" { cflags = append(cflags, cflagsHardening) } diff --git a/cmd/fyne/internal/commands/hardening_flags.go b/cmd/fyne/internal/commands/hardening_flags.go index 9ae015b7..9f45049d 100644 --- a/cmd/fyne/internal/commands/hardening_flags.go +++ b/cmd/fyne/internal/commands/hardening_flags.go @@ -3,6 +3,8 @@ package commands import ( "os" "os/exec" + "regexp" + "strings" "golang.org/x/mod/semver" @@ -28,12 +30,16 @@ var hardeningFlagsTable = []hardeningFlags{ //revive:enable:add-constant } -func ccVersion() string { +func ccProg() string { cc, ok := os.LookupEnv("CC") if !ok { - cc = "cc" + return "cc" } + return cc +} +func ccVersion() string { + cc := ccProg() cmd := exec.Command(cc, "--version") out, err := cmd.CombinedOutput() if err != nil { @@ -43,11 +49,60 @@ func ccVersion() string { return string(out) } +const ccTestFlagsCode = ` +int main(int argc, char **argv) { + return 0; +} +` + +func ccVersionAndDefaultFlags() (string, error) { + f, err := os.CreateTemp("", "fyne-check-cc-*.c") + if err != nil { + return "", err + } + inFile := f.Name() + outFile := strings.TrimSuffix(inFile, ".c") + defer func() { + _ = os.Remove(inFile) + _ = os.Remove(outFile) + }() + + if _, err := f.WriteString(ccTestFlagsCode); err != nil { + return "", err + } + if err := f.Close(); err != nil { + return "", err + } + + cmd := exec.Command(ccProg(), "-Q", "-v", "-o", outFile, inFile) + out, err := cmd.CombinedOutput() + if err != nil { + return "", err + } + + return string(out), nil +} + +func gccDefaultFlags(s string) []string { + re := regexp.MustCompile(`(?ms)^options enabled:((?:\s+\S+\n?)*)`) + m := re.FindStringSubmatch(s) + if len(m) < 2 { + return nil + } + return strings.Fields(m[1]) +} + func hardeningCFlagsLookup(out, goos, arch string) string { info, err := util.DetectCompiler(out, goos) if err != nil { return "" } + + var defs []string + if info.Name == "gcc" { + defs = gccDefaultFlags(out) + } + for _, e := range hardeningFlagsTable { //revive:disable:add-constant if e.cc != "*" && e.cc != info.Name { @@ -65,8 +120,29 @@ func hardeningCFlagsLookup(out, goos, arch string) string { if e.maxVer != "*" && semver.Compare("v"+info.Version, "v"+e.maxVer) > 0 { continue } - return e.cflags + return dedupeFlags(e.cflags, defs) //revive:enable:add-constant } - return hardeningCFLAGS + return dedupeFlags(hardeningCFLAGS, defs) +} + +func dedupeFlags(s string, defs []string) string { + if len(defs) == 0 { + return s + } + + seen := make(map[string]struct{}) + for _, flag := range defs { + seen[flag] = struct{}{} + } + + r := []string{} + for _, flag := range strings.Fields(s) { + if _, found := seen[flag]; found { + continue + } + seen[flag] = struct{}{} + r = append(r, flag) + } + return util.JoinSpace(r) } diff --git a/cmd/fyne/internal/commands/hardening_flags_test.go b/cmd/fyne/internal/commands/hardening_flags_test.go index 45bc8812..f5f9b12f 100644 --- a/cmd/fyne/internal/commands/hardening_flags_test.go +++ b/cmd/fyne/internal/commands/hardening_flags_test.go @@ -34,3 +34,31 @@ func Test_hardeningCFlagsLookup(t *testing.T) { // darwin/arm64 doesn't do -fcf-protection assert.Equal(t, "-D_FORTIFY_SOURCE=3 -fstack-protector-strong", hardeningCFlagsLookup("Apple clang version 17.0.0 (clang-1700.0.13.5)", "darwin", "arm64")) } + +func Test_gccDefaultFlags(t *testing.T) { + in := ` +GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072 +options passed: -v -auxbase +options enabled: -falign-loops -fargument-alias + -fasynchronous-unwind-tables -fbranch-count-reg -fcommon -fearly-inlining + -feliminate-unused-debug-types -femit-class-debug-always -ffunction-cse + -fgcse-lm -finline-functions-called-once -fivopts -fkeep-static-consts + -fleading-underscore -fmath-errno -fmove-loop-invariants -fpeephole -fpic + -fpie -freg-struct-return -fsched-interblock -fsched-spec + -fsched-stalled-insns-dep -fshow-column -fsplit-ivs-in-unroller + -ftoplevel-reorder -ftrapping-math -ftree-loop-im -ftree-loop-ivcanon + -ftree-loop-optimize -ftree-vect-loop-version -funwind-tables + -fvar-tracking -m128bit-long-double -m64 -m80387 + -maccumulate-outgoing-args -malign-stringops -mfancy-math-387 + -mfp-ret-in-387 -mieee-fp -mmmx -mpush-args -mred-zone -msse -msse2 +Compiler executable checksum: 1e242b9c9b970b8bb2f3765bba204637 +` + x := gccDefaultFlags(in) + assert.NotNil(t, x) +} + +func Test_ccVersionAndDefaultFlags(t *testing.T) { + s, err := ccVersionAndDefaultFlags() + assert.NoError(t, err) + assert.NotEmpty(t, s) +}