diff options
author | Jack Lloyd <[email protected]> | 2017-05-19 10:43:22 -0400 |
---|---|---|
committer | Jack Lloyd <[email protected]> | 2017-05-19 10:43:22 -0400 |
commit | d0ed211552b3b4934974246af0aa7d555a0bd2ba (patch) | |
tree | 10b264087b615d5095b435cbe357ca42ae981c12 /configure.py | |
parent | 08ea995eb6f55ae52ec74c5c76ea8a114c72ccf8 (diff) | |
parent | 611f192f8f6bdf7e9c98865e949d798e3b131676 (diff) |
Merge GH #1052 Add build-time compiler detection
Diffstat (limited to 'configure.py')
-rwxr-xr-x | configure.py | 121 |
1 files changed, 104 insertions, 17 deletions
diff --git a/configure.py b/configure.py index 43f5ec94d..ad055aa23 100755 --- a/configure.py +++ b/configure.py @@ -772,7 +772,12 @@ class ModuleInfo(InfoObject): raise InternalError('Module %s mentions unknown OS %s' % (self.infofile, supp_os)) for supp_cc in self.cc: if supp_cc not in cc_info: - raise InternalError('Module %s mentions unknown compiler %s' % (self.infofile, supp_cc)) + colon_idx = supp_cc.find(':') + # a versioned compiler dependency + if colon_idx > 0 and supp_cc[0:colon_idx] in cc_info: + pass + else: + raise InternalError('Module %s mentions unknown compiler %s' % (self.infofile, supp_cc)) for supp_arch in self.arch: if supp_arch not in arch_info: raise InternalError('Module %s mentions unknown arch %s' % (self.infofile, supp_arch)) @@ -812,15 +817,32 @@ class ModuleInfo(InfoObject): def compatible_os(self, os_name): return self.os == [] or os_name in self.os - def compatible_compiler(self, cc, arch): - if self.cc != [] and cc.basename not in self.cc: - return False + def compatible_compiler(self, ccinfo, cc_version, arch): + # Check if this compiler supports the flags we need + def supported_isa_flags(ccinfo, arch): + for isa in self.need_isa: + if ccinfo.isa_flags_for(isa, arch) is None: + return False + return True - for isa in self.need_isa: - if cc.isa_flags_for(isa, arch) is None: - return False + # Check if module gives explicit compiler dependencies + def supported_compiler(ccinfo, cc_version): - return True + if self.cc == [] or ccinfo.basename in self.cc: + return True + + # Maybe a versioned compiler dep + if cc_version != None: + for cc in self.cc: + with_version = cc.find(':') + if with_version > 0: + if cc[0:with_version] == ccinfo.basename: + min_cc_version = [int(v) for v in cc[with_version+1:].split('.')] + cur_cc_version = [int(v) for v in cc_version.split('.')] + # With lists of ints, this does what we want + return cur_cc_version >= min_cc_version + + return supported_isa_flags(ccinfo, arch) and supported_compiler(ccinfo, cc_version) def dependencies(self): # base is an implicit dep for all submodules @@ -1978,11 +2000,12 @@ class ModulesChooser(object): Determine which modules to load based on options, target, etc """ - def __init__(self, modules, module_policy, archinfo, ccinfo, options): + def __init__(self, modules, module_policy, archinfo, ccinfo, cc_version, options): self._modules = modules self._module_policy = module_policy self._archinfo = archinfo self._ccinfo = ccinfo + self._cc_version = cc_version self._options = options self._maybe_dep = set() @@ -1998,7 +2021,7 @@ class ModulesChooser(object): if not module.compatible_os(self._options.os): self._not_using_because['incompatible OS'].add(modname) return False - elif not module.compatible_compiler(self._ccinfo, self._archinfo.basename): + elif not module.compatible_compiler(self._ccinfo, self._cc_version, self._archinfo.basename): self._not_using_because['incompatible compiler'].add(modname) return False elif not module.compatible_cpu(self._archinfo, self._options): @@ -2515,6 +2538,67 @@ class AmalgamationGenerator(object): return amalgamation_sources +def detect_compiler_version(ccinfo, cc_bin, os_name): + + cc_version_flag = { + 'msvc': ([], r'Compiler Version ([0-9]+).[0-9\.]+ for'), + 'gcc': (['-v'], r'gcc version ([0-9]+.[0-9])+.[0-9]+'), + 'clang': (['-v'], r'clang version ([0-9]+.[0-9])+.[0-9]+') + } + + if ccinfo.basename not in cc_version_flag.keys(): + logging.info("No compiler version detection available for %s" % (ccinfo.basename)) + return None + + (flags, version_re_str) = cc_version_flag[ccinfo.basename] + cc_cmd = cc_bin.split(' ') + flags + + try: + cc_version = None + + version = re.compile(version_re_str) + cc_output = subprocess.Popen(cc_cmd, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + universal_newlines=True).communicate() + + cc_output = str(cc_output) + + match = version.search(cc_output) + + if match: + cc_version = match.group(1) + elif match is None and ccinfo.basename == 'clang' and os_name in ['darwin', 'ios']: + xcode_version_to_clang = { + '703': '3.8', + '800': '3.9', + '802': '4.0' + } + + version = re.compile(r'Apple LLVM version [0-9.]+ \(clang-([0-9]{3})\.') + match = version.search(cc_output) + + if match: + apple_clang_version = match.group(1) + if apple_clang_version in xcode_version_to_clang: + cc_version = xcode_version_to_clang[apple_clang_version] + logging.info('Mapping Apple Clang version %s to LLVM version %s' % ( + apple_clang_version, cc_version)) + else: + logging.warning('Unable to determine LLVM Clang version cooresponding to Apple Clang %s' % + (apple_clang_version)) + return '3.8' # safe default + + if cc_version is None: + logging.error("Ran '%s' to get %s compiler version, but no %s version found in %s" % ( + ' '.join(cc_cmd), ccinfo.basename, ccinfo.basename, cc_output)) + + logging.info('Detected %s compiler version %s' % (ccinfo.basename, cc_version)) + return cc_version + except OSError as e: + logging.warning('Could not execute %s for version check: %s' % (cc_cmd, e)) + return None + def have_program(program): """ Test for the existence of a program @@ -2721,15 +2805,14 @@ def validate_options(options, info_os, info_cc, available_module_policies): if options.os == 'windows' and options.compiler == 'gcc': logging.warning('Detected GCC on Windows; use --os=cygwin or --os=mingw?') - - def main_action_list_available_modules(info_modules): for modname in sorted(info_modules.keys()): print(modname) -def prepare_configure_build(info_modules, source_paths, options, cc, arch, osinfo, module_policy): - loaded_module_names = ModulesChooser(info_modules, module_policy, arch, cc, options).choose() +def prepare_configure_build(info_modules, source_paths, options, + cc, cc_version, arch, osinfo, module_policy): + loaded_module_names = ModulesChooser(info_modules, module_policy, arch, cc, cc_version, options).choose() using_mods = [info_modules[modname] for modname in loaded_module_names] build_config = BuildPaths(source_paths, options, using_mods) @@ -2743,10 +2826,12 @@ def prepare_configure_build(info_modules, source_paths, options, cc, arch, osinf return using_mods, build_config, template_vars, makefile_template -def main_action_configure_build(info_modules, source_paths, options, cc, arch, osinfo, module_policy): # pylint: disable=too-many-locals +def main_action_configure_build(info_modules, source_paths, options, + cc, cc_version, arch, osinfo, module_policy): + # pylint: disable=too-many-locals using_mods, build_config, template_vars, makefile_template = prepare_configure_build( - info_modules, source_paths, options, cc, arch, osinfo, module_policy) + info_modules, source_paths, options, cc, cc_version, arch, osinfo, module_policy) # Now we start writing to disk @@ -2879,6 +2964,8 @@ def main(argv): osinfo = info_os[options.os] module_policy = info_module_policies[options.module_policy] if options.module_policy else None + cc_version = detect_compiler_version(cc, options.compiler_binary or cc.binary_name, osinfo.basename) + if options.build_shared_lib and not osinfo.building_shared_supported: logging.warning('Shared libs not supported on %s, disabling shared lib support' % (osinfo.basename)) options.build_shared_lib = False @@ -2887,7 +2974,7 @@ def main(argv): main_action_list_available_modules(info_modules) return 0 else: - main_action_configure_build(info_modules, source_paths, options, cc, arch, osinfo, module_policy) + main_action_configure_build(info_modules, source_paths, options, cc, cc_version, arch, osinfo, module_policy) return 0 |