blob: 7abbbb16fa03f1351015bc51f204ffe61e049ce6 [file] [log] [blame]
// 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.clangRootRelPath = "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.clangRootRelPath = "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.clangRootRelPath = "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.clangRootRelPath = "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.clangRootRelPath = "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.clangRootRelPath = "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, "-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, "-target", "i686_64-cros-linux-gnu"}},
{"./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)
}
if err := verifyArgOrder(cmd, "--prefix=a/b/c/x86_64-cros-linux-gnu-"); 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)
}
if err := verifyArgOrder(cmd, "--prefix=a/first/x86_64-cros-linux-gnu-"); 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)
}
if err := verifyArgOrder(cmd, "--prefix=bin/x86_64-cros-linux-gnu-"); err != nil {
t.Error(err)
}
})
}
func TestClangLinkerPathRelativeToRootDir(t *testing.T) {
withTestContext(t, func(ctx *testContext) {
ctx.cfg.clangRootRelPath = "somepath"
cmd := ctx.must(callCompiler(ctx, ctx.cfg,
ctx.newCommand(clangX86_64, mainCc)))
if err := verifyArgOrder(cmd, "-Bsomepath/bin"); err != nil {
t.Error(err)
}
if err := verifyArgOrder(cmd, "--prefix=somepath/bin/x86_64-cros-linux-gnu-"); err != nil {
t.Error(err)
}
})
}