diff options
Diffstat (limited to 'meson/mesonbuild/dependencies/ui.py')
-rw-r--r-- | meson/mesonbuild/dependencies/ui.py | 277 |
1 files changed, 277 insertions, 0 deletions
diff --git a/meson/mesonbuild/dependencies/ui.py b/meson/mesonbuild/dependencies/ui.py new file mode 100644 index 000000000..f256a370c --- /dev/null +++ b/meson/mesonbuild/dependencies/ui.py @@ -0,0 +1,277 @@ +# Copyright 2013-2017 The Meson development team + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This file contains the detection logic for external dependencies that +# are UI-related. +import os +import subprocess +import typing as T + +from .. import mlog +from .. import mesonlib +from ..mesonlib import ( + Popen_safe, extract_as_list, version_compare_many +) +from ..environment import detect_cpu_family + +from .base import DependencyException, DependencyMethods, DependencyTypeName, SystemDependency +from .configtool import ConfigToolDependency +from .factory import DependencyFactory + +if T.TYPE_CHECKING: + from ..environment import Environment + + +class GLDependencySystem(SystemDependency): + def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T.Any]) -> None: + super().__init__(name, environment, kwargs) + + if self.env.machines[self.for_machine].is_darwin(): + self.is_found = True + # FIXME: Use AppleFrameworks dependency + self.link_args = ['-framework', 'OpenGL'] + # FIXME: Detect version using self.clib_compiler + return + if self.env.machines[self.for_machine].is_windows(): + self.is_found = True + # FIXME: Use self.clib_compiler.find_library() + self.link_args = ['-lopengl32'] + # FIXME: Detect version using self.clib_compiler + return + + @staticmethod + def get_methods() -> T.List[DependencyMethods]: + if mesonlib.is_osx() or mesonlib.is_windows(): + return [DependencyMethods.PKGCONFIG, DependencyMethods.SYSTEM] + else: + return [DependencyMethods.PKGCONFIG] + + def log_tried(self) -> str: + return 'system' + +class GnuStepDependency(ConfigToolDependency): + + tools = ['gnustep-config'] + tool_name = 'gnustep-config' + + def __init__(self, environment: 'Environment', kwargs: T.Dict[str, T.Any]) -> None: + super().__init__('gnustep', environment, kwargs, language='objc') + if not self.is_found: + return + self.modules = kwargs.get('modules', []) + self.compile_args = self.filter_args( + self.get_config_value(['--objc-flags'], 'compile_args')) + self.link_args = self.weird_filter(self.get_config_value( + ['--gui-libs' if 'gui' in self.modules else '--base-libs'], + 'link_args')) + + def find_config(self, versions: T.Optional[T.List[str]] = None, returncode: int = 0) -> T.Tuple[T.Optional[T.List[str]], T.Optional[str]]: + tool = [self.tools[0]] + try: + p, out = Popen_safe(tool + ['--help'])[:2] + except (FileNotFoundError, PermissionError): + return (None, None) + if p.returncode != returncode: + return (None, None) + self.config = tool + found_version = self.detect_version() + if versions and not version_compare_many(found_version, versions)[0]: + return (None, found_version) + + return (tool, found_version) + + @staticmethod + def weird_filter(elems: T.List[str]) -> T.List[str]: + """When building packages, the output of the enclosing Make is + sometimes mixed among the subprocess output. I have no idea why. As a + hack filter out everything that is not a flag. + """ + return [e for e in elems if e.startswith('-')] + + @staticmethod + def filter_args(args: T.List[str]) -> T.List[str]: + """gnustep-config returns a bunch of garbage args such as -O2 and so + on. Drop everything that is not needed. + """ + result = [] + for f in args: + if f.startswith('-D') \ + or f.startswith('-f') \ + or f.startswith('-I') \ + or f == '-pthread' \ + or (f.startswith('-W') and not f == '-Wall'): + result.append(f) + return result + + def detect_version(self) -> str: + gmake = self.get_config_value(['--variable=GNUMAKE'], 'variable')[0] + makefile_dir = self.get_config_value(['--variable=GNUSTEP_MAKEFILES'], 'variable')[0] + # This Makefile has the GNUStep version set + base_make = os.path.join(makefile_dir, 'Additional', 'base.make') + # Print the Makefile variable passed as the argument. For instance, if + # you run the make target `print-SOME_VARIABLE`, this will print the + # value of the variable `SOME_VARIABLE`. + printver = "print-%:\n\t@echo '$($*)'" + env = os.environ.copy() + # See base.make to understand why this is set + env['FOUNDATION_LIB'] = 'gnu' + p, o, e = Popen_safe([gmake, '-f', '-', '-f', base_make, + 'print-GNUSTEP_BASE_VERSION'], + env=env, write=printver, stdin=subprocess.PIPE) + version = o.strip() + if not version: + mlog.debug("Couldn't detect GNUStep version, falling back to '1'") + # Fallback to setting some 1.x version + version = '1' + return version + + +class SDL2DependencyConfigTool(ConfigToolDependency): + + tools = ['sdl2-config'] + tool_name = 'sdl2-config' + + def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T.Any]): + super().__init__(name, environment, kwargs) + if not self.is_found: + return + self.compile_args = self.get_config_value(['--cflags'], 'compile_args') + self.link_args = self.get_config_value(['--libs'], 'link_args') + + @staticmethod + def get_methods() -> T.List[DependencyMethods]: + if mesonlib.is_osx(): + return [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL, DependencyMethods.EXTRAFRAMEWORK] + else: + return [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL] + + +class WxDependency(ConfigToolDependency): + + tools = ['wx-config-3.0', 'wx-config', 'wx-config-gtk3'] + tool_name = 'wx-config' + + def __init__(self, environment: 'Environment', kwargs: T.Dict[str, T.Any]): + super().__init__('WxWidgets', environment, kwargs, language='cpp') + if not self.is_found: + return + self.requested_modules = self.get_requested(kwargs) + + extra_args = [] + if self.static: + extra_args.append('--static=yes') + + # Check to make sure static is going to work + err = Popen_safe(self.config + extra_args)[2] + if 'No config found to match' in err: + mlog.debug('WxWidgets is missing static libraries.') + self.is_found = False + return + + # wx-config seems to have a cflags as well but since it requires C++, + # this should be good, at least for now. + self.compile_args = self.get_config_value(['--cxxflags'] + extra_args + self.requested_modules, 'compile_args') + self.link_args = self.get_config_value(['--libs'] + extra_args + self.requested_modules, 'link_args') + + @staticmethod + def get_requested(kwargs: T.Dict[str, T.Any]) -> T.List[str]: + if 'modules' not in kwargs: + return [] + candidates = extract_as_list(kwargs, 'modules') + for c in candidates: + if not isinstance(c, str): + raise DependencyException('wxwidgets module argument is not a string') + return candidates + + +class VulkanDependencySystem(SystemDependency): + + def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T.Any], language: T.Optional[str] = None) -> None: + super().__init__(name, environment, kwargs, language=language) + + try: + self.vulkan_sdk = os.environ['VULKAN_SDK'] + if not os.path.isabs(self.vulkan_sdk): + raise DependencyException('VULKAN_SDK must be an absolute path.') + except KeyError: + self.vulkan_sdk = None + + if self.vulkan_sdk: + # TODO: this config might not work on some platforms, fix bugs as reported + # we should at least detect other 64-bit platforms (e.g. armv8) + lib_name = 'vulkan' + lib_dir = 'lib' + inc_dir = 'include' + if mesonlib.is_windows(): + lib_name = 'vulkan-1' + lib_dir = 'Lib32' + inc_dir = 'Include' + if detect_cpu_family(self.env.coredata.compilers.host) == 'x86_64': + lib_dir = 'Lib' + + # make sure header and lib are valid + inc_path = os.path.join(self.vulkan_sdk, inc_dir) + header = os.path.join(inc_path, 'vulkan', 'vulkan.h') + lib_path = os.path.join(self.vulkan_sdk, lib_dir) + find_lib = self.clib_compiler.find_library(lib_name, environment, [lib_path]) + + if not find_lib: + raise DependencyException('VULKAN_SDK point to invalid directory (no lib)') + + if not os.path.isfile(header): + raise DependencyException('VULKAN_SDK point to invalid directory (no include)') + + # XXX: this is very odd, and may deserve being removed + self.type_name = DependencyTypeName('vulkan_sdk') + self.is_found = True + self.compile_args.append('-I' + inc_path) + self.link_args.append('-L' + lib_path) + self.link_args.append('-l' + lib_name) + + # TODO: find a way to retrieve the version from the sdk? + # Usually it is a part of the path to it (but does not have to be) + return + else: + # simply try to guess it, usually works on linux + libs = self.clib_compiler.find_library('vulkan', environment, []) + if libs is not None and self.clib_compiler.has_header('vulkan/vulkan.h', '', environment, disable_cache=True)[0]: + self.is_found = True + for lib in libs: + self.link_args.append(lib) + return + + @staticmethod + def get_methods() -> T.List[DependencyMethods]: + return [DependencyMethods.SYSTEM] + + def log_tried(self) -> str: + return 'system' + +gl_factory = DependencyFactory( + 'gl', + [DependencyMethods.PKGCONFIG, DependencyMethods.SYSTEM], + system_class=GLDependencySystem, +) + +sdl2_factory = DependencyFactory( + 'sdl2', + [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL, DependencyMethods.EXTRAFRAMEWORK], + configtool_class=SDL2DependencyConfigTool, +) + +vulkan_factory = DependencyFactory( + 'vulkan', + [DependencyMethods.PKGCONFIG, DependencyMethods.SYSTEM], + system_class=VulkanDependencySystem, +) |