Skip to content

Commit 4907ad1

Browse files
committed
cache macOS sysroot discovery
1 parent 5374194 commit 4907ad1

2 files changed

Lines changed: 90 additions & 4 deletions

File tree

internal/crosscompile/crosscompile.go

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"path/filepath"
1010
"runtime"
1111
"strings"
12+
"sync"
1213

1314
"github.com/goplus/llgo/internal/crosscompile/compile"
1415
"github.com/goplus/llgo/internal/env"
@@ -96,14 +97,35 @@ func getCanonicalArchName(triple string) string {
9697
return arch
9798
}
9899

99-
// getMacOSSysroot returns the macOS SDK path using xcrun
100+
var (
101+
macOSSysrootMu sync.Mutex
102+
macOSSysrootCached string
103+
macOSSysrootLookup = func() (string, error) {
104+
cmd := exec.Command("xcrun", "--sdk", "macosx", "--show-sdk-path")
105+
output, err := cmd.Output()
106+
if err != nil {
107+
return "", err
108+
}
109+
return strings.TrimSpace(string(output)), nil
110+
}
111+
)
112+
113+
// getMacOSSysroot returns the macOS SDK path using xcrun.
100114
func getMacOSSysroot() (string, error) {
101-
cmd := exec.Command("xcrun", "--sdk", "macosx", "--show-sdk-path")
102-
output, err := cmd.Output()
115+
macOSSysrootMu.Lock()
116+
defer macOSSysrootMu.Unlock()
117+
if macOSSysrootCached != "" {
118+
return macOSSysrootCached, nil
119+
}
120+
121+
sysroot, err := macOSSysrootLookup()
103122
if err != nil {
104123
return "", err
105124
}
106-
return strings.TrimSpace(string(output)), nil
125+
if sysroot != "" {
126+
macOSSysrootCached = sysroot
127+
}
128+
return sysroot, nil
107129
}
108130

109131
// getESPClangRoot returns the ESP Clang root directory, checking LLGoROOT first,

internal/crosscompile/crosscompile_test.go

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
package crosscompile
55

66
import (
7+
"errors"
78
"os"
89
"path/filepath"
910
"runtime"
@@ -21,6 +22,69 @@ const (
2122
libPrefix = "-L"
2223
)
2324

25+
func resetMacOSSysrootForTest(t *testing.T) {
26+
t.Helper()
27+
macOSSysrootMu.Lock()
28+
oldCached := macOSSysrootCached
29+
oldLookup := macOSSysrootLookup
30+
macOSSysrootCached = ""
31+
macOSSysrootMu.Unlock()
32+
t.Cleanup(func() {
33+
macOSSysrootMu.Lock()
34+
macOSSysrootCached = oldCached
35+
macOSSysrootLookup = oldLookup
36+
macOSSysrootMu.Unlock()
37+
})
38+
}
39+
40+
func TestGetMacOSSysrootCachesSuccess(t *testing.T) {
41+
resetMacOSSysrootForTest(t)
42+
calls := 0
43+
macOSSysrootLookup = func() (string, error) {
44+
calls++
45+
return "/test/sdk", nil
46+
}
47+
first, err := getMacOSSysroot()
48+
if err != nil {
49+
t.Fatalf("first getMacOSSysroot: %v", err)
50+
}
51+
second, err := getMacOSSysroot()
52+
if err != nil {
53+
t.Fatalf("second getMacOSSysroot: %v", err)
54+
}
55+
if first != "/test/sdk" || second != "/test/sdk" {
56+
t.Fatalf("sysroots = %q, %q; want cached /test/sdk", first, second)
57+
}
58+
if calls != 1 {
59+
t.Fatalf("lookup calls = %d, want 1", calls)
60+
}
61+
}
62+
63+
func TestGetMacOSSysrootDoesNotCacheErrors(t *testing.T) {
64+
resetMacOSSysrootForTest(t)
65+
calls := 0
66+
macOSSysrootLookup = func() (string, error) {
67+
calls++
68+
if calls == 1 {
69+
return "", errors.New("temporary xcrun failure")
70+
}
71+
return "/test/sdk", nil
72+
}
73+
if _, err := getMacOSSysroot(); err == nil {
74+
t.Fatal("first getMacOSSysroot succeeded, want error")
75+
}
76+
got, err := getMacOSSysroot()
77+
if err != nil {
78+
t.Fatalf("second getMacOSSysroot: %v", err)
79+
}
80+
if got != "/test/sdk" {
81+
t.Fatalf("sysroot = %q, want /test/sdk", got)
82+
}
83+
if calls != 2 {
84+
t.Fatalf("lookup calls = %d, want retry after error", calls)
85+
}
86+
}
87+
2488
func TestUseCrossCompileSDK(t *testing.T) {
2589
// Skip long-running tests unless explicitly enabled
2690
if testing.Short() {

0 commit comments

Comments
 (0)