Files
swift-mirror/utils/swift_build_support/tests/test_cmake.py
Michael Gottesman f13b8eb10b [cmake] Rather than using CMAKE_{C,CXX}_COMPILER and CMAKE_{C,CXX}_COMPILER_ARG1 for distcc, use CMAKE_{C,CXX}_COMPILER_LAUNCHER.
This is a cleaner, more principled way of adding "compiler launcher" support and
ensures that cmake understands that distcc is not the "actual" compiler.

This ensures that when we compile SwiftRemoteMirrors for the host, we do not try
to compile using distcc without needing to reset CMAKE_{C,CXX}_COMPILER_ARG1
(which is unset when compiling things in the stdlib).
2019-02-05 13:22:53 -08:00

483 lines
18 KiB
Python

# test_cmake.py - Unit tests for swift_build_support.cmake -*- python -*-
#
# This source file is part of the Swift.org open source project
#
# Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
# Licensed under Apache License v2.0 with Runtime Library Exception
#
# See https://swift.org/LICENSE.txt for license information
# See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
import os
import unittest
from argparse import Namespace
from swift_build_support.arguments import CompilerVersion
from swift_build_support.cmake import CMake, CMakeOptions
from swift_build_support.toolchain import host_toolchain
class CMakeTestCase(unittest.TestCase):
def mock_distcc_path(self):
"""Return a path string of mock distcc executable
"""
return os.path.join(os.path.dirname(__file__),
'mock-distcc')
def default_args(self):
"""Return new args object with default values
"""
return Namespace(host_cc="/path/to/clang",
host_cxx="/path/to/clang++",
host_libtool="/path/to/libtool",
enable_asan=False,
enable_ubsan=False,
enable_tsan=False,
enable_lsan=False,
enable_sanitize_coverage=False,
export_compile_commands=False,
distcc=False,
cmake_generator="Ninja",
clang_compiler_version=None,
clang_user_visible_version=None,
build_jobs=8,
build_args=[],
verbose_build=False,
build_ninja=False)
def which_ninja(self, args):
toolchain = host_toolchain()
if toolchain.ninja is not None:
return '/path/to/installed/ninja'
# Maybe we'll build a ninja, maybe we wont.
# Fake it anyway for the tests.
return '/path/to/built/ninja'
def cmake(self, args):
"""Return new CMake object initialized with given args
"""
toolchain = host_toolchain()
toolchain.cc = args.host_cc
toolchain.cxx = args.host_cxx
toolchain.libtool = args.host_libtool
if args.distcc:
toolchain.distcc = self.mock_distcc_path()
toolchain.ninja = self.which_ninja(args)
return CMake(args=args, toolchain=toolchain)
def test_common_options_defaults(self):
args = self.default_args()
cmake = self.cmake(args)
self.assertEqual(
list(cmake.common_options()),
["-G", "Ninja",
"-DCMAKE_C_COMPILER:PATH=/path/to/clang",
"-DCMAKE_CXX_COMPILER:PATH=/path/to/clang++",
"-DCMAKE_LIBTOOL:PATH=/path/to/libtool",
"-DCMAKE_MAKE_PROGRAM=" + self.which_ninja(args)])
def test_common_options_asan(self):
args = self.default_args()
args.enable_asan = True
cmake = self.cmake(args)
self.assertEqual(
list(cmake.common_options()),
["-G", "Ninja",
"-DLLVM_USE_SANITIZER=Address",
"-DCMAKE_C_COMPILER:PATH=/path/to/clang",
"-DCMAKE_CXX_COMPILER:PATH=/path/to/clang++",
"-DCMAKE_LIBTOOL:PATH=/path/to/libtool",
"-DCMAKE_MAKE_PROGRAM=" + self.which_ninja(args)])
def test_common_options_ubsan(self):
args = self.default_args()
args.enable_ubsan = True
cmake = self.cmake(args)
self.assertEqual(
list(cmake.common_options()),
["-G", "Ninja",
"-DLLVM_USE_SANITIZER=Undefined",
"-DCMAKE_C_COMPILER:PATH=/path/to/clang",
"-DCMAKE_CXX_COMPILER:PATH=/path/to/clang++",
"-DCMAKE_LIBTOOL:PATH=/path/to/libtool",
"-DCMAKE_MAKE_PROGRAM=" + self.which_ninja(args)])
def test_common_options_tsan(self):
args = self.default_args()
args.enable_tsan = True
cmake = self.cmake(args)
self.assertEqual(
list(cmake.common_options()),
["-G", "Ninja",
"-DLLVM_USE_SANITIZER=Thread",
"-DCMAKE_C_COMPILER:PATH=/path/to/clang",
"-DCMAKE_CXX_COMPILER:PATH=/path/to/clang++",
"-DCMAKE_LIBTOOL:PATH=/path/to/libtool",
"-DCMAKE_MAKE_PROGRAM=" + self.which_ninja(args)])
def test_common_options_asan_ubsan(self):
args = self.default_args()
args.enable_asan = True
args.enable_ubsan = True
cmake = self.cmake(args)
self.assertEqual(
list(cmake.common_options()),
["-G", "Ninja",
"-DLLVM_USE_SANITIZER=Address;Undefined",
"-DCMAKE_C_COMPILER:PATH=/path/to/clang",
"-DCMAKE_CXX_COMPILER:PATH=/path/to/clang++",
"-DCMAKE_LIBTOOL:PATH=/path/to/libtool",
"-DCMAKE_MAKE_PROGRAM=" + self.which_ninja(args)])
def test_common_options_ubsan_tsan(self):
args = self.default_args()
args.enable_ubsan = True
args.enable_tsan = True
cmake = self.cmake(args)
self.assertEqual(
list(cmake.common_options()),
["-G", "Ninja",
"-DLLVM_USE_SANITIZER=Undefined;Thread",
"-DCMAKE_C_COMPILER:PATH=/path/to/clang",
"-DCMAKE_CXX_COMPILER:PATH=/path/to/clang++",
"-DCMAKE_LIBTOOL:PATH=/path/to/libtool",
"-DCMAKE_MAKE_PROGRAM=" + self.which_ninja(args)])
def test_common_options_asan_ubsan_tsan(self):
args = self.default_args()
args.enable_asan = True
args.enable_ubsan = True
args.enable_tsan = True
cmake = self.cmake(args)
self.assertEqual(
list(cmake.common_options()),
["-G", "Ninja",
"-DLLVM_USE_SANITIZER=Address;Undefined;Thread",
"-DCMAKE_C_COMPILER:PATH=/path/to/clang",
"-DCMAKE_CXX_COMPILER:PATH=/path/to/clang++",
"-DCMAKE_LIBTOOL:PATH=/path/to/libtool",
"-DCMAKE_MAKE_PROGRAM=" + self.which_ninja(args)])
def test_common_options_lsan(self):
args = self.default_args()
args.enable_lsan = True
cmake = self.cmake(args)
self.assertEqual(
list(cmake.common_options()),
["-G", "Ninja",
"-DLLVM_USE_SANITIZER=Leaks",
"-DCMAKE_C_COMPILER:PATH=/path/to/clang",
"-DCMAKE_CXX_COMPILER:PATH=/path/to/clang++",
"-DCMAKE_LIBTOOL:PATH=/path/to/libtool",
"-DCMAKE_MAKE_PROGRAM=" + self.which_ninja(args)])
def test_common_options_coverage_sanitizer(self):
args = self.default_args()
args.enable_sanitize_coverage = True
cmake = self.cmake(args)
self.assertEqual(
list(cmake.common_options()),
["-G", "Ninja",
"-DLLVM_USE_SANITIZE_COVERAGE=ON",
"-DCMAKE_C_COMPILER:PATH=/path/to/clang",
"-DCMAKE_CXX_COMPILER:PATH=/path/to/clang++",
"-DCMAKE_LIBTOOL:PATH=/path/to/libtool",
"-DCMAKE_MAKE_PROGRAM=" + self.which_ninja(args)])
def test_common_options_export_compile_commands(self):
args = self.default_args()
args.export_compile_commands = True
cmake = self.cmake(args)
self.assertEqual(
list(cmake.common_options()),
["-G", "Ninja",
"-DCMAKE_EXPORT_COMPILE_COMMANDS=ON",
"-DCMAKE_C_COMPILER:PATH=/path/to/clang",
"-DCMAKE_CXX_COMPILER:PATH=/path/to/clang++",
"-DCMAKE_LIBTOOL:PATH=/path/to/libtool",
"-DCMAKE_MAKE_PROGRAM=" + self.which_ninja(args)])
def test_common_options_distcc(self):
args = self.default_args()
args.distcc = True
cmake = self.cmake(args)
self.assertEqual(
list(cmake.common_options()),
["-G", "Ninja",
"-DCMAKE_C_COMPILER_LAUNCHER:PATH=" + self.mock_distcc_path(),
"-DCMAKE_CXX_COMPILER_LAUNCHER:PATH=" + self.mock_distcc_path(),
"-DCMAKE_C_COMPILER:PATH=/path/to/clang",
"-DCMAKE_CXX_COMPILER:PATH=/path/to/clang++",
"-DCMAKE_LIBTOOL:PATH=/path/to/libtool",
"-DCMAKE_MAKE_PROGRAM=" + self.which_ninja(args)])
def test_common_options_xcode(self):
args = self.default_args()
args.cmake_generator = 'Xcode'
cmake = self.cmake(args)
self.assertEqual(
list(cmake.common_options()),
["-G", "Xcode",
"-DCMAKE_C_COMPILER:PATH=/path/to/clang",
"-DCMAKE_CXX_COMPILER:PATH=/path/to/clang++",
"-DCMAKE_LIBTOOL:PATH=/path/to/libtool",
"-DCMAKE_CONFIGURATION_TYPES=" +
"Debug;Release;MinSizeRel;RelWithDebInfo"])
def test_common_options_clang_compiler_version(self):
args = self.default_args()
args.clang_compiler_version = CompilerVersion(
string_representation="999.0.999",
components=("999", "0", "999", None))
cmake = self.cmake(args)
self.assertEqual(
list(cmake.common_options()),
["-G", "Ninja",
"-DCMAKE_C_COMPILER:PATH=/path/to/clang",
"-DCMAKE_CXX_COMPILER:PATH=/path/to/clang++",
"-DCMAKE_LIBTOOL:PATH=/path/to/libtool",
"-DCMAKE_MAKE_PROGRAM=" + self.which_ninja(args)])
def test_common_options_clang_user_visible_version(self):
args = self.default_args()
args.clang_user_visible_version = CompilerVersion(
string_representation="9.0.0",
components=("9", "0", "0", None))
cmake = self.cmake(args)
self.assertEqual(
list(cmake.common_options()),
["-G", "Ninja",
"-DCMAKE_C_COMPILER:PATH=/path/to/clang",
"-DCMAKE_CXX_COMPILER:PATH=/path/to/clang++",
"-DCMAKE_LIBTOOL:PATH=/path/to/libtool",
"-DLLVM_VERSION_MAJOR:STRING=9",
"-DLLVM_VERSION_MINOR:STRING=0",
"-DLLVM_VERSION_PATCH:STRING=0",
"-DCLANG_VERSION_MAJOR:STRING=9",
"-DCLANG_VERSION_MINOR:STRING=0",
"-DCLANG_VERSION_PATCH:STRING=0",
"-DCMAKE_MAKE_PROGRAM=" + self.which_ninja(args)])
def test_common_options_build_ninja(self):
args = self.default_args()
args.build_ninja = True
cmake = self.cmake(args)
self.assertEqual(
list(cmake.common_options()),
["-G", "Ninja",
"-DCMAKE_C_COMPILER:PATH=/path/to/clang",
"-DCMAKE_CXX_COMPILER:PATH=/path/to/clang++",
"-DCMAKE_LIBTOOL:PATH=/path/to/libtool",
"-DCMAKE_MAKE_PROGRAM=" + self.which_ninja(args)])
def test_common_options_full(self):
args = self.default_args()
args.enable_asan = True
args.enable_ubsan = True
args.export_compile_commands = True
args.distcc = True
args.cmake_generator = 'Xcode'
args.clang_user_visible_version = CompilerVersion(
string_representation="9.0.0",
components=("9", "0", "0", None))
args.clang_compiler_version = CompilerVersion(
string_representation="999.0.900",
components=("999", "0", "900", None))
args.build_ninja = True
cmake = self.cmake(args)
self.assertEqual(
list(cmake.common_options()),
["-G", "Xcode",
"-DLLVM_USE_SANITIZER=Address;Undefined",
"-DCMAKE_EXPORT_COMPILE_COMMANDS=ON",
"-DCMAKE_C_COMPILER_LAUNCHER:PATH=" + self.mock_distcc_path(),
"-DCMAKE_CXX_COMPILER_LAUNCHER:PATH=" + self.mock_distcc_path(),
"-DCMAKE_C_COMPILER:PATH=/path/to/clang",
"-DCMAKE_CXX_COMPILER:PATH=/path/to/clang++",
"-DCMAKE_LIBTOOL:PATH=/path/to/libtool",
"-DCMAKE_CONFIGURATION_TYPES=" +
"Debug;Release;MinSizeRel;RelWithDebInfo",
"-DLLVM_VERSION_MAJOR:STRING=9",
"-DLLVM_VERSION_MINOR:STRING=0",
"-DLLVM_VERSION_PATCH:STRING=0",
"-DCLANG_VERSION_MAJOR:STRING=9",
"-DCLANG_VERSION_MINOR:STRING=0",
"-DCLANG_VERSION_PATCH:STRING=0"])
# NOTE: No "-DCMAKE_MAKE_PROGRAM=/path/to/built/ninja" because
# cmake_generator is 'Xcode'
def test_build_args_ninja(self):
args = self.default_args()
cmake = self.cmake(args)
self.assertEqual(
list(cmake.build_args()),
["-j8"])
args.verbose_build = True
cmake = self.cmake(args)
self.assertEqual(
list(cmake.build_args()),
["-j8", "-v"])
def test_build_args_makefile(self):
args = self.default_args()
args.cmake_generator = "Unix Makefiles"
cmake = self.cmake(args)
self.assertEqual(
list(cmake.build_args()),
["-j8"])
args.verbose_build = True
cmake = self.cmake(args)
self.assertEqual(
list(cmake.build_args()),
["-j8", "VERBOSE=1"])
def test_build_args_xcode(self):
args = self.default_args()
args.cmake_generator = "Xcode"
cmake = self.cmake(args)
self.assertEqual(
list(cmake.build_args()),
["-parallelizeTargets", "-jobs", "8"])
# NOTE: Xcode generator DOES NOT take 'verbose-build' into account.
args.verbose_build = True
cmake = self.cmake(args)
self.assertEqual(
list(cmake.build_args()),
["-parallelizeTargets", "-jobs", "8"])
def test_build_args_eclipse_ninja(self):
# NOTE: Eclipse generator DOES NOT take 'build-jobs' into account,
# nor 'verbose-build'.
args = self.default_args()
args.cmake_generator = "Eclipse CDT4 - Ninja"
args.verbose_build = True
cmake = self.cmake(args)
self.assertEqual(
list(cmake.build_args()), [])
def test_build_args_custom_build_args(self):
args = self.default_args()
args.build_args = ["-foo", "bar baz"]
cmake = self.cmake(args)
self.assertEqual(
list(cmake.build_args()),
["-foo", "bar baz", "-j8"])
def test_build_args_distcc(self):
args = self.default_args()
args.distcc = True
cmake = self.cmake(args)
self.assertEqual(
list(cmake.build_args()),
["-j6"])
class CMakeOptionsTestCase(unittest.TestCase):
def test_define(self):
options = CMakeOptions()
options.define('OPT1:STRING', 'foo')
options.define('OPT2:BOOL', True)
options.define('OPT3:BOOL', 1)
options.define('OPT4:BOOL', 'True')
options.define('OPT5:BOOL', 'true')
options.define('OPT6:BOOL', 'YES')
options.define('OPT7:BOOL', '1')
options.define('OPT8:BOOL', False)
options.define('OPT9:BOOL', 0)
options.define('OPT10:BOOL', 'false')
options.define('OPT11:BOOL', 'False')
options.define('OPT12:BOOL', 'No')
options.define('OPT13:BOOL', '0')
options.define('OPT14', 12)
options.define('OPT15', '')
options.define('OPT16', None)
options.define('OPT17:PATH', 'foo')
self.assertRaises(ValueError, options.define, 'ERR', ["FOO"])
self.assertRaises(ValueError, options.define, 'ERR', {"FOO": 1})
self.assertRaises(ValueError, options.define, 'ERR:BOOL', None)
self.assertRaises(ValueError, options.define, 'ERR:BOOL', 3)
self.assertRaises(ValueError, options.define, 'ERR:BOOL', 'foo')
self.assertRaises(ValueError, options.define, 'ERR:BOOL', [1])
self.assertEqual(list(options), [
'-DOPT1:STRING=foo',
'-DOPT2:BOOL=TRUE',
'-DOPT3:BOOL=TRUE',
'-DOPT4:BOOL=TRUE',
'-DOPT5:BOOL=TRUE',
'-DOPT6:BOOL=TRUE',
'-DOPT7:BOOL=TRUE',
'-DOPT8:BOOL=FALSE',
'-DOPT9:BOOL=FALSE',
'-DOPT10:BOOL=FALSE',
'-DOPT11:BOOL=FALSE',
'-DOPT12:BOOL=FALSE',
'-DOPT13:BOOL=FALSE',
'-DOPT14=12',
'-DOPT15=',
'-DOPT16=',
'-DOPT17:PATH=foo'])
def test_operations(self):
options1 = CMakeOptions()
options1.define("OPT1_1", 'VAL1')
options1.define("OPT1_2", 'VAL2')
options2 = CMakeOptions()
options2.define("OPT2_1", 'VAL3')
options = options1 + options2
self.assertIsInstance(options, CMakeOptions)
self.assertEqual(list(options), [
"-DOPT1_1=VAL1",
"-DOPT1_2=VAL2",
"-DOPT2_1=VAL3"])
options_added = options + ["-CUSTOM", "12"]
self.assertIsInstance(options_added, CMakeOptions)
self.assertEqual(list(options_added), [
"-DOPT1_1=VAL1",
"-DOPT1_2=VAL2",
"-DOPT2_1=VAL3",
"-CUSTOM", "12"])
options += options2
self.assertIsInstance(options, CMakeOptions)
self.assertEqual(list(options), [
"-DOPT1_1=VAL1",
"-DOPT1_2=VAL2",
"-DOPT2_1=VAL3",
"-DOPT2_1=VAL3"])
options += ["-G", "Ninja"]
self.assertIsInstance(options, CMakeOptions)
self.assertEqual(list(options), [
"-DOPT1_1=VAL1",
"-DOPT1_2=VAL2",
"-DOPT2_1=VAL3",
"-DOPT2_1=VAL3",
"-G", "Ninja"])
list_options = ["-G", "Ninja"]
list_options += options1
self.assertIsInstance(list_options, list)
self.assertEqual(list_options, [
"-G", "Ninja",
"-DOPT1_1=VAL1",
"-DOPT1_2=VAL2"])
if __name__ == '__main__':
unittest.main()