Files
meson/mesonbuild/dependencies/ui.py
T
Dylan Baker e991c4d454 Use SPDX-License-Identifier consistently
This replaces all of the Apache blurbs at the start of each file with an
`# SPDX-License-Identifier: Apache-2.0` string. It also fixes existing
uses to be consistent in capitalization, and to be placed above any
copyright notices.

This removes nearly 3000 lines of boilerplate from the project (only
python files), which no developer cares to look at.

SPDX is in common use, particularly in the Linux kernel, and is the
recommended format for Meson's own `project(license: )` field
2023-12-13 15:19:21 -05:00

282 lines
11 KiB
Python

# SPDX-License-Identifier: Apache-2.0
# Copyright 2013-2017 The Meson development team
# This file contains the detection logic for external dependencies that
# are UI-related.
from __future__ import annotations
import os
import re
import subprocess
import typing as T
from .. import mlog
from .. import mesonlib
from ..compilers.compilers import CrossNoRunException
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 .detect import packages
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
elif 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
else:
links = self.clib_compiler.find_library('GL', environment, [])
has_header = self.clib_compiler.has_header('GL/gl.h', '', environment)[0]
if links and has_header:
self.is_found = True
self.link_args = links
elif links:
raise DependencyException('Found GL runtime library but no development header files')
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
packages['gnustep'] = GnuStepDependency
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')
class WxDependency(ConfigToolDependency):
tools = ['wx-config-3.0', 'wx-config-3.1', '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
packages['wxwidgets'] = WxDependency
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)
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)
if self.is_found:
get_version = '''\
#include <stdio.h>
#include <vulkan/vulkan.h>
int main() {
printf("%i.%i.%i", VK_VERSION_MAJOR(VK_HEADER_VERSION_COMPLETE),
VK_VERSION_MINOR(VK_HEADER_VERSION_COMPLETE),
VK_VERSION_PATCH(VK_HEADER_VERSION_COMPLETE));
return 0;
}
'''
try:
run = self.clib_compiler.run(get_version, environment, extra_args=self.compile_args)
except CrossNoRunException:
run = None
if run and run.compiled and run.returncode == 0:
self.version = run.stdout
elif self.vulkan_sdk:
# fall back to heuristics: detect version number in path
# matches the default install path on Windows
match = re.search(rf'VulkanSDK{re.escape(os.path.sep)}([0-9]+(?:\.[0-9]+)+)', self.vulkan_sdk)
if match:
self.version = match.group(1)
else:
mlog.warning(f'Environment variable VULKAN_SDK={self.vulkan_sdk} is present, but Vulkan version could not be extracted.')
packages['gl'] = gl_factory = DependencyFactory(
'gl',
[DependencyMethods.PKGCONFIG, DependencyMethods.SYSTEM],
system_class=GLDependencySystem,
)
packages['sdl2'] = sdl2_factory = DependencyFactory(
'sdl2',
[DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL, DependencyMethods.EXTRAFRAMEWORK, DependencyMethods.CMAKE],
configtool_class=SDL2DependencyConfigTool,
cmake_name='SDL2',
)
packages['vulkan'] = vulkan_factory = DependencyFactory(
'vulkan',
[DependencyMethods.PKGCONFIG, DependencyMethods.SYSTEM],
system_class=VulkanDependencySystem,
)