Files
swift-mirror/utils/swift_build_support/tests/test_cmake.py
Daniel Rodríguez Troitiño 6bf0826524 [build-script] Improvements to CMakeOptions.
CMakeOptions was briefly used in the cmake module, but mostly unused in
the rest of the modules, however, several products were dealing with
what eventually will end as CMake options, but not using the already
existing code, and duplicating it.

The changes tries to unify all usage around CMakeOptions which avoids
code duplication. Additionally, it provides some more API surface in
CMakeOptions to make it more useful.

- The initializer can be passed a list of tuples or another CMakeOptions
  to copy into the newly created options.
- Boolean Python values are treated automatically as boolean CMake
  options and transformed into `TRUE` and `FALSE` automatically.
- Provides `extend`, which will add all the tuples from a list or all
  the options from another `CMakeOptions` into the receiving
  `CMakeOptions`.
- Provides `__contains__`, which makes checking for existing options a
  little easier (however, being `CMakeOptions` basically a list, the
  checking has to include also the value, which is not that helpful).
- Modify LLVM and Swift products to use `CMakeOptions`. It makes the
  boolean values clearer and avoid a lot of repetitive string
  formatting.
- Modify the tests to make them pass and provide new test for newly
  introduced features.
2019-05-14 13:25:58 -07:00

543 lines
20 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",
cmake_c_launcher=None,
cmake_cxx_launcher=None,
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_launcher(self):
args = self.default_args()
cmake_c_launcher = "/path/to/c_launcher"
cmake_cxx_launcher = "/path/to/cxx_launcher"
args.cmake_c_launcher = cmake_c_launcher
args.cmake_cxx_launcher = cmake_cxx_launcher
cmake = self.cmake(args)
self.assertEqual(
list(cmake.common_options()),
["-G", "Ninja",
"-DCMAKE_C_COMPILER_LAUNCHER:PATH=" + cmake_c_launcher,
"-DCMAKE_CXX_COMPILER_LAUNCHER:PATH=" + cmake_cxx_launcher,
"-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"])
def test_initial_options_with_tuples(self):
options = CMakeOptions([('FOO', 'foo'), ('BAR', True)])
self.assertIn('-DFOO=foo', options)
self.assertIn('-DBAR=TRUE', options)
def test_initial_options_with_other_options(self):
options = CMakeOptions()
options.define('FOO', 'foo')
options.define('BAR', True)
derived = CMakeOptions(options)
self.assertIn('-DFOO=foo', derived)
self.assertIn('-DBAR=TRUE', derived)
def test_booleans_are_translated(self):
options = CMakeOptions()
options.define('A_BOOLEAN_OPTION', True)
options.define('ANOTHER_BOOLEAN_OPTION', False)
self.assertIn('-DA_BOOLEAN_OPTION=TRUE', options)
self.assertIn('-DANOTHER_BOOLEAN_OPTION=FALSE', options)
def test_extend_with_other_options(self):
options = CMakeOptions()
options.define('FOO', 'foo')
options.define('BAR', True)
derived = CMakeOptions()
derived.extend(options)
self.assertIn('-DFOO=foo', derived)
self.assertIn('-DBAR=TRUE', derived)
def test_extend_with_tuples(self):
options = CMakeOptions()
options.extend([('FOO', 'foo'), ('BAR', True)])
self.assertIn('-DFOO=foo', options)
self.assertIn('-DBAR=TRUE', options)
def test_contains(self):
options = CMakeOptions()
self.assertTrue('-DFOO=foo' not in options)
options.define('FOO', 'foo')
self.assertTrue('-DFOO=foo' in options)
if __name__ == '__main__':
unittest.main()