• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2019 The ChromiumOS Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5package main
6
7import (
8	"errors"
9	"fmt"
10	"io"
11	"path/filepath"
12	"strings"
13	"testing"
14)
15
16func TestClangBasename(t *testing.T) {
17	withTestContext(t, func(ctx *testContext) {
18		var tests = []struct {
19			in  string
20			out string
21		}{
22			{"./x86_64-cros-linux-gnu-clang", ".*/clang"},
23			{"./x86_64-cros-linux-gnu-clang++", ".*/clang\\+\\+"},
24		}
25
26		for _, tt := range tests {
27			cmd := ctx.must(callCompiler(ctx, ctx.cfg,
28				ctx.newCommand(tt.in, mainCc)))
29			if err := verifyPath(cmd, tt.out); err != nil {
30				t.Error(err)
31			}
32		}
33	})
34}
35
36func TestClangPathGivenClangEnv(t *testing.T) {
37	withTestContext(t, func(ctx *testContext) {
38		ctx.env = []string{"CLANG=/a/b/clang"}
39		cmd := ctx.must(callCompiler(ctx, ctx.cfg,
40			ctx.newCommand(clangX86_64, mainCc)))
41		if err := verifyPath(cmd, "/a/b/clang"); err != nil {
42			t.Error(err)
43		}
44	})
45}
46
47func TestAbsoluteClangPathBasedOnRootPath(t *testing.T) {
48	withTestContext(t, func(ctx *testContext) {
49		ctx.cfg.clangRootRelPath = "somepath"
50		cmd := ctx.must(callCompiler(ctx, ctx.cfg,
51			ctx.newCommand(filepath.Join(ctx.tempDir, clangX86_64), mainCc)))
52		if err := verifyPath(cmd, filepath.Join(ctx.tempDir, "somepath/usr/bin/clang")); err != nil {
53			t.Error(err)
54		}
55	})
56}
57
58func TestRelativeClangPathBasedOnRootPath(t *testing.T) {
59	withTestContext(t, func(ctx *testContext) {
60		ctx.cfg.clangRootRelPath = "somepath"
61		cmd := ctx.must(callCompiler(ctx, ctx.cfg,
62			ctx.newCommand(clangX86_64, mainCc)))
63		if err := verifyPath(cmd, "somepath/usr/bin/clang"); err != nil {
64			t.Error(err)
65		}
66	})
67}
68
69func TestRelativeClangPathWithDirBasedOnRootPath(t *testing.T) {
70	withTestContext(t, func(ctx *testContext) {
71		ctx.cfg.clangRootRelPath = "somepath"
72		cmd := ctx.must(callCompiler(ctx, ctx.cfg,
73			ctx.newCommand("test/x86_64-cros-linux-gnu-clang", mainCc)))
74		if err := verifyPath(cmd, "test/somepath/usr/bin/clang"); err != nil {
75			t.Error(err)
76		}
77	})
78}
79
80func TestPathEnvClangPathBasedOnRootPath(t *testing.T) {
81	withTestContext(t, func(ctx *testContext) {
82		ctx.cfg.clangRootRelPath = "somepath"
83		ctx.env = []string{"PATH=" + filepath.Join(ctx.tempDir, "/pathenv")}
84		ctx.writeFile(filepath.Join(ctx.tempDir, "/pathenv/x86_64-cros-linux-gnu-clang"), "")
85		cmd := ctx.must(callCompiler(ctx, ctx.cfg,
86			ctx.newCommand("x86_64-cros-linux-gnu-clang", mainCc)))
87		if err := verifyPath(cmd, filepath.Join(ctx.tempDir, "pathenv/somepath/usr/bin/clang")); err != nil {
88			t.Error(err)
89		}
90	})
91}
92
93func TestClangPathForClangHostWrapper(t *testing.T) {
94	withTestContext(t, func(ctx *testContext) {
95		ctx.cfg.isHostWrapper = true
96		ctx.cfg.clangRootRelPath = "somepath"
97		cmd := ctx.must(callCompiler(ctx, ctx.cfg,
98			ctx.newCommand(clangX86_64, mainCc)))
99		if err := verifyPath(cmd, filepath.Join(ctx.tempDir, "clang")); err != nil {
100			t.Error(err)
101		}
102	})
103}
104
105func TestClangPathForAndroidWrapper(t *testing.T) {
106	withTestContext(t, func(ctx *testContext) {
107		ctx.cfg.isAndroidWrapper = true
108		cmd := ctx.must(callCompiler(ctx, ctx.cfg,
109			ctx.newCommand("somedir/clang", mainCc)))
110		if err := verifyPath(cmd, "somedir/clang.real"); err != nil {
111			t.Error(err)
112		}
113	})
114}
115
116func TestClangPathForAndroidWrapperWithSymlinks(t *testing.T) {
117	withTestContext(t, func(ctx *testContext) {
118		ctx.cfg.isAndroidWrapper = true
119		ctx.writeFile("base/come_clang", "")
120		ctx.symlink("base/some_clang", "linked/clang")
121		cmd := ctx.must(callCompiler(ctx, ctx.cfg,
122			ctx.newCommand("linked/clang", mainCc)))
123		if err := verifyPath(cmd, "linked/some_clang.real"); err != nil {
124			t.Error(err)
125		}
126	})
127}
128
129func TestUseXclangPathAndCalcResourceDirByNestedClangCall(t *testing.T) {
130	withTestContext(t, func(ctx *testContext) {
131		ctx.cfg.clangRootRelPath = "somepath"
132		ctx.cmdMock = func(cmd *command, stdin io.Reader, stdout io.Writer, stderr io.Writer) error {
133			if ctx.cmdCount > 1 {
134				return nil
135			}
136			if err := verifyPath(cmd, "somepath/usr/bin/clang"); err != nil {
137				t.Error(err)
138			}
139			if err := verifyArgOrder(cmd, "--print-resource-dir"); err != nil {
140				t.Error(err)
141			}
142			fmt.Fprint(stdout, "someResourcePath\n")
143			return nil
144		}
145		cmd := ctx.must(callCompiler(ctx, ctx.cfg,
146			ctx.newCommand(clangX86_64, "-Xclang-path=somedir", mainCc)))
147		if err := verifyPath(cmd, "somedir/clang"); err != nil {
148			t.Error(err)
149		}
150		if err := verifyArgOrder(cmd, "-resource-dir=someResourcePath",
151			"--gcc-toolchain=/usr", mainCc); err != nil {
152			t.Error(err)
153		}
154	})
155}
156
157func TestXclangPathFailIfNestedClangCallFails(t *testing.T) {
158	withTestContext(t, func(ctx *testContext) {
159		ctx.cmdMock = func(cmd *command, stdin io.Reader, stdout io.Writer, stderr io.Writer) error {
160			fmt.Fprint(stderr, "someclangerror")
161			return errors.New("someerror")
162		}
163		stderr := ctx.mustFail(callCompiler(ctx, ctx.cfg,
164			ctx.newCommand(clangX86_64, "-Xclang-path=somedir", mainCc)))
165		if err := verifyInternalError(stderr); err != nil {
166			t.Fatal(err)
167		}
168		if !strings.Contains(stderr, "clang") {
169			t.Errorf("could not find compiler path on stderr. Got: %s", stderr)
170		}
171		if !strings.Contains(stderr, "someerror") {
172			t.Errorf("could not find original error on stderr. Got: %s", stderr)
173		}
174		if !strings.Contains(stderr, "someclangerror") {
175			t.Errorf("stderr was not forwarded. Got: %s", stderr)
176		}
177	})
178}
179
180func TestConvertGccToClangFlags(t *testing.T) {
181	withTestContext(t, func(ctx *testContext) {
182		var tests = []struct {
183			in  string
184			out string
185		}{
186			{"-Wno-error=maybe-uninitialized", "-Wno-error=uninitialized"},
187			{"-Wno-error=cpp", "-Wno-#warnings"},
188			{"-Xclang-only=-abc=xyz", "-abc=xyz"},
189		}
190
191		for _, tt := range tests {
192			cmd := ctx.must(callCompiler(ctx, ctx.cfg,
193				ctx.newCommand(clangX86_64, tt.in, mainCc)))
194			if err := verifyArgCount(cmd, 0, tt.in); err != nil {
195				t.Error(err)
196			}
197			if err := verifyArgOrder(cmd, tt.out, mainCc); err != nil {
198				t.Error(err)
199			}
200		}
201	})
202}
203
204func TestFilterUnsupportedClangFlags(t *testing.T) {
205	withTestContext(t, func(ctx *testContext) {
206		var tests = []struct {
207			compiler      string
208			flag          string
209			expectedCount int
210		}{
211			{clangX86_64, "-Wstrict-aliasing=xyz", 0},
212			{clangX86_64, "-finline-limit=xyz", 0},
213			{"./armv7a-cros-linux-gnu-clang", "-ftrapv", 0},
214			{"./armv7a-cros-win-gnu-clang", "-ftrapv", 1},
215			{"./armv8a-cros-win-gnu-clang", "-ftrapv", 1},
216			{clangX86_64, "-ftrapv", 1},
217		}
218
219		for _, tt := range tests {
220			cmd := ctx.must(callCompiler(ctx, ctx.cfg,
221				ctx.newCommand(tt.compiler, tt.flag, mainCc)))
222			if err := verifyArgCount(cmd, tt.expectedCount, tt.flag); err != nil {
223				t.Error(err)
224			}
225		}
226	})
227}
228
229func TestClangArchFlags(t *testing.T) {
230	withTestContext(t, func(ctx *testContext) {
231		var tests = []struct {
232			compiler string
233			flags    []string
234		}{
235			{"./i686_64-cros-linux-gnu-clang", []string{mainCc, "-target", "i686_64-cros-linux-gnu"}},
236			{"./x86_64-cros-linux-gnu-clang", []string{mainCc, "-target", "x86_64-cros-linux-gnu"}},
237		}
238		for _, tt := range tests {
239			cmd := ctx.must(callCompiler(ctx, ctx.cfg,
240				ctx.newCommand(tt.compiler, mainCc)))
241			if err := verifyArgOrder(cmd, tt.flags...); err != nil {
242				t.Error(err)
243			}
244		}
245	})
246}
247
248func TestClangLinkerPathProbesBinariesOnPath(t *testing.T) {
249	withTestContext(t, func(ctx *testContext) {
250		linkerPath := filepath.Join(ctx.tempDir, "a/b/c")
251		ctx.writeFile(filepath.Join(linkerPath, "x86_64-cros-linux-gnu-ld.bfd"), "")
252		ctx.env = []string{"PATH=nonExistantPath:" + linkerPath}
253		cmd := ctx.must(callCompiler(ctx, ctx.cfg,
254			ctx.newCommand("./x86_64-cros-linux-gnu-clang", mainCc)))
255		if err := verifyArgOrder(cmd, "-Ba/b/c"); err != nil {
256			t.Error(err)
257		}
258		if err := verifyArgOrder(cmd, "--prefix=a/b/c/x86_64-cros-linux-gnu-"); err != nil {
259			t.Error(err)
260		}
261
262	})
263}
264
265func TestClangLinkerPathEvaluatesSymlinksForBinariesOnPath(t *testing.T) {
266	withTestContext(t, func(ctx *testContext) {
267		realLinkerPath := filepath.Join(ctx.tempDir, "a/original/path/somelinker")
268		ctx.writeFile(realLinkerPath, "")
269		firstLinkLinkerPath := filepath.Join(ctx.tempDir, "a/first/somelinker")
270		ctx.symlink(realLinkerPath, firstLinkLinkerPath)
271		secondLinkLinkerPath := filepath.Join(ctx.tempDir, "a/second/x86_64-cros-linux-gnu-ld.bfd")
272		ctx.symlink(firstLinkLinkerPath, secondLinkLinkerPath)
273
274		ctx.env = []string{"PATH=nonExistantPath:" + filepath.Dir(secondLinkLinkerPath)}
275		cmd := ctx.must(callCompiler(ctx, ctx.cfg,
276			ctx.newCommand("./x86_64-cros-linux-gnu-clang", mainCc)))
277		if err := verifyArgOrder(cmd, "-Ba/first"); err != nil {
278			t.Error(err)
279		}
280		if err := verifyArgOrder(cmd, "--prefix=a/first/x86_64-cros-linux-gnu-"); err != nil {
281			t.Error(err)
282		}
283
284	})
285}
286
287func TestClangFallbackLinkerPathRelativeToRootDir(t *testing.T) {
288	withTestContext(t, func(ctx *testContext) {
289		cmd := ctx.must(callCompiler(ctx, ctx.cfg,
290			ctx.newCommand(clangX86_64, mainCc)))
291		if err := verifyArgOrder(cmd, "-Bbin"); err != nil {
292			t.Error(err)
293		}
294		if err := verifyArgOrder(cmd, "--prefix=bin/x86_64-cros-linux-gnu-"); err != nil {
295			t.Error(err)
296		}
297	})
298}
299
300func TestClangLinkerPathRelativeToRootDir(t *testing.T) {
301	withTestContext(t, func(ctx *testContext) {
302		ctx.cfg.clangRootRelPath = "somepath"
303		cmd := ctx.must(callCompiler(ctx, ctx.cfg,
304			ctx.newCommand(clangX86_64, mainCc)))
305		if err := verifyArgOrder(cmd, "-Bsomepath/bin"); err != nil {
306			t.Error(err)
307		}
308		if err := verifyArgOrder(cmd, "--prefix=somepath/bin/x86_64-cros-linux-gnu-"); err != nil {
309			t.Error(err)
310		}
311	})
312}
313