diff --git a/builder/actions/cmake.py b/builder/actions/cmake.py index 5d1d31335..4031aee7d 100644 --- a/builder/actions/cmake.py +++ b/builder/actions/cmake.py @@ -2,8 +2,10 @@ # SPDX-License-Identifier: Apache-2.0. import os +import pprint import re import shutil +from collections import defaultdict from functools import lru_cache, partial from pathlib import Path @@ -100,6 +102,29 @@ def _project_dirs(env, project): return source_dir, build_dir, install_dir +def _merge_cmake_lang_flags(cmake_args): + print("=== _merge_cmake_lang_flags: cmake args") + pprint.pprint(cmake_args, indent=4, depth=4) + pattern = re.compile(r'''-D(CMAKE_C(?:XX)?_FLAGS)=["']?([^"']+)''') + + new_cmake_args = [] + + cmake_lang_flags = defaultdict(list) + for arg in cmake_args: + m = pattern.match(arg) + if m: + cmake_lang_flags[m.group(1)].append(m.group(2)) + else: + new_cmake_args.append(arg) + + pprint.pprint(cmake_lang_flags, indent=4, depth=4) + + for (k, v) in cmake_lang_flags.items(): + new_cmake_args.append('-D{}={}'.format(k, ' '.join(v))) + + return new_cmake_args + + def _build_project(env, project, cmake_extra, build_tests=False, args_transformer=None, coverage=False): sh = env.shell config = project.get_config(env.spec) @@ -135,6 +160,7 @@ def _build_project(env, project, cmake_extra, build_tests=False, args_transforme # Set compiler flags compiler_flags = [] + c_path = None if toolchain.compiler != 'default' and toolchain.compiler != 'msvc' and not toolchain.cross_compile: c_path = toolchain.compiler_path() cxx_path = toolchain.cxx_compiler_path() @@ -163,6 +189,7 @@ def _build_project(env, project, cmake_extra, build_tests=False, args_transforme # as off. Without UniqueList cmake will treat it as on. cmake_args += project.cmake_args(env) cmake_args += cmake_extra + cmake_args += ['-DCMAKE_VERBOSE_MAKEFILE=ON'] if coverage: if c_path and "gcc" in c_path: # Tell cmake to add coverage related configuration. And make sure GCC is used to compile the project. @@ -177,6 +204,13 @@ def _build_project(env, project, cmake_extra, build_tests=False, args_transforme else: raise Exception('--coverage only support GCC as compiler. Current compiler is: {}'.format(c_path)) + # If there are multiple of the same -DCMAKE__FLAGS arguments, CMake takes only the last one. + # Since -DCMAKE__FLAGS can be set in multiple places (e.g. in a default config for a specific platform or + # compiler, in a user project's config, in this Python module, etc.), we should merge language flags into one per + # language. + cmake_args = _merge_cmake_lang_flags(cmake_args) + print("=== _build_project: cmake_args: {}".format(cmake_args)) + # Allow caller to programmatically tweak the cmake_args, # as a last resort in case data merging wasn't working out if args_transformer: @@ -197,6 +231,7 @@ def _build_project(env, project, cmake_extra, build_tests=False, args_transforme # configure sh.exec(*toolchain.shell_env, cmake, cmake_args, working_dir=working_dir, check=True) + print("=== toolchain.host is {}".format(toolchain.host)) # build & install sh.exec(*toolchain.shell_env, cmake, "--build", project_build_dir, "--config", build_config, "--target", "install", working_dir=working_dir, check=True) diff --git a/builder/core/data.py b/builder/core/data.py index c1e226666..70a507fe9 100644 --- a/builder/core/data.py +++ b/builder/core/data.py @@ -508,6 +508,9 @@ class PKG_TOOLS(Enum): '3': { 'c': "clang-3.9", 'cxx': "clang++-3.9", + # specific version number in use + 'releases': ['3.9'], + 'cmake_args': ['-DAWS_WARNINGS_ARE_ERRORS=OFF'], }, '6': { 'c': "clang-6.0", diff --git a/builder/core/toolchain.py b/builder/core/toolchain.py index c33fc9815..2a3e160b1 100644 --- a/builder/core/toolchain.py +++ b/builder/core/toolchain.py @@ -14,7 +14,6 @@ def _compiler_version(cc): if current_os() != 'windows': result = util.run_command(cc, '--version', quiet=True) lines = result.output.split('\n') - for text in lines: # Apple clang m = re.match(r'Apple (LLVM|clang) version (\d+)', text) @@ -45,15 +44,24 @@ def _find_compiler_tool(name, versions): for version in versions: for pattern in ('{name}-{version}', '{name}-{version}.0'): exe = pattern.format(name=name, version=version) + print("version: {}".format(exe)) path = util.where(exe, resolve_symlinks=False) if path: return path, version return None, None -def _clang_versions(): - versions = [v for v in COMPILERS['clang'] - ['versions'].keys() if v != 'default'] +def _clang_versions(version=None): + versions = [] + all_versions = [v for v in COMPILERS['clang'] + ['versions'].keys() if v != 'default'] + if version: + if version in all_versions: + versions = [version] + if 'releases' in COMPILERS['clang']['versions'][str(version)]: + versions += COMPILERS['clang']['versions'][str(version)]['releases'] + else: + versions += all_versions versions.sort() versions.reverse() return versions @@ -181,7 +189,7 @@ def find_gcc_tool(name, version=None): def find_llvm_tool(name, version=None): """ Finds clang, clang-tidy, lld, etc at a specific version, or the latest one available """ - versions = [version] if version else _clang_versions() + versions = _clang_versions(version) return _find_compiler_tool(name, versions) @staticmethod