From 6efc94b5dd0d360218eec3fae98caf3a87a757b9 Mon Sep 17 00:00:00 2001 From: Daniel Mensinger Date: Tue, 12 Feb 2019 14:42:03 +0100 Subject: [PATCH 01/10] Support different CMake files --- mesonbuild/dependencies/base.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index f4e47cf5d..a192bd47b 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -1049,7 +1049,7 @@ class CMakeDependency(ExternalDependency): cmake_opts = ['-G', i] + cmake_opts # Run CMake - ret1, out1, err1 = self._call_cmake(cmake_opts) + ret1, out1, err1 = self._call_cmake(cmake_opts, 'CMakeLists.txt') # Current generator was successful if ret1 == 0: @@ -1449,7 +1449,7 @@ set(CMAKE_CXX_ABI_COMPILED TRUE) set(CMAKE_SIZEOF_VOID_P "{}") '''.format(os.path.realpath(__file__), ctypes.sizeof(ctypes.c_voidp))) - def _setup_cmake_dir(self): + def _setup_cmake_dir(self, cmake_file: str): # Setup the CMake build environment and return the "build" directory build_dir = '{}/cmake_{}'.format(self.cmake_root_dir, self.name) os.makedirs(build_dir, exist_ok=True) @@ -1458,15 +1458,15 @@ set(CMAKE_SIZEOF_VOID_P "{}") cmake_lists = '{}/CMakeLists.txt'.format(build_dir) if not os.path.exists(cmake_lists): dir_path = os.path.dirname(os.path.realpath(__file__)) - src_cmake = '{}/data/CMakeLists.txt'.format(dir_path) + src_cmake = '{}/data/{}'.format(dir_path, cmake_file) shutil.copyfile(src_cmake, cmake_lists) self._setup_compiler(build_dir) self._reset_cmake_cache(build_dir) return build_dir - def _call_cmake_real(self, args, env): - build_dir = self._setup_cmake_dir() + def _call_cmake_real(self, args, cmake_file: str, env): + build_dir = self._setup_cmake_dir(cmake_file) cmd = self.cmakebin.get_command() + args p, out, err = Popen_safe(cmd, env=env, cwd=build_dir) rc = p.returncode @@ -1475,7 +1475,7 @@ set(CMAKE_SIZEOF_VOID_P "{}") return rc, out, err - def _call_cmake(self, args, env=None): + def _call_cmake(self, args, cmake_file: str, env=None): if env is None: fenv = env env = os.environ @@ -1486,7 +1486,7 @@ set(CMAKE_SIZEOF_VOID_P "{}") # First check if cached, if not call the real cmake function cache = CMakeDependency.cmake_cache if (self.cmakebin, targs, fenv) not in cache: - cache[(self.cmakebin, targs, fenv)] = self._call_cmake_real(args, env) + cache[(self.cmakebin, targs, fenv)] = self._call_cmake_real(args, cmake_file, env) return cache[(self.cmakebin, targs, fenv)] @staticmethod From cdc338b74337e29c903bb73b61dc6f22877208e7 Mon Sep 17 00:00:00 2001 From: Daniel Mensinger Date: Tue, 12 Feb 2019 18:51:09 +0100 Subject: [PATCH 02/10] Preliminary CMake module search --- mesonbuild/dependencies/base.py | 187 +++++++++++++++++- mesonbuild/dependencies/data/CMakeLists.txt | 18 +- .../dependencies/data/CMakePathInfo.txt | 29 +++ setup.py | 2 +- 4 files changed, 211 insertions(+), 25 deletions(-) create mode 100644 mesonbuild/dependencies/data/CMakePathInfo.txt diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index a192bd47b..e98c12237 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -37,6 +37,7 @@ from ..environment import BinaryTable, Environment from ..mesonlib import MachineChoice, MesonException, OrderedSet, PerMachine from ..mesonlib import Popen_safe, version_compare_many, version_compare, listify from ..mesonlib import Version +from typing import List # These must be defined in this file to avoid cyclical references. packages = {} @@ -916,12 +917,17 @@ class CMakeDependency(ExternalDependency): # multiple times in the same Meson invocation. class_cmakebin = PerMachine(None, None, None) class_cmakevers = PerMachine(None, None, None) + class_cmakeinfo = PerMachine(None, None, None) # We cache all pkg-config subprocess invocations to avoid redundant calls cmake_cache = {} # Version string for the minimum CMake version class_cmake_version = '>=3.4' # CMake generators to try (empty for no generator) class_cmake_generators = ['', 'Ninja', 'Unix Makefiles', 'Visual Studio 10 2010'] + class_working_generator = None + # Cache for os.listdir and os.path.exists + class_listdir_cache = {} + class_isdir_cache = {} def _gen_exception(self, msg): return DependencyException('Dependency {} not found: {}'.format(self.name, msg)) @@ -934,6 +940,7 @@ class CMakeDependency(ExternalDependency): # stored in the pickled coredata and recovered. self.cmakebin = None self.cmakevers = None + self.cmakeinfo = None # Dict of CMake variables: '': ['list', 'of', 'values'] self.vars = {} @@ -1009,6 +1016,12 @@ class CMakeDependency(ExternalDependency): mlog.debug(msg) return + if CMakeDependency.class_cmakeinfo[for_machine] is None: + CMakeDependency.class_cmakeinfo[for_machine] = self._get_cmake_info() + self.cmakeinfo = CMakeDependency.class_cmakeinfo[for_machine] + if self.cmakeinfo is None: + raise self._gen_exception('Unable to obtain CMake system information') + modules = kwargs.get('modules', []) cm_path = kwargs.get('cmake_module_path', []) cm_args = kwargs.get('cmake_args', []) @@ -1021,6 +1034,8 @@ class CMakeDependency(ExternalDependency): cm_path = [x if os.path.isabs(x) else os.path.join(environment.get_source_dir(), x) for x in cm_path] if cm_path: cm_args += ['-DCMAKE_MODULE_PATH={}'.format(';'.join(cm_path))] + if not self._preliminary_find_check(name, cm_path): + return self._detect_dep(name, modules, cm_args) def __repr__(self): @@ -1028,6 +1043,150 @@ class CMakeDependency(ExternalDependency): return s.format(self.__class__.__name__, self.name, self.is_found, self.version_reqs) + def _get_cmake_info(self): + mlog.debug("Extracting basic cmake information") + res = {} + + # Try different CMake generators since specifying no generator may fail + # in cygwin for some reason + gen_list = [] + # First try the last working generator + if CMakeDependency.class_working_generator is not None: + gen_list += [CMakeDependency.class_working_generator] + gen_list += CMakeDependency.class_cmake_generators + + for i in gen_list: + mlog.debug('Try CMake generator: {}'.format(i if len(i) > 0 else 'auto')) + + # Prepare options + cmake_opts = ['--trace-expand', '.'] + if len(i) > 0: + cmake_opts = ['-G', i] + cmake_opts + + # Run CMake + ret1, out1, err1 = self._call_cmake(cmake_opts, 'CMakePathInfo.txt') + + # Current generator was successful + if ret1 == 0: + break + + mlog.debug('CMake failed to gather system information for generator {} with error code {}'.format(i, ret1)) + mlog.debug('OUT:\n{}\n\n\nERR:\n{}\n\n'.format(out1, err1)) + + # Check if any generator succeeded + if ret1 != 0: + return None + + try: + # First parse the trace + lexer1 = self._lex_trace(err1) + + # Primary pass -- parse all invocations of set + for l in lexer1: + if l.func == 'set': + self._cmake_set(l) + except: + return None + + # Extract the variables and sanity check them + module_paths = list(sorted(list(set(self.get_cmake_var('MESON_PATHS_LIST'))))) + module_paths = list(filter(lambda x: os.path.isdir(x), module_paths)) + archs = self.get_cmake_var('MESON_ARCH_LIST') + + common_paths = ['lib', 'lib32', 'lib64', 'libx32', 'share'] + for i in archs: + common_paths += [os.path.join('lib', i)] + + res = { + 'module_paths': module_paths, + 'cmake_root': self.get_cmake_var('MESON_CMAKE_ROOT')[0], + 'archs': archs, + 'common_paths': common_paths + } + + mlog.debug(' -- Module search paths: {}'.format(res['module_paths'])) + mlog.debug(' -- CMake root: {}'.format(res['cmake_root'])) + mlog.debug(' -- CMake architectures: {}'.format(res['archs'])) + mlog.debug(' -- CMake lib search paths: {}'.format(res['common_paths'])) + + # Reset variables + self.vars = {} + return res + + def _cached_listdir(self, path: str) -> List[str]: + if path not in CMakeDependency.class_listdir_cache: + CMakeDependency.class_listdir_cache[path] = list(map(lambda x: x.lower(), os.listdir(path))) + return CMakeDependency.class_listdir_cache[path] + + def _cached_isdir(self, path: str) -> bool: + if path not in CMakeDependency.class_isdir_cache: + CMakeDependency.class_isdir_cache[path] = os.path.isdir(path) + return CMakeDependency.class_isdir_cache[path] + + def _preliminary_find_check(self, name: str, module_path: List[str]) -> bool: + lname = str(name).lower() + # Checks , /cmake, /CMake + def find_module(path: str) -> bool: + for i in [path, os.path.join(path, 'cmake'), os.path.join(path, 'CMake')]: + if not self._cached_isdir(i): + continue + + for j in ['Find{}.cmake', '{}Config.cmake', '{}-config.cmake']: + if os.path.isfile(os.path.join(i, j.format(name))): + return True + return False + + # Search in /(lib/|lib*|share) for cmake files + def search_lib_dirs(path: str) -> bool: + for i in [os.path.join(path, x) for x in self.cmakeinfo['common_paths']]: + if not self._cached_isdir(i): + continue + + # Check /(lib/|lib*|share)/cmake/*/ + cm_dir = os.path.join(i, 'cmake') + if self._cached_isdir(cm_dir): + content = self._cached_listdir(cm_dir) + content = list(filter(lambda x: x.startswith(lname), content)) + for k in content: + if find_module(os.path.join(cm_dir, k)): + return True + + # /(lib/|lib*|share)/*/ + # /(lib/|lib*|share)/*/(cmake|CMake)/ + content = self._cached_listdir(i) + content = list(filter(lambda x: x.startswith(lname), content)) + for k in content: + if find_module(os.path.join(i, k)): + return True + + return False + + # Check the user provided and system module paths + for i in module_path + [os.path.join(self.cmakeinfo['cmake_root'], 'Modules')]: + if find_module(i): + return True + + # Check the system paths + for i in self.cmakeinfo['module_paths']: + if find_module(i): + return True + + if search_lib_dirs(i): + return True + + content = self._cached_listdir(i) + content = list(filter(lambda x: x.startswith(lname), content)) + for k in content: + if search_lib_dirs(os.path.join(i, k)): + return True + + # Check the environment path + env_path = os.environ.get('{}_DIR'.format(name)) + if env_path and find_module(env_path): + return True + + return False + def _detect_dep(self, name: str, modules: List[str], args: List[str]): # Detect a dependency with CMake using the '--find-package' mode # and the trace output (stderr) @@ -1040,11 +1199,17 @@ class CMakeDependency(ExternalDependency): # Try different CMake generators since specifying no generator may fail # in cygwin for some reason - for i in CMakeDependency.class_cmake_generators: + gen_list = [] + # First try the last working generator + if CMakeDependency.class_working_generator is not None: + gen_list += [CMakeDependency.class_working_generator] + gen_list += CMakeDependency.class_cmake_generators + + for i in gen_list: mlog.debug('Try CMake generator: {}'.format(i if len(i) > 0 else 'auto')) # Prepare options - cmake_opts = ['--trace-expand', '-DNAME={}'.format(name)] + args + ['.'] + cmake_opts = ['--trace-expand', '-DNAME={}'.format(name), '-DARCHS={}'.format(';'.join(self.cmakeinfo['archs']))] + args + ['.'] if len(i) > 0: cmake_opts = ['-G', i] + cmake_opts @@ -1053,6 +1218,7 @@ class CMakeDependency(ExternalDependency): # Current generator was successful if ret1 == 0: + CMakeDependency.class_working_generator = i break mlog.debug('CMake failed for generator {} and package {} with error code {}'.format(i, name, ret1)) @@ -1221,7 +1387,7 @@ class CMakeDependency(ExternalDependency): def get_cmake_var(self, var): # Return the value of the CMake variable var or an empty list if var does not exist - for var in self.vars: + if var in self.vars: return self.vars[var] return [] @@ -1456,10 +1622,11 @@ set(CMAKE_SIZEOF_VOID_P "{}") # Copy the CMakeLists.txt cmake_lists = '{}/CMakeLists.txt'.format(build_dir) - if not os.path.exists(cmake_lists): - dir_path = os.path.dirname(os.path.realpath(__file__)) - src_cmake = '{}/data/{}'.format(dir_path, cmake_file) - shutil.copyfile(src_cmake, cmake_lists) + dir_path = os.path.dirname(os.path.realpath(__file__)) + src_cmake = '{}/data/{}'.format(dir_path, cmake_file) + if os.path.exists(cmake_lists): + os.remove(cmake_lists) + shutil.copyfile(src_cmake, cmake_lists) self._setup_compiler(build_dir) self._reset_cmake_cache(build_dir) @@ -1485,9 +1652,9 @@ set(CMAKE_SIZEOF_VOID_P "{}") # First check if cached, if not call the real cmake function cache = CMakeDependency.cmake_cache - if (self.cmakebin, targs, fenv) not in cache: - cache[(self.cmakebin, targs, fenv)] = self._call_cmake_real(args, cmake_file, env) - return cache[(self.cmakebin, targs, fenv)] + if (self.cmakebin, targs, cmake_file, fenv) not in cache: + cache[(self.cmakebin, targs, cmake_file, fenv)] = self._call_cmake_real(args, cmake_file, env) + return cache[(self.cmakebin, targs, cmake_file, fenv)] @staticmethod def get_methods(): diff --git a/mesonbuild/dependencies/data/CMakeLists.txt b/mesonbuild/dependencies/data/CMakeLists.txt index 6f51681f2..64f5b235c 100644 --- a/mesonbuild/dependencies/data/CMakeLists.txt +++ b/mesonbuild/dependencies/data/CMakeLists.txt @@ -1,16 +1,5 @@ cmake_minimum_required(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION} ) -# Inspired by CMakeDetermineCompilerABI.cmake to set CMAKE_LIBRARY_ARCHITECTURE -set(LIB_ARCH_LIST) -if(CMAKE_LIBRARY_ARCHITECTURE_REGEX) - file(GLOB implicit_dirs RELATIVE /lib /lib/*-linux-gnu* ) - foreach(dir ${implicit_dirs}) - if("${dir}" MATCHES "${CMAKE_LIBRARY_ARCHITECTURE_REGEX}") - list(APPEND LIB_ARCH_LIST "${dir}") - endif() - endforeach() -endif() - set(PACKAGE_FOUND FALSE) set(_packageName "${NAME}") string(TOUPPER "${_packageName}" PACKAGE_NAME) @@ -18,12 +7,13 @@ string(TOUPPER "${_packageName}" PACKAGE_NAME) while(TRUE) find_package("${NAME}" QUIET) - if(${_packageName}_FOUND OR ${PACKAGE_NAME}_FOUND OR "${LIB_ARCH_LIST}" STREQUAL "") + # ARCHS has to be set via the CMD interface + if(${_packageName}_FOUND OR ${PACKAGE_NAME}_FOUND OR "${ARCHS}" STREQUAL "") break() endif() - list(GET LIB_ARCH_LIST 0 CMAKE_LIBRARY_ARCHITECTURE) - list(REMOVE_AT LIB_ARCH_LIST 0) + list(GET ARCHS 0 CMAKE_LIBRARY_ARCHITECTURE) + list(REMOVE_AT ARCHS 0) endwhile() if(${_packageName}_FOUND OR ${PACKAGE_NAME}_FOUND) diff --git a/mesonbuild/dependencies/data/CMakePathInfo.txt b/mesonbuild/dependencies/data/CMakePathInfo.txt new file mode 100644 index 000000000..713c2da31 --- /dev/null +++ b/mesonbuild/dependencies/data/CMakePathInfo.txt @@ -0,0 +1,29 @@ +cmake_minimum_required(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION}) + +set(TMP_PATHS_LIST) +list(APPEND TMP_PATHS_LIST ${CMAKE_PREFIX_PATH}) +list(APPEND TMP_PATHS_LIST ${CMAKE_FRAMEWORK_PATH}) +list(APPEND TMP_PATHS_LIST ${CMAKE_APPBUNDLE_PATH}) +list(APPEND TMP_PATHS_LIST $ENV{CMAKE_PREFIX_PATH}) +list(APPEND TMP_PATHS_LIST $ENV{CMAKE_FRAMEWORK_PATH}) +list(APPEND TMP_PATHS_LIST $ENV{CMAKE_APPBUNDLE_PATH}) +list(APPEND TMP_PATHS_LIST ${CMAKE_SYSTEM_PREFIX_PATH}) +list(APPEND TMP_PATHS_LIST ${CMAKE_SYSTEM_FRAMEWORK_PATH}) +list(APPEND TMP_PATHS_LIST ${CMAKE_SYSTEM_APPBUNDLE_PATH}) + +set(LIB_ARCH_LIST) +if(CMAKE_LIBRARY_ARCHITECTURE_REGEX) + file(GLOB implicit_dirs RELATIVE /lib /lib/*-linux-gnu* ) + foreach(dir ${implicit_dirs}) + if("${dir}" MATCHES "${CMAKE_LIBRARY_ARCHITECTURE_REGEX}") + list(APPEND LIB_ARCH_LIST "${dir}") + endif() + endforeach() +endif() + +# "Export" these variables: +set(MESON_ARCH_LIST ${LIB_ARCH_LIST}) +set(MESON_PATHS_LIST ${TMP_PATHS_LIST}) +set(MESON_CMAKE_ROOT ${CMAKE_ROOT}) + +message(STATUS ${TMP_PATHS_LIST}) diff --git a/setup.py b/setup.py index f35296030..07bd3dde5 100644 --- a/setup.py +++ b/setup.py @@ -35,7 +35,7 @@ packages = ['mesonbuild', 'mesonbuild.modules', 'mesonbuild.scripts', 'mesonbuild.wrap'] -package_data = {'mesonbuild.dependencies': ['data/CMakeLists.txt']} +package_data = {'mesonbuild.dependencies': ['data/CMakeLists.txt', 'data/CMakePathInfo.txt']} data_files = [] if sys.platform != 'win32': # Only useful on UNIX-like systems From 03d9bc3b0ede16a426281c666ed8b6981e29112c Mon Sep 17 00:00:00 2001 From: Daniel Mensinger Date: Tue, 12 Feb 2019 19:20:39 +0100 Subject: [PATCH 03/10] Ignore exceptions --- mesonbuild/dependencies/base.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index e98c12237..8bee2ced8 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -1115,12 +1115,18 @@ class CMakeDependency(ExternalDependency): def _cached_listdir(self, path: str) -> List[str]: if path not in CMakeDependency.class_listdir_cache: - CMakeDependency.class_listdir_cache[path] = list(map(lambda x: x.lower(), os.listdir(path))) + try: + CMakeDependency.class_listdir_cache[path] = list(map(lambda x: x.lower(), os.listdir(path))) + except: + CMakeDependency.class_listdir_cache[path] = [] return CMakeDependency.class_listdir_cache[path] def _cached_isdir(self, path: str) -> bool: if path not in CMakeDependency.class_isdir_cache: - CMakeDependency.class_isdir_cache[path] = os.path.isdir(path) + try: + CMakeDependency.class_isdir_cache[path] = os.path.isdir(path) + except: + CMakeDependency.class_isdir_cache[path] = False return CMakeDependency.class_isdir_cache[path] def _preliminary_find_check(self, name: str, module_path: List[str]) -> bool: From 33f5f06f38fce742816101924441f85e95f15375 Mon Sep 17 00:00:00 2001 From: Daniel Mensinger Date: Tue, 12 Feb 2019 19:30:46 +0100 Subject: [PATCH 04/10] Added Mac support --- mesonbuild/dependencies/base.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index 8bee2ced8..80ef4c630 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -1186,6 +1186,13 @@ class CMakeDependency(ExternalDependency): if search_lib_dirs(os.path.join(i, k)): return True + # Mac framework support + for j in ['{}.framework', '{}.app']: + j = j.format(lname) + if j in content: + if find_module(os.path.join(i, j, 'Resources')): + return True + # Check the environment path env_path = os.environ.get('{}_DIR'.format(name)) if env_path and find_module(env_path): From b2dd5fbe08faa3a5a070513b4ca529b2ac33d90b Mon Sep 17 00:00:00 2001 From: Daniel Mensinger Date: Tue, 12 Feb 2019 19:37:26 +0100 Subject: [PATCH 05/10] Fixed minor logic error regarding case conversion --- mesonbuild/dependencies/base.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index 80ef4c630..a9fc313c5 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -37,7 +37,7 @@ from ..environment import BinaryTable, Environment from ..mesonlib import MachineChoice, MesonException, OrderedSet, PerMachine from ..mesonlib import Popen_safe, version_compare_many, version_compare, listify from ..mesonlib import Version -from typing import List +from typing import List, Tuple # These must be defined in this file to avoid cyclical references. packages = {} @@ -1113,10 +1113,10 @@ class CMakeDependency(ExternalDependency): self.vars = {} return res - def _cached_listdir(self, path: str) -> List[str]: + def _cached_listdir(self, path: str) -> List[Tuple[str, str]]: if path not in CMakeDependency.class_listdir_cache: try: - CMakeDependency.class_listdir_cache[path] = list(map(lambda x: x.lower(), os.listdir(path))) + CMakeDependency.class_listdir_cache[path] = [(x, str(x).lower()) for x in os.listdir(path)] except: CMakeDependency.class_listdir_cache[path] = [] return CMakeDependency.class_listdir_cache[path] @@ -1152,17 +1152,17 @@ class CMakeDependency(ExternalDependency): cm_dir = os.path.join(i, 'cmake') if self._cached_isdir(cm_dir): content = self._cached_listdir(cm_dir) - content = list(filter(lambda x: x.startswith(lname), content)) + content = list(filter(lambda x: x[1].startswith(lname), content)) for k in content: - if find_module(os.path.join(cm_dir, k)): + if find_module(os.path.join(cm_dir, k[0])): return True # /(lib/|lib*|share)/*/ # /(lib/|lib*|share)/*/(cmake|CMake)/ content = self._cached_listdir(i) - content = list(filter(lambda x: x.startswith(lname), content)) + content = list(filter(lambda x: x[1].startswith(lname), content)) for k in content: - if find_module(os.path.join(i, k)): + if find_module(os.path.join(i, k[0])): return True return False @@ -1181,16 +1181,16 @@ class CMakeDependency(ExternalDependency): return True content = self._cached_listdir(i) - content = list(filter(lambda x: x.startswith(lname), content)) + content = list(filter(lambda x: x[1].startswith(lname), content)) for k in content: - if search_lib_dirs(os.path.join(i, k)): + if search_lib_dirs(os.path.join(i, k[0])): return True # Mac framework support for j in ['{}.framework', '{}.app']: j = j.format(lname) if j in content: - if find_module(os.path.join(i, j, 'Resources')): + if find_module(os.path.join(i, j[0], 'Resources')): return True # Check the environment path From b69e45ebaca517a47ab39757d1f61f9fd5f55804 Mon Sep 17 00:00:00 2001 From: Daniel Mensinger Date: Tue, 12 Feb 2019 19:49:19 +0100 Subject: [PATCH 06/10] Fixed flake8 --- mesonbuild/dependencies/base.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index a9fc313c5..516b03679 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -26,7 +26,7 @@ import textwrap import platform import itertools import ctypes -from typing import List +from typing import List, Tuple from enum import Enum from pathlib import Path, PurePath @@ -37,7 +37,6 @@ from ..environment import BinaryTable, Environment from ..mesonlib import MachineChoice, MesonException, OrderedSet, PerMachine from ..mesonlib import Popen_safe, version_compare_many, version_compare, listify from ..mesonlib import Version -from typing import List, Tuple # These must be defined in this file to avoid cyclical references. packages = {} @@ -1116,7 +1115,7 @@ class CMakeDependency(ExternalDependency): def _cached_listdir(self, path: str) -> List[Tuple[str, str]]: if path not in CMakeDependency.class_listdir_cache: try: - CMakeDependency.class_listdir_cache[path] = [(x, str(x).lower()) for x in os.listdir(path)] + CMakeDependency.class_listdir_cache[path] = [(x, str(x).lower()) for x in os.listdir(path)] except: CMakeDependency.class_listdir_cache[path] = [] return CMakeDependency.class_listdir_cache[path] @@ -1131,6 +1130,7 @@ class CMakeDependency(ExternalDependency): def _preliminary_find_check(self, name: str, module_path: List[str]) -> bool: lname = str(name).lower() + # Checks , /cmake, /CMake def find_module(path: str) -> bool: for i in [path, os.path.join(path, 'cmake'), os.path.join(path, 'CMake')]: From 1dfa3783f50afffe1f537c482e856a2a5a40fc1c Mon Sep 17 00:00:00 2001 From: Daniel Mensinger Date: Tue, 12 Feb 2019 22:36:02 +0100 Subject: [PATCH 07/10] Use @lru_cache and added return annotation --- mesonbuild/dependencies/base.py | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index 516b03679..44c3ef24d 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -924,9 +924,6 @@ class CMakeDependency(ExternalDependency): # CMake generators to try (empty for no generator) class_cmake_generators = ['', 'Ninja', 'Unix Makefiles', 'Visual Studio 10 2010'] class_working_generator = None - # Cache for os.listdir and os.path.exists - class_listdir_cache = {} - class_isdir_cache = {} def _gen_exception(self, msg): return DependencyException('Dependency {} not found: {}'.format(self.name, msg)) @@ -1112,21 +1109,21 @@ class CMakeDependency(ExternalDependency): self.vars = {} return res - def _cached_listdir(self, path: str) -> List[Tuple[str, str]]: - if path not in CMakeDependency.class_listdir_cache: - try: - CMakeDependency.class_listdir_cache[path] = [(x, str(x).lower()) for x in os.listdir(path)] - except: - CMakeDependency.class_listdir_cache[path] = [] - return CMakeDependency.class_listdir_cache[path] + @staticmethod + @functools.lru_cache(maxsize=None) + def _cached_listdir(path: str) -> List[Tuple[str, str]]: + try: + return [(x, str(x).lower()) for x in os.listdir(path)] + except: + return [] - def _cached_isdir(self, path: str) -> bool: - if path not in CMakeDependency.class_isdir_cache: - try: - CMakeDependency.class_isdir_cache[path] = os.path.isdir(path) - except: - CMakeDependency.class_isdir_cache[path] = False - return CMakeDependency.class_isdir_cache[path] + @staticmethod + @functools.lru_cache(maxsize=None) + def _cached_isdir(path: str) -> bool: + try: + return os.path.isdir(path) + except: + return False def _preliminary_find_check(self, name: str, module_path: List[str]) -> bool: lname = str(name).lower() @@ -1628,7 +1625,7 @@ set(CMAKE_CXX_ABI_COMPILED TRUE) set(CMAKE_SIZEOF_VOID_P "{}") '''.format(os.path.realpath(__file__), ctypes.sizeof(ctypes.c_voidp))) - def _setup_cmake_dir(self, cmake_file: str): + def _setup_cmake_dir(self, cmake_file: str) -> str: # Setup the CMake build environment and return the "build" directory build_dir = '{}/cmake_{}'.format(self.cmake_root_dir, self.name) os.makedirs(build_dir, exist_ok=True) From bc25a12709e97b915027162422cbb571df3e826a Mon Sep 17 00:00:00 2001 From: Daniel Mensinger Date: Mon, 18 Feb 2019 15:01:49 +0100 Subject: [PATCH 08/10] Minor code fixes --- mesonbuild/dependencies/base.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index 44c3ef24d..b25927cba 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -1111,18 +1111,18 @@ class CMakeDependency(ExternalDependency): @staticmethod @functools.lru_cache(maxsize=None) - def _cached_listdir(path: str) -> List[Tuple[str, str]]: + def _cached_listdir(path: str) -> Tuple[Tuple[str, str]]: try: - return [(x, str(x).lower()) for x in os.listdir(path)] - except: - return [] + return tuple([(x, str(x).lower()) for x in os.listdir(path)]) + except OSError: + return () @staticmethod @functools.lru_cache(maxsize=None) def _cached_isdir(path: str) -> bool: try: return os.path.isdir(path) - except: + except OSError: return False def _preliminary_find_check(self, name: str, module_path: List[str]) -> bool: From b7fa161cb9fbca000f7411fd659b7c86dcdced7c Mon Sep 17 00:00:00 2001 From: Nirbheek Chauhan Date: Mon, 18 Feb 2019 15:13:50 +0100 Subject: [PATCH 09/10] Use tuple comprehensions Co-Authored-By: mensinda --- mesonbuild/dependencies/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index b25927cba..c132dfe4a 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -1113,7 +1113,7 @@ class CMakeDependency(ExternalDependency): @functools.lru_cache(maxsize=None) def _cached_listdir(path: str) -> Tuple[Tuple[str, str]]: try: - return tuple([(x, str(x).lower()) for x in os.listdir(path)]) + return tuple((x, str(x).lower()) for x in os.listdir(path)) except OSError: return () From 719730ff1465076aac41527961f0a3c09ed6512f Mon Sep 17 00:00:00 2001 From: Daniel Mensinger Date: Sat, 23 Feb 2019 09:03:23 +0100 Subject: [PATCH 10/10] Minor fixes for code review --- mesonbuild/dependencies/base.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index c132dfe4a..b9fcc11cf 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -33,7 +33,7 @@ from pathlib import Path, PurePath from .. import mlog from .. import mesonlib from ..compilers import clib_langs -from ..environment import BinaryTable, Environment +from ..environment import BinaryTable, Environment, MachineInfo from ..mesonlib import MachineChoice, MesonException, OrderedSet, PerMachine from ..mesonlib import Popen_safe, version_compare_many, version_compare, listify from ..mesonlib import Version @@ -1030,7 +1030,7 @@ class CMakeDependency(ExternalDependency): cm_path = [x if os.path.isabs(x) else os.path.join(environment.get_source_dir(), x) for x in cm_path] if cm_path: cm_args += ['-DCMAKE_MODULE_PATH={}'.format(';'.join(cm_path))] - if not self._preliminary_find_check(name, cm_path): + if not self._preliminary_find_check(name, cm_path, environment.machines[for_machine]): return self._detect_dep(name, modules, cm_args) @@ -1064,6 +1064,7 @@ class CMakeDependency(ExternalDependency): # Current generator was successful if ret1 == 0: + CMakeDependency.class_working_generator = i break mlog.debug('CMake failed to gather system information for generator {} with error code {}'.format(i, ret1)) @@ -1085,7 +1086,7 @@ class CMakeDependency(ExternalDependency): return None # Extract the variables and sanity check them - module_paths = list(sorted(list(set(self.get_cmake_var('MESON_PATHS_LIST'))))) + module_paths = sorted(set(self.get_cmake_var('MESON_PATHS_LIST'))) module_paths = list(filter(lambda x: os.path.isdir(x), module_paths)) archs = self.get_cmake_var('MESON_ARCH_LIST') @@ -1125,7 +1126,7 @@ class CMakeDependency(ExternalDependency): except OSError: return False - def _preliminary_find_check(self, name: str, module_path: List[str]) -> bool: + def _preliminary_find_check(self, name: str, module_path: List[str], machine: MachineInfo) -> bool: lname = str(name).lower() # Checks , /cmake, /CMake @@ -1184,11 +1185,12 @@ class CMakeDependency(ExternalDependency): return True # Mac framework support - for j in ['{}.framework', '{}.app']: - j = j.format(lname) - if j in content: - if find_module(os.path.join(i, j[0], 'Resources')): - return True + if machine.is_darwin(): + for j in ['{}.framework', '{}.app']: + j = j.format(lname) + if j in content: + if find_module(os.path.join(i, j[0], 'Resources')) or find_module(os.path.join(i, j[0], 'Version')): + return True # Check the environment path env_path = os.environ.get('{}_DIR'.format(name))