From ec396dc4f0872dc7d96393a2bdc02625f8a4c878 Mon Sep 17 00:00:00 2001 From: Simon Evans Date: Wed, 14 Aug 2019 07:55:35 +0100 Subject: [PATCH] Linux: Build CMake if the checked out version is newer than the installed version. - For Linux only, if the checked out CMake repository is a newer version than the installed CMake version or CMake is not installed, build and use CMake from source. - This does not affect macOS build or set any minimum required CMake version in CMakeLists.txt --- utils/build-script | 8 ++ .../swift_build_support/cmake.py | 96 +++++++++++++++++++ 2 files changed, 104 insertions(+) diff --git a/utils/build-script b/utils/build-script index 7c538c1da257..338f229e918c 100755 --- a/utils/build-script +++ b/utils/build-script @@ -1042,6 +1042,14 @@ def main_normal(): if args.cmake is not None: toolchain.cmake = args.cmake + cmake = CMake(args=args, toolchain=toolchain) + # Check the CMake version is sufficient on Linux and build from source + # if not. + cmake_path = cmake.check_cmake_version(SWIFT_SOURCE_ROOT, SWIFT_BUILD_ROOT) + if cmake_path is not None: + toolchain.cmake = cmake_path + args.cmake = cmake_path + # Preprocess the arguments to apply defaults. BuildScriptInvocation.apply_default_arguments(toolchain, args) diff --git a/utils/swift_build_support/swift_build_support/cmake.py b/utils/swift_build_support/swift_build_support/cmake.py index 3b29646ddbf1..ae1b2bcf3217 100644 --- a/utils/swift_build_support/swift_build_support/cmake.py +++ b/utils/swift_build_support/swift_build_support/cmake.py @@ -16,6 +16,9 @@ from __future__ import absolute_import +import os +import platform +import re from numbers import Number from . import shell @@ -177,3 +180,96 @@ def build_args(self): '-jobs', str(jobs)] return build_args + + # Determine the version of the installed CMake binary. + def installed_cmake_version(self, cmake_binary): + version = shell.capture([cmake_binary, '--version'], dry_run=False, + echo=True, optional=True) + (c_major, c_minor, c_patch) = (0, 0, 0) + if version is not None: + x = re.findall(r'cmake version (\d+)\.(\d+)\.(\d+)', + version.rstrip()) + if len(x) == 1: + (c_major, c_minor, c_patch) = map(int, x[0]) + + return (c_major, c_minor, c_patch) + + # Determine the version of the checked out CMake source. + def cmake_source_version(self, cmake_source_dir): + cmake_version_file = os.path.join(cmake_source_dir, 'Source', + 'CMakeVersion.cmake') + major = -1 + minor = -1 + patch = -1 + + file = open(cmake_version_file, "r") + for line in file.readlines(): + m = re.findall(r'set\(CMake_VERSION_MAJOR (\d+)\)', line) + if len(m) == 1: + major = int(m[0]) + continue + + m = re.findall(r'set\(CMake_VERSION_MINOR (\d+)\)', line) + if len(m) == 1: + minor = int(m[0]) + continue + + m = re.findall(r'set\(CMake_VERSION_PATCH (\d+)\)', line) + if len(m) == 1: + patch = int(m[0]) + continue + + if major == -1 or minor == -1 or patch == -1: + raise RuntimeError("Cant determine CMake version from %s" + % cmake_version_file) + + return (major, minor, patch) + + # Build CMake from source. + def build_cmake(self, source_root, build_root): + cmake_bootstrap = os.path.join(source_root, 'cmake', 'bootstrap') + + if hasattr(self.args, 'build_script_impl_args'): + for opt in self.args.build_script_impl_args: + m = re.findall('--build-dir=(.*)', opt) + if len(m) == 1: + build_root = m[0] + + cmake_build_dir = os.path.join(build_root, 'cmake-%s' % + self.args.host_target) + if not os.path.isdir(cmake_build_dir): + os.makedirs(cmake_build_dir) + + cwd = os.getcwd() + os.chdir(cmake_build_dir) + shell.call_without_sleeping([cmake_bootstrap], echo=True) + shell.call_without_sleeping(['make', '-j%s' % self.args.build_jobs], + echo=True) + os.chdir(cwd) + return os.path.join(cmake_build_dir, 'bin', 'cmake') + + # For Linux only, determine the version of the installed CMake compared to + # the source and build the source if necessary. Returns the path to the + # cmake binary. + def check_cmake_version(self, source_root, build_root): + if platform.system() != 'Linux': + return + + cmake_source_dir = os.path.join(source_root, 'cmake') + # If the source is not checked out then don't attempt to build cmake. + if not os.path.isdir(cmake_source_dir): + return + + cmake_binary = 'cmake' + try: + if self.args.cmake is not None: + cmake_binary = self.args.cmake + except AttributeError: + cmake_binary = 'cmake' + + installed_ver = self.installed_cmake_version(cmake_binary) + if installed_ver > self.cmake_source_version(cmake_source_dir): + return + else: + # Build CMake from source and return the path to the executable. + return self.build_cmake(source_root, build_root)