mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
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).
483 lines
18 KiB
Python
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()
|