mirror of
https://github.com/mesonbuild/meson.git
synced 2026-11-06 05:16:42 +00:00
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
282 lines
11 KiB
Python
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,
|
|
)
|