You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
303 lines
9.1 KiB
303 lines
9.1 KiB
// Copyright 2019 The Chromium OS Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
package main
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestClangBasename(t *testing.T) {
|
|
withTestContext(t, func(ctx *testContext) {
|
|
var tests = []struct {
|
|
in string
|
|
out string
|
|
}{
|
|
{"./x86_64-cros-linux-gnu-clang", ".*/clang"},
|
|
{"./x86_64-cros-linux-gnu-clang++", ".*/clang\\+\\+"},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
cmd := ctx.must(callCompiler(ctx, ctx.cfg,
|
|
ctx.newCommand(tt.in, mainCc)))
|
|
if err := verifyPath(cmd, tt.out); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestClangPathGivenClangEnv(t *testing.T) {
|
|
withTestContext(t, func(ctx *testContext) {
|
|
ctx.env = []string{"CLANG=/a/b/clang"}
|
|
cmd := ctx.must(callCompiler(ctx, ctx.cfg,
|
|
ctx.newCommand(clangX86_64, mainCc)))
|
|
if err := verifyPath(cmd, "/a/b/clang"); err != nil {
|
|
t.Error(err)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestAbsoluteClangPathBasedOnRootPath(t *testing.T) {
|
|
withTestContext(t, func(ctx *testContext) {
|
|
ctx.cfg.rootRelPath = "somepath"
|
|
cmd := ctx.must(callCompiler(ctx, ctx.cfg,
|
|
ctx.newCommand(filepath.Join(ctx.tempDir, clangX86_64), mainCc)))
|
|
if err := verifyPath(cmd, filepath.Join(ctx.tempDir, "somepath/usr/bin/clang")); err != nil {
|
|
t.Error(err)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestRelativeClangPathBasedOnRootPath(t *testing.T) {
|
|
withTestContext(t, func(ctx *testContext) {
|
|
ctx.cfg.rootRelPath = "somepath"
|
|
cmd := ctx.must(callCompiler(ctx, ctx.cfg,
|
|
ctx.newCommand(clangX86_64, mainCc)))
|
|
if err := verifyPath(cmd, "somepath/usr/bin/clang"); err != nil {
|
|
t.Error(err)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestRelativeClangPathWithDirBasedOnRootPath(t *testing.T) {
|
|
withTestContext(t, func(ctx *testContext) {
|
|
ctx.cfg.rootRelPath = "somepath"
|
|
cmd := ctx.must(callCompiler(ctx, ctx.cfg,
|
|
ctx.newCommand("test/x86_64-cros-linux-gnu-clang", mainCc)))
|
|
if err := verifyPath(cmd, "test/somepath/usr/bin/clang"); err != nil {
|
|
t.Error(err)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestPathEnvClangPathBasedOnRootPath(t *testing.T) {
|
|
withTestContext(t, func(ctx *testContext) {
|
|
ctx.cfg.rootRelPath = "somepath"
|
|
ctx.env = []string{"PATH=" + filepath.Join(ctx.tempDir, "/pathenv")}
|
|
ctx.writeFile(filepath.Join(ctx.tempDir, "/pathenv/x86_64-cros-linux-gnu-clang"), "")
|
|
cmd := ctx.must(callCompiler(ctx, ctx.cfg,
|
|
ctx.newCommand("x86_64-cros-linux-gnu-clang", mainCc)))
|
|
if err := verifyPath(cmd, filepath.Join(ctx.tempDir, "pathenv/somepath/usr/bin/clang")); err != nil {
|
|
t.Error(err)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestClangPathForClangHostWrapper(t *testing.T) {
|
|
withTestContext(t, func(ctx *testContext) {
|
|
ctx.cfg.isHostWrapper = true
|
|
ctx.cfg.rootRelPath = "somepath"
|
|
cmd := ctx.must(callCompiler(ctx, ctx.cfg,
|
|
ctx.newCommand(clangX86_64, mainCc)))
|
|
if err := verifyPath(cmd, filepath.Join(ctx.tempDir, "clang")); err != nil {
|
|
t.Error(err)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestClangPathForAndroidWrapper(t *testing.T) {
|
|
withTestContext(t, func(ctx *testContext) {
|
|
ctx.cfg.isAndroidWrapper = true
|
|
cmd := ctx.must(callCompiler(ctx, ctx.cfg,
|
|
ctx.newCommand("somedir/clang", mainCc)))
|
|
if err := verifyPath(cmd, "somedir/clang.real"); err != nil {
|
|
t.Error(err)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestClangPathForAndroidWrapperWithSymlinks(t *testing.T) {
|
|
withTestContext(t, func(ctx *testContext) {
|
|
ctx.cfg.isAndroidWrapper = true
|
|
ctx.writeFile("base/come_clang", "")
|
|
ctx.symlink("base/some_clang", "linked/clang")
|
|
cmd := ctx.must(callCompiler(ctx, ctx.cfg,
|
|
ctx.newCommand("linked/clang", mainCc)))
|
|
if err := verifyPath(cmd, "linked/some_clang.real"); err != nil {
|
|
t.Error(err)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestUseXclangPathAndCalcResourceDirByNestedClangCall(t *testing.T) {
|
|
withTestContext(t, func(ctx *testContext) {
|
|
ctx.cfg.rootRelPath = "somepath"
|
|
ctx.cmdMock = func(cmd *command, stdin io.Reader, stdout io.Writer, stderr io.Writer) error {
|
|
if ctx.cmdCount > 1 {
|
|
return nil
|
|
}
|
|
if err := verifyPath(cmd, "somepath/usr/bin/clang"); err != nil {
|
|
t.Error(err)
|
|
}
|
|
if err := verifyArgOrder(cmd, "--print-resource-dir"); err != nil {
|
|
t.Error(err)
|
|
}
|
|
fmt.Fprint(stdout, "someResourcePath\n")
|
|
return nil
|
|
}
|
|
cmd := ctx.must(callCompiler(ctx, ctx.cfg,
|
|
ctx.newCommand(clangX86_64, "-Xclang-path=somedir", mainCc)))
|
|
if err := verifyPath(cmd, "somedir/clang"); err != nil {
|
|
t.Error(err)
|
|
}
|
|
if err := verifyArgOrder(cmd, "-resource-dir=someResourcePath",
|
|
"--gcc-toolchain=/usr", mainCc); err != nil {
|
|
t.Error(err)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestXclangPathFailIfNestedClangCallFails(t *testing.T) {
|
|
withTestContext(t, func(ctx *testContext) {
|
|
ctx.cmdMock = func(cmd *command, stdin io.Reader, stdout io.Writer, stderr io.Writer) error {
|
|
fmt.Fprint(stderr, "someclangerror")
|
|
return errors.New("someerror")
|
|
}
|
|
stderr := ctx.mustFail(callCompiler(ctx, ctx.cfg,
|
|
ctx.newCommand(clangX86_64, "-Xclang-path=somedir", mainCc)))
|
|
if err := verifyInternalError(stderr); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !strings.Contains(stderr, "clang") {
|
|
t.Errorf("could not find compiler path on stderr. Got: %s", stderr)
|
|
}
|
|
if !strings.Contains(stderr, "someerror") {
|
|
t.Errorf("could not find original error on stderr. Got: %s", stderr)
|
|
}
|
|
if !strings.Contains(stderr, "someclangerror") {
|
|
t.Errorf("stderr was not forwarded. Got: %s", stderr)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestConvertGccToClangFlags(t *testing.T) {
|
|
withTestContext(t, func(ctx *testContext) {
|
|
var tests = []struct {
|
|
in string
|
|
out string
|
|
}{
|
|
{"-Wno-error=unused-but-set-variable", "-Wno-error=unused-variable"},
|
|
{"-Wno-error=maybe-uninitialized", "-Wno-error=uninitialized"},
|
|
{"-Wno-unused-but-set-variable", "-Wno-unused-variable"},
|
|
{"-Wunused-but-set-variable", "-Wunused-variable"},
|
|
{"-Wno-error=cpp", "-Wno-#warnings"},
|
|
{"-Xclang-only=-abc=xyz", "-abc=xyz"},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
cmd := ctx.must(callCompiler(ctx, ctx.cfg,
|
|
ctx.newCommand(clangX86_64, tt.in, mainCc)))
|
|
if err := verifyArgCount(cmd, 0, tt.in); err != nil {
|
|
t.Error(err)
|
|
}
|
|
if err := verifyArgOrder(cmd, tt.out, mainCc); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestFilterUnsupportedClangFlags(t *testing.T) {
|
|
withTestContext(t, func(ctx *testContext) {
|
|
var tests = []struct {
|
|
compiler string
|
|
flag string
|
|
expectedCount int
|
|
}{
|
|
{clangX86_64, "-pass-exit-codes", 0},
|
|
{clangX86_64, "-Wstrict-aliasing=xyz", 0},
|
|
{clangX86_64, "-finline-limit=xyz", 0},
|
|
{"./armv7a-cros-linux-gnu-clang", "-ftrapv", 0},
|
|
{"./armv7a-cros-win-gnu-clang", "-ftrapv", 1},
|
|
{"./armv8a-cros-win-gnu-clang", "-ftrapv", 1},
|
|
{clangX86_64, "-ftrapv", 1},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
cmd := ctx.must(callCompiler(ctx, ctx.cfg,
|
|
ctx.newCommand(tt.compiler, tt.flag, mainCc)))
|
|
if err := verifyArgCount(cmd, tt.expectedCount, tt.flag); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestClangArchFlags(t *testing.T) {
|
|
withTestContext(t, func(ctx *testContext) {
|
|
var tests = []struct {
|
|
compiler string
|
|
flags []string
|
|
}{
|
|
{"./i686_64-cros-linux-gnu-clang", []string{mainCc, "-m32", "-Xclang", "-target-feature", "-Xclang", "-movbe"}},
|
|
{"./x86_64-cros-linux-gnu-clang", []string{mainCc, "-target", "x86_64-cros-linux-gnu"}},
|
|
}
|
|
for _, tt := range tests {
|
|
cmd := ctx.must(callCompiler(ctx, ctx.cfg,
|
|
ctx.newCommand(tt.compiler, mainCc)))
|
|
if err := verifyArgOrder(cmd, tt.flags...); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestClangLinkerPathProbesBinariesOnPath(t *testing.T) {
|
|
withTestContext(t, func(ctx *testContext) {
|
|
linkerPath := filepath.Join(ctx.tempDir, "a/b/c")
|
|
ctx.writeFile(filepath.Join(linkerPath, "x86_64-cros-linux-gnu-ld"), "")
|
|
ctx.env = []string{"PATH=nonExistantPath:" + linkerPath}
|
|
cmd := ctx.must(callCompiler(ctx, ctx.cfg,
|
|
ctx.newCommand("./x86_64-cros-linux-gnu-clang", mainCc)))
|
|
if err := verifyArgOrder(cmd, "-Ba/b/c"); err != nil {
|
|
t.Error(err)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestClangLinkerPathEvaluatesSymlinksForBinariesOnPath(t *testing.T) {
|
|
withTestContext(t, func(ctx *testContext) {
|
|
realLinkerPath := filepath.Join(ctx.tempDir, "a/original/path/somelinker")
|
|
ctx.writeFile(realLinkerPath, "")
|
|
firstLinkLinkerPath := filepath.Join(ctx.tempDir, "a/first/somelinker")
|
|
ctx.symlink(realLinkerPath, firstLinkLinkerPath)
|
|
secondLinkLinkerPath := filepath.Join(ctx.tempDir, "a/second/x86_64-cros-linux-gnu-ld")
|
|
ctx.symlink(firstLinkLinkerPath, secondLinkLinkerPath)
|
|
|
|
ctx.env = []string{"PATH=nonExistantPath:" + filepath.Dir(secondLinkLinkerPath)}
|
|
cmd := ctx.must(callCompiler(ctx, ctx.cfg,
|
|
ctx.newCommand("./x86_64-cros-linux-gnu-clang", mainCc)))
|
|
if err := verifyArgOrder(cmd, "-Ba/first"); err != nil {
|
|
t.Error(err)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestClangFallbackLinkerPathRelativeToRootDir(t *testing.T) {
|
|
withTestContext(t, func(ctx *testContext) {
|
|
cmd := ctx.must(callCompiler(ctx, ctx.cfg,
|
|
ctx.newCommand(clangX86_64, mainCc)))
|
|
if err := verifyArgOrder(cmd, "-Bbin"); err != nil {
|
|
t.Error(err)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestClangLinkerPathRelativeToRootDir(t *testing.T) {
|
|
withTestContext(t, func(ctx *testContext) {
|
|
ctx.cfg.rootRelPath = "somepath"
|
|
cmd := ctx.must(callCompiler(ctx, ctx.cfg,
|
|
ctx.newCommand(clangX86_64, mainCc)))
|
|
if err := verifyArgOrder(cmd, "-Bsomepath/bin"); err != nil {
|
|
t.Error(err)
|
|
}
|
|
})
|
|
}
|