|
|
|
# Copyright 2013-2019 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 miscellaneous external dependencies.
|
|
|
|
|
|
|
|
from pathlib import Path
|
|
|
|
import functools
|
|
|
|
import re
|
|
|
|
import sysconfig
|
|
|
|
import typing as T
|
|
|
|
|
|
|
|
from .. import mesonlib
|
|
|
|
from .. import mlog
|
|
|
|
from ..environment import detect_cpu_family
|
|
|
|
from .base import DependencyException, DependencyMethods
|
|
|
|
from .base import BuiltinDependency, SystemDependency
|
|
|
|
from .cmake import CMakeDependency
|
|
|
|
from .configtool import ConfigToolDependency
|
|
|
|
from .factory import DependencyFactory, factory_methods
|
|
|
|
from .pkgconfig import PkgConfigDependency
|
|
|
|
|
|
|
|
if T.TYPE_CHECKING:
|
|
|
|
from ..environment import Environment, MachineChoice
|
|
|
|
from .factory import DependencyGenerator
|
|
|
|
|
|
|
|
|
|
|
|
@factory_methods({DependencyMethods.PKGCONFIG, DependencyMethods.CMAKE})
|
|
|
|
def netcdf_factory(env: 'Environment',
|
|
|
|
for_machine: 'MachineChoice',
|
|
|
|
kwargs: T.Dict[str, T.Any],
|
|
|
|
methods: T.List[DependencyMethods]) -> T.List['DependencyGenerator']:
|
|
|
|
language = kwargs.get('language', 'c')
|
|
|
|
if language not in ('c', 'cpp', 'fortran'):
|
|
|
|
raise DependencyException(f'Language {language} is not supported with NetCDF.')
|
|
|
|
|
|
|
|
candidates: T.List['DependencyGenerator'] = []
|
|
|
|
|
|
|
|
if DependencyMethods.PKGCONFIG in methods:
|
|
|
|
if language == 'fortran':
|
|
|
|
pkg = 'netcdf-fortran'
|
|
|
|
else:
|
|
|
|
pkg = 'netcdf'
|
|
|
|
|
|
|
|
candidates.append(functools.partial(PkgConfigDependency, pkg, env, kwargs, language=language))
|
|
|
|
|
|
|
|
if DependencyMethods.CMAKE in methods:
|
|
|
|
candidates.append(functools.partial(CMakeDependency, 'NetCDF', env, kwargs, language=language))
|
|
|
|
|
|
|
|
return candidates
|
|
|
|
|
|
|
|
|
|
|
|
class DlBuiltinDependency(BuiltinDependency):
|
|
|
|
def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any]):
|
|
|
|
super().__init__(name, env, kwargs)
|
|
|
|
self.feature_since = ('0.62.0', "consider checking for `dlopen` with and without `find_library('dl')`")
|
|
|
|
|
|
|
|
if self.clib_compiler.has_function('dlopen', '#include <dlfcn.h>', env)[0]:
|
|
|
|
self.is_found = True
|
|
|
|
|
|
|
|
|
|
|
|
class DlSystemDependency(SystemDependency):
|
|
|
|
def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any]):
|
|
|
|
super().__init__(name, env, kwargs)
|
|
|
|
self.feature_since = ('0.62.0', "consider checking for `dlopen` with and without `find_library('dl')`")
|
|
|
|
|
|
|
|
h = self.clib_compiler.has_header('dlfcn.h', '', env)
|
|
|
|
self.link_args = self.clib_compiler.find_library('dl', env, [], self.libtype)
|
|
|
|
|
|
|
|
if h[0] and self.link_args:
|
|
|
|
self.is_found = True
|
|
|
|
|
|
|
|
|
|
|
|
class OpenMPDependency(SystemDependency):
|
|
|
|
# Map date of specification release (which is the macro value) to a version.
|
|
|
|
VERSIONS = {
|
|
|
|
'201811': '5.0',
|
|
|
|
'201611': '5.0-revision1', # This is supported by ICC 19.x
|
|
|
|
'201511': '4.5',
|
|
|
|
'201307': '4.0',
|
|
|
|
'201107': '3.1',
|
|
|
|
'200805': '3.0',
|
|
|
|
'200505': '2.5',
|
|
|
|
'200203': '2.0',
|
|
|
|
'199810': '1.0',
|
|
|
|
}
|
|
|
|
|
|
|
|
def __init__(self, environment: 'Environment', kwargs: T.Dict[str, T.Any]) -> None:
|
|
|
|
language = kwargs.get('language')
|
|
|
|
super().__init__('openmp', environment, kwargs, language=language)
|
|
|
|
self.is_found = False
|
|
|
|
if self.clib_compiler.get_id() == 'nagfor':
|
|
|
|
# No macro defined for OpenMP, but OpenMP 3.1 is supported.
|
|
|
|
self.version = '3.1'
|
|
|
|
self.is_found = True
|
|
|
|
self.compile_args = self.link_args = self.clib_compiler.openmp_flags()
|
|
|
|
return
|
|
|
|
if self.clib_compiler.get_id() == 'pgi':
|
|
|
|
# through at least PGI 19.4, there is no macro defined for OpenMP, but OpenMP 3.1 is supported.
|
|
|
|
self.version = '3.1'
|
|
|
|
self.is_found = True
|
|
|
|
self.compile_args = self.link_args = self.clib_compiler.openmp_flags()
|
|
|
|
return
|
|
|
|
try:
|
|
|
|
openmp_date = self.clib_compiler.get_define(
|
|
|
|
'_OPENMP', '', self.env, self.clib_compiler.openmp_flags(), [self], disable_cache=True)[0]
|
|
|
|
except mesonlib.EnvironmentException as e:
|
|
|
|
mlog.debug('OpenMP support not available in the compiler')
|
|
|
|
mlog.debug(e)
|
|
|
|
openmp_date = None
|
|
|
|
|
|
|
|
if openmp_date:
|
|
|
|
try:
|
|
|
|
self.version = self.VERSIONS[openmp_date]
|
|
|
|
except KeyError:
|
|
|
|
mlog.debug(f'Could not find an OpenMP version matching {openmp_date}')
|
|
|
|
if openmp_date == '_OPENMP':
|
|
|
|
mlog.debug('This can be caused by flags such as gcc\'s `-fdirectives-only`, which affect preprocessor behavior.')
|
|
|
|
return
|
|
|
|
# Flang has omp_lib.h
|
|
|
|
header_names = ('omp.h', 'omp_lib.h')
|
|
|
|
for name in header_names:
|
|
|
|
if self.clib_compiler.has_header(name, '', self.env, dependencies=[self], disable_cache=True)[0]:
|
|
|
|
self.is_found = True
|
|
|
|
self.compile_args = self.clib_compiler.openmp_flags()
|
|
|
|
self.link_args = self.clib_compiler.openmp_link_flags()
|
|
|
|
break
|
|
|
|
if not self.is_found:
|
|
|
|
mlog.log(mlog.yellow('WARNING:'), 'OpenMP found but omp.h missing.')
|
|
|
|
|
|
|
|
|
|
|
|
class ThreadDependency(SystemDependency):
|
|
|
|
def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T.Any]) -> None:
|
|
|
|
super().__init__(name, environment, kwargs)
|
|
|
|
self.is_found = True
|
|
|
|
# Happens if you are using a language with threads
|
|
|
|
# concept without C, such as plain Cuda.
|
|
|
|
if self.clib_compiler is None:
|
|
|
|
self.compile_args = []
|
|
|
|
self.link_args = []
|
|
|
|
else:
|
|
|
|
self.compile_args = self.clib_compiler.thread_flags(environment)
|
|
|
|
self.link_args = self.clib_compiler.thread_link_flags(environment)
|
|
|
|
|
|
|
|
|
|
|
|
class BlocksDependency(SystemDependency):
|
|
|
|
def __init__(self, environment: 'Environment', kwargs: T.Dict[str, T.Any]) -> None:
|
|
|
|
super().__init__('blocks', environment, kwargs)
|
|
|
|
self.name = 'blocks'
|
|
|
|
self.is_found = False
|
|
|
|
|
|
|
|
if self.env.machines[self.for_machine].is_darwin():
|
|
|
|
self.compile_args = []
|
|
|
|
self.link_args = []
|
|
|
|
else:
|
|
|
|
self.compile_args = ['-fblocks']
|
|
|
|
self.link_args = ['-lBlocksRuntime']
|
|
|
|
|
|
|
|
if not self.clib_compiler.has_header('Block.h', '', environment, disable_cache=True) or \
|
|
|
|
not self.clib_compiler.find_library('BlocksRuntime', environment, []):
|
|
|
|
mlog.log(mlog.red('ERROR:'), 'BlocksRuntime not found.')
|
|
|
|
return
|
|
|
|
|
|
|
|
source = '''
|
|
|
|
int main(int argc, char **argv)
|
|
|
|
{
|
|
|
|
int (^callback)(void) = ^ int (void) { return 0; };
|
|
|
|
return callback();
|
|
|
|
}'''
|
|
|
|
|
|
|
|
with self.clib_compiler.compile(source, extra_args=self.compile_args + self.link_args) as p:
|
|
|
|
if p.returncode != 0:
|
|
|
|
mlog.log(mlog.red('ERROR:'), 'Compiler does not support blocks extension.')
|
|
|
|
return
|
|
|
|
|
|
|
|
self.is_found = True
|
|
|
|
|
|
|
|
|
|
|
|
class Python3DependencySystem(SystemDependency):
|
|
|
|
def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T.Any]) -> None:
|
|
|
|
super().__init__(name, environment, kwargs)
|
|
|
|
|
|
|
|
if not environment.machines.matches_build_machine(self.for_machine):
|
|
|
|
return
|
|
|
|
if not environment.machines[self.for_machine].is_windows():
|
|
|
|
return
|
|
|
|
|
|
|
|
self.name = 'python3'
|
|
|
|
self.static = kwargs.get('static', False)
|
|
|
|
# We can only be sure that it is Python 3 at this point
|
|
|
|
self.version = '3'
|
|
|
|
self._find_libpy3_windows(environment)
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def get_windows_python_arch() -> T.Optional[str]:
|
|
|
|
pyplat = sysconfig.get_platform()
|
|
|
|
if pyplat == 'mingw':
|
|
|
|
pycc = sysconfig.get_config_var('CC')
|
|
|
|
if pycc.startswith('x86_64'):
|
|
|
|
return '64'
|
|
|
|
elif pycc.startswith(('i686', 'i386')):
|
|
|
|
return '32'
|
|
|
|
else:
|
|
|
|
mlog.log(f'MinGW Python built with unknown CC {pycc!r}, please file a bug')
|
|
|
|
return None
|
|
|
|
elif pyplat == 'win32':
|
|
|
|
return '32'
|
|
|
|
elif pyplat in ('win64', 'win-amd64'):
|
|
|
|
return '64'
|
|
|
|
mlog.log(f'Unknown Windows Python platform {pyplat!r}')
|
|
|
|
return None
|
|
|
|
|
|
|
|
def get_windows_link_args(self) -> T.Optional[T.List[str]]:
|
|
|
|
pyplat = sysconfig.get_platform()
|
|
|
|
if pyplat.startswith('win'):
|
|
|
|
vernum = sysconfig.get_config_var('py_version_nodot')
|
|
|
|
if self.static:
|
|
|
|
libpath = Path('libs') / f'libpython{vernum}.a'
|
|
|
|
else:
|
|
|
|
comp = self.get_compiler()
|
|
|
|
if comp.id == "gcc":
|
|
|
|
libpath = Path(f'python{vernum}.dll')
|
|
|
|
else:
|
|
|
|
libpath = Path('libs') / f'python{vernum}.lib'
|
|
|
|
lib = Path(sysconfig.get_config_var('base')) / libpath
|
|
|
|
elif pyplat == 'mingw':
|
|
|
|
if self.static:
|
|
|
|
libname = sysconfig.get_config_var('LIBRARY')
|
|
|
|
else:
|
|
|
|
libname = sysconfig.get_config_var('LDLIBRARY')
|
|
|
|
lib = Path(sysconfig.get_config_var('LIBDIR')) / libname
|
|
|
|
if not lib.exists():
|
|
|
|
mlog.log('Could not find Python3 library {!r}'.format(str(lib)))
|
|
|
|
return None
|
|
|
|
return [str(lib)]
|
|
|
|
|
|
|
|
def _find_libpy3_windows(self, env: 'Environment') -> None:
|
|
|
|
'''
|
|
|
|
Find python3 libraries on Windows and also verify that the arch matches
|
|
|
|
what we are building for.
|
|
|
|
'''
|
|
|
|
pyarch = self.get_windows_python_arch()
|
|
|
|
if pyarch is None:
|
|
|
|
self.is_found = False
|
|
|
|
return
|
|
|
|
arch = detect_cpu_family(env.coredata.compilers.host)
|
|
|
|
if arch == 'x86':
|
|
|
|
arch = '32'
|
|
|
|
elif arch == 'x86_64':
|
|
|
|
arch = '64'
|
|
|
|
else:
|
|
|
|
# We can't cross-compile Python 3 dependencies on Windows yet
|
|
|
|
mlog.log(f'Unknown architecture {arch!r} for',
|
|
|
|
mlog.bold(self.name))
|
|
|
|
self.is_found = False
|
|
|
|
return
|
|
|
|
# Pyarch ends in '32' or '64'
|
|
|
|
if arch != pyarch:
|
|
|
|
mlog.log('Need', mlog.bold(self.name), 'for {}-bit, but '
|
|
|
|
'found {}-bit'.format(arch, pyarch))
|
|
|
|
self.is_found = False
|
|
|
|
return
|
|
|
|
# This can fail if the library is not found
|
|
|
|
largs = self.get_windows_link_args()
|
|
|
|
if largs is None:
|
|
|
|
self.is_found = False
|
|
|
|
return
|
|
|
|
self.link_args = largs
|
|
|
|
# Compile args
|
|
|
|
inc = sysconfig.get_path('include')
|
|
|
|
platinc = sysconfig.get_path('platinclude')
|
|
|
|
self.compile_args = ['-I' + inc]
|
|
|
|
if inc != platinc:
|
|
|
|
self.compile_args.append('-I' + platinc)
|
|
|
|
self.version = sysconfig.get_config_var('py_version')
|
|
|
|
self.is_found = True
|
|
|
|
|
|
|
|
def log_tried(self) -> str:
|
|
|
|
return 'sysconfig'
|
|
|
|
|
|
|
|
class PcapDependencyConfigTool(ConfigToolDependency):
|
|
|
|
|
|
|
|
tools = ['pcap-config']
|
|
|
|
tool_name = 'pcap-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')
|
|
|
|
self.version = self.get_pcap_lib_version()
|
|
|
|
|
|
|
|
def get_pcap_lib_version(self) -> T.Optional[str]:
|
|
|
|
# Since we seem to need to run a program to discover the pcap version,
|
|
|
|
# we can't do that when cross-compiling
|
|
|
|
# FIXME: this should be handled if we have an exe_wrapper
|
|
|
|
if not self.env.machines.matches_build_machine(self.for_machine):
|
|
|
|
return None
|
|
|
|
|
|
|
|
v = self.clib_compiler.get_return_value('pcap_lib_version', 'string',
|
|
|
|
'#include <pcap.h>', self.env, [], [self])
|
|
|
|
v = re.sub(r'libpcap version ', '', str(v))
|
|
|
|
v = re.sub(r' -- Apple version.*$', '', v)
|
|
|
|
return v
|
|
|
|
|
|
|
|
|
|
|
|
class CupsDependencyConfigTool(ConfigToolDependency):
|
|
|
|
|
|
|
|
tools = ['cups-config']
|
|
|
|
tool_name = 'cups-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(['--ldflags', '--libs'], 'link_args')
|
|
|
|
|
|
|
|
|
|
|
|
class LibWmfDependencyConfigTool(ConfigToolDependency):
|
|
|
|
|
|
|
|
tools = ['libwmf-config']
|
|
|
|
tool_name = 'libwmf-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 LibGCryptDependencyConfigTool(ConfigToolDependency):
|
|
|
|
|
|
|
|
tools = ['libgcrypt-config']
|
|
|
|
tool_name = 'libgcrypt-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')
|
|
|
|
self.version = self.get_config_value(['--version'], 'version')[0]
|
|
|
|
|
|
|
|
|
|
|
|
class GpgmeDependencyConfigTool(ConfigToolDependency):
|
|
|
|
|
|
|
|
tools = ['gpgme-config']
|
|
|
|
tool_name = 'gpg-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')
|
|
|
|
self.version = self.get_config_value(['--version'], 'version')[0]
|
|
|
|
|
|
|
|
|
|
|
|
class ShadercDependency(SystemDependency):
|
|
|
|
|
|
|
|
def __init__(self, environment: 'Environment', kwargs: T.Dict[str, T.Any]):
|
|
|
|
super().__init__('shaderc', environment, kwargs)
|
|
|
|
|
|
|
|
static_lib = 'shaderc_combined'
|
|
|
|
shared_lib = 'shaderc_shared'
|
|
|
|
|
|
|
|
libs = [shared_lib, static_lib]
|
|
|
|
if self.static:
|
|
|
|
libs.reverse()
|
|
|
|
|
|
|
|
cc = self.get_compiler()
|
|
|
|
|
|
|
|
for lib in libs:
|
|
|
|
self.link_args = cc.find_library(lib, environment, [])
|
|
|
|
if self.link_args is not None:
|
|
|
|
self.is_found = True
|
|
|
|
|
|
|
|
if self.static and lib != static_lib:
|
|
|
|
mlog.warning(f'Static library {static_lib!r} not found for dependency '
|
|
|
|
f'{self.name!r}, may not be statically linked')
|
|
|
|
|
|
|
|
break
|
|
|
|
|
|
|
|
def log_tried(self) -> str:
|
|
|
|
return 'system'
|
|
|
|
|
|
|
|
|
|
|
|
class CursesConfigToolDependency(ConfigToolDependency):
|
|
|
|
|
|
|
|
"""Use the curses config tools."""
|
|
|
|
|
|
|
|
tool = 'curses-config'
|
|
|
|
# ncurses5.4-config is for macOS Catalina
|
|
|
|
tools = ['ncursesw6-config', 'ncursesw5-config', 'ncurses6-config', 'ncurses5-config', 'ncurses5.4-config']
|
|
|
|
|
|
|
|
def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any], language: T.Optional[str] = None):
|
|
|
|
super().__init__(name, env, kwargs, language)
|
|
|
|
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 CursesSystemDependency(SystemDependency):
|
|
|
|
|
|
|
|
"""Curses dependency the hard way.
|
|
|
|
|
|
|
|
This replaces hand rolled find_library() and has_header() calls. We
|
|
|
|
provide this for portability reasons, there are a large number of curses
|
|
|
|
implementations, and the differences between them can be very annoying.
|
|
|
|
"""
|
|
|
|
|
|
|
|
def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any]):
|
|
|
|
super().__init__(name, env, kwargs)
|
|
|
|
|
|
|
|
candidates = [
|
|
|
|
('pdcurses', ['pdcurses/curses.h']),
|
|
|
|
('ncursesw', ['ncursesw/ncurses.h', 'ncurses.h']),
|
|
|
|
('ncurses', ['ncurses/ncurses.h', 'ncurses/curses.h', 'ncurses.h']),
|
|
|
|
('curses', ['curses.h']),
|
|
|
|
]
|
|
|
|
|
|
|
|
# Not sure how else to elegently break out of both loops
|
|
|
|
for lib, headers in candidates:
|
|
|
|
l = self.clib_compiler.find_library(lib, env, [])
|
|
|
|
if l:
|
|
|
|
for header in headers:
|
|
|
|
h = self.clib_compiler.has_header(header, '', env)
|
|
|
|
if h[0]:
|
|
|
|
self.is_found = True
|
|
|
|
self.link_args = l
|
|
|
|
# Not sure how to find version for non-ncurses curses
|
|
|
|
# implementations. The one in illumos/OpenIndiana
|
|
|
|
# doesn't seem to have a version defined in the header.
|
|
|
|
if lib.startswith('ncurses'):
|
|
|
|
v, _ = self.clib_compiler.get_define('NCURSES_VERSION', f'#include <{header}>', env, [], [self])
|
|
|
|
self.version = v.strip('"')
|
|
|
|
if lib.startswith('pdcurses'):
|
|
|
|
v_major, _ = self.clib_compiler.get_define('PDC_VER_MAJOR', f'#include <{header}>', env, [], [self])
|
|
|
|
v_minor, _ = self.clib_compiler.get_define('PDC_VER_MINOR', f'#include <{header}>', env, [], [self])
|
|
|
|
self.version = f'{v_major}.{v_minor}'
|
|
|
|
|
|
|
|
# Check the version if possible, emit a warning if we can't
|
|
|
|
req = kwargs.get('version')
|
|
|
|
if req:
|
|
|
|
if self.version:
|
|
|
|
self.is_found = mesonlib.version_compare(self.version, req)
|
|
|
|
else:
|
|
|
|
mlog.warning('Cannot determine version of curses to compare against.')
|
|
|
|
|
|
|
|
if self.is_found:
|
|
|
|
mlog.debug('Curses library:', l)
|
|
|
|
mlog.debug('Curses header:', header)
|
|
|
|
break
|
|
|
|
if self.is_found:
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
|
|
class IconvBuiltinDependency(BuiltinDependency):
|
|
|
|
def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any]):
|
|
|
|
super().__init__(name, env, kwargs)
|
|
|
|
self.feature_since = ('0.60.0', "consider checking for `iconv_open` with and without `find_library('iconv')`")
|
|
|
|
code = '''#include <iconv.h>\n\nint main() {\n iconv_open("","");\n}''' # [ignore encoding] this is C, not python, Mr. Lint
|
|
|
|
|
|
|
|
if self.clib_compiler.links(code, env)[0]:
|
|
|
|
self.is_found = True
|
|
|
|
|
|
|
|
|
|
|
|
class IconvSystemDependency(SystemDependency):
|
|
|
|
def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any]):
|
|
|
|
super().__init__(name, env, kwargs)
|
|
|
|
self.feature_since = ('0.60.0', "consider checking for `iconv_open` with and without find_library('iconv')")
|
|
|
|
|
|
|
|
h = self.clib_compiler.has_header('iconv.h', '', env)
|
|
|
|
self.link_args = self.clib_compiler.find_library('iconv', env, [], self.libtype)
|
|
|
|
|
|
|
|
if h[0] and self.link_args:
|
|
|
|
self.is_found = True
|
|
|
|
|
|
|
|
|
|
|
|
class IntlBuiltinDependency(BuiltinDependency):
|
|
|
|
def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any]):
|
|
|
|
super().__init__(name, env, kwargs)
|
|
|
|
self.feature_since = ('0.59.0', "consider checking for `ngettext` with and without `find_library('intl')`")
|
|
|
|
code = '''#include <libintl.h>\n\nint main() {\n gettext("Hello world");\n}'''
|
|
|
|
|
|
|
|
if self.clib_compiler.links(code, env)[0]:
|
|
|
|
self.is_found = True
|
|
|
|
|
|
|
|
|
|
|
|
class IntlSystemDependency(SystemDependency):
|
|
|
|
def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any]):
|
|
|
|
super().__init__(name, env, kwargs)
|
|
|
|
self.feature_since = ('0.59.0', "consider checking for `ngettext` with and without `find_library('intl')`")
|
|
|
|
|
|
|
|
h = self.clib_compiler.has_header('libintl.h', '', env)
|
|
|
|
self.link_args = self.clib_compiler.find_library('intl', env, [], self.libtype)
|
|
|
|
|
|
|
|
if h[0] and self.link_args:
|
|
|
|
self.is_found = True
|
|
|
|
|
|
|
|
if self.static:
|
|
|
|
if not self._add_sub_dependency(iconv_factory(env, self.for_machine, {'static': True})):
|
|
|
|
self.is_found = False
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
class OpensslSystemDependency(SystemDependency):
|
|
|
|
def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any]):
|
|
|
|
super().__init__(name, env, kwargs)
|
|
|
|
|
|
|
|
dependency_kwargs = {
|
|
|
|
'method': 'system',
|
|
|
|
'static': self.static,
|
|
|
|
}
|
|
|
|
if not self.clib_compiler.has_header('openssl/ssl.h', '', env)[0]:
|
|
|
|
return
|
|
|
|
|
|
|
|
# openssl >= 3 only
|
|
|
|
self.version = self.clib_compiler.get_define('OPENSSL_VERSION_STR', '#include <openssl/opensslv.h>', env, [], [self])[0]
|
|
|
|
# openssl < 3 only
|
|
|
|
if not self.version:
|
|
|
|
version_hex = self.clib_compiler.get_define('OPENSSL_VERSION_NUMBER', '#include <openssl/opensslv.h>', env, [], [self])[0]
|
|
|
|
if not version_hex:
|
|
|
|
return
|
|
|
|
version_hex = version_hex.rstrip('L')
|
|
|
|
version_ints = [((int(version_hex.rstrip('L'), 16) >> 4 + i) & 0xFF) for i in (24, 16, 8, 0)]
|
|
|
|
# since this is openssl, the format is 1.2.3a in four parts
|
|
|
|
self.version = '.'.join(str(i) for i in version_ints[:3]) + chr(ord('a') + version_ints[3] - 1)
|
|
|
|
|
|
|
|
if name == 'openssl':
|
|
|
|
if self._add_sub_dependency(libssl_factory(env, self.for_machine, dependency_kwargs)) and \
|
|
|
|
self._add_sub_dependency(libcrypto_factory(env, self.for_machine, dependency_kwargs)):
|
|
|
|
self.is_found = True
|
|
|
|
return
|
|
|
|
else:
|
|
|
|
self.link_args = self.clib_compiler.find_library(name.lstrip('lib'), env, [], self.libtype)
|
|
|
|
if not self.link_args:
|
|
|
|
return
|
|
|
|
|
|
|
|
if not self.static:
|
|
|
|
self.is_found = True
|
|
|
|
else:
|
|
|
|
if name == 'libssl':
|
|
|
|
if self._add_sub_dependency(libcrypto_factory(env, self.for_machine, dependency_kwargs)):
|
|
|
|
self.is_found = True
|
|
|
|
elif name == 'libcrypto':
|
|
|
|
use_threads = self.clib_compiler.has_header_symbol('openssl/opensslconf.h', 'OPENSSL_THREADS', '', env, dependencies=[self])[0]
|
|
|
|
if not use_threads or self._add_sub_dependency(threads_factory(env, self.for_machine, {})):
|
|
|
|
self.is_found = True
|
|
|
|
# only relevant on platforms where it is distributed with the libc, in which case it always succeeds
|
|
|
|
sublib = self.clib_compiler.find_library('dl', env, [], self.libtype)
|
|
|
|
if sublib:
|
|
|
|
self.link_args.extend(sublib)
|
|
|
|
|
|
|
|
|
|
|
|
@factory_methods({DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL, DependencyMethods.SYSTEM})
|
|
|
|
def curses_factory(env: 'Environment',
|
|
|
|
for_machine: 'MachineChoice',
|
|
|
|
kwargs: T.Dict[str, T.Any],
|
|
|
|
methods: T.List[DependencyMethods]) -> T.List['DependencyGenerator']:
|
|
|
|
candidates: T.List['DependencyGenerator'] = []
|
|
|
|
|
|
|
|
if DependencyMethods.PKGCONFIG in methods:
|
|
|
|
pkgconfig_files = ['pdcurses', 'ncursesw', 'ncurses', 'curses']
|
|
|
|
for pkg in pkgconfig_files:
|
|
|
|
candidates.append(functools.partial(PkgConfigDependency, pkg, env, kwargs))
|
|
|
|
|
|
|
|
# There are path handling problems with these methods on msys, and they
|
|
|
|
# don't apply to windows otherwise (cygwin is handled separately from
|
|
|
|
# windows)
|
|
|
|
if not env.machines[for_machine].is_windows():
|
|
|
|
if DependencyMethods.CONFIG_TOOL in methods:
|
|
|
|
candidates.append(functools.partial(CursesConfigToolDependency, 'curses', env, kwargs))
|
|
|
|
|
|
|
|
if DependencyMethods.SYSTEM in methods:
|
|
|
|
candidates.append(functools.partial(CursesSystemDependency, 'curses', env, kwargs))
|
|
|
|
|
|
|
|
return candidates
|
|
|
|
|
|
|
|
|
|
|
|
@factory_methods({DependencyMethods.PKGCONFIG, DependencyMethods.SYSTEM})
|
|
|
|
def shaderc_factory(env: 'Environment',
|
|
|
|
for_machine: 'MachineChoice',
|
|
|
|
kwargs: T.Dict[str, T.Any],
|
|
|
|
methods: T.List[DependencyMethods]) -> T.List['DependencyGenerator']:
|
|
|
|
"""Custom DependencyFactory for ShaderC.
|
|
|
|
|
|
|
|
ShaderC's odd you get three different libraries from the same build
|
|
|
|
thing are just easier to represent as a separate function than
|
|
|
|
twisting DependencyFactory even more.
|
|
|
|
"""
|
|
|
|
candidates: T.List['DependencyGenerator'] = []
|
|
|
|
|
|
|
|
if DependencyMethods.PKGCONFIG in methods:
|
|
|
|
# ShaderC packages their shared and static libs together
|
|
|
|
# and provides different pkg-config files for each one. We
|
|
|
|
# smooth over this difference by handling the static
|
|
|
|
# keyword before handing off to the pkg-config handler.
|
|
|
|
shared_libs = ['shaderc']
|
|
|
|
static_libs = ['shaderc_combined', 'shaderc_static']
|
|
|
|
|
|
|
|
if kwargs.get('static', False):
|
|
|
|
c = [functools.partial(PkgConfigDependency, name, env, kwargs)
|
|
|
|
for name in static_libs + shared_libs]
|
|
|
|
else:
|
|
|
|
c = [functools.partial(PkgConfigDependency, name, env, kwargs)
|
|
|
|
for name in shared_libs + static_libs]
|
|
|
|
candidates.extend(c)
|
|
|
|
|
|
|
|
if DependencyMethods.SYSTEM in methods:
|
|
|
|
candidates.append(functools.partial(ShadercDependency, env, kwargs))
|
|
|
|
|
|
|
|
return candidates
|
|
|
|
|
|
|
|
|
|
|
|
cups_factory = DependencyFactory(
|
|
|
|
'cups',
|
|
|
|
[DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL, DependencyMethods.EXTRAFRAMEWORK, DependencyMethods.CMAKE],
|
|
|
|
configtool_class=CupsDependencyConfigTool,
|
|
|
|
cmake_name='Cups',
|
|
|
|
)
|
|
|
|
|
|
|
|
dl_factory = DependencyFactory(
|
|
|
|
'dl',
|
|
|
|
[DependencyMethods.BUILTIN, DependencyMethods.SYSTEM],
|
|
|
|
builtin_class=DlBuiltinDependency,
|
|
|
|
system_class=DlSystemDependency,
|
|
|
|
)
|
|
|
|
|
|
|
|
gpgme_factory = DependencyFactory(
|
|
|
|
'gpgme',
|
|
|
|
[DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL],
|
|
|
|
configtool_class=GpgmeDependencyConfigTool,
|
|
|
|
)
|
|
|
|
|
|
|
|
libgcrypt_factory = DependencyFactory(
|
|
|
|
'libgcrypt',
|
|
|
|
[DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL],
|
|
|
|
configtool_class=LibGCryptDependencyConfigTool,
|
|
|
|
)
|
|
|
|
|
|
|
|
libwmf_factory = DependencyFactory(
|
|
|
|
'libwmf',
|
|
|
|
[DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL],
|
|
|
|
configtool_class=LibWmfDependencyConfigTool,
|
|
|
|
)
|
|
|
|
|
|
|
|
pcap_factory = DependencyFactory(
|
|
|
|
'pcap',
|
|
|
|
[DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL],
|
|
|
|
configtool_class=PcapDependencyConfigTool,
|
|
|
|
pkgconfig_name='libpcap',
|
|
|
|
)
|
|
|
|
|
|
|
|
python3_factory = DependencyFactory(
|
|
|
|
'python3',
|
|
|
|
[DependencyMethods.PKGCONFIG, DependencyMethods.SYSTEM, DependencyMethods.EXTRAFRAMEWORK],
|
|
|
|
system_class=Python3DependencySystem,
|
|
|
|
# There is no version number in the macOS version number
|
|
|
|
framework_name='Python',
|
|
|
|
# There is a python in /System/Library/Frameworks, but that's python 2.x,
|
|
|
|
# Python 3 will always be in /Library
|
|
|
|
extra_kwargs={'paths': ['/Library/Frameworks']},
|
|
|
|
)
|
|
|
|
|
|
|
|
threads_factory = DependencyFactory(
|
|
|
|
'threads',
|
|
|
|
[DependencyMethods.SYSTEM, DependencyMethods.CMAKE],
|
|
|
|
cmake_name='Threads',
|
|
|
|
system_class=ThreadDependency,
|
|
|
|
)
|
|
|
|
|
|
|
|
iconv_factory = DependencyFactory(
|
|
|
|
'iconv',
|
|
|
|
[DependencyMethods.BUILTIN, DependencyMethods.SYSTEM],
|
|
|
|
builtin_class=IconvBuiltinDependency,
|
|
|
|
system_class=IconvSystemDependency,
|
|
|
|
)
|
|
|
|
|
|
|
|
intl_factory = DependencyFactory(
|
|
|
|
'intl',
|
|
|
|
[DependencyMethods.BUILTIN, DependencyMethods.SYSTEM],
|
|
|
|
builtin_class=IntlBuiltinDependency,
|
|
|
|
system_class=IntlSystemDependency,
|
|
|
|
)
|
|
|
|
|
|
|
|
openssl_factory = DependencyFactory(
|
|
|
|
'openssl',
|
openssl dependency: add cmake support
This is gross and looks terrible, but I'm not entirely sure how else to
do this.
And cmake is an inferior methodology, TBH, since it is effectively the
same as our own builtins. However, cmake also handles some bizarre
Windows library names whose provenance I'm not entirely sure of, in
addition to implementing the usual excessive pattern of hardcoded search
directories. So, this may be useful, at least on Windows, as a fallback.
(I am not really interested in offering feature compatibility with cmake
for a bunch of bizarre naming schemes that ***aren't the official cmake
library names***, so if cmake allows that and people really feel they
need it, all the more power to them.)
Nevertheless, I believe if it got found via our system dependency class,
it will always provide results which are just as functional as cmake.
cmake can only find openssl installations that would otherwise be
missed.
This also avoids the case where users did
```
dependency('OpenSSL', modules: [...], method: 'cmake')
```
and expected it to work, since our builtin dependency supersedes the
divergent case and didn't previously allow the cmake method. I don't
know why they would do such a thing, but who knows... it is always
possible.
3 years ago
|
|
|
[DependencyMethods.PKGCONFIG, DependencyMethods.SYSTEM, DependencyMethods.CMAKE],
|
|
|
|
system_class=OpensslSystemDependency,
|
openssl dependency: add cmake support
This is gross and looks terrible, but I'm not entirely sure how else to
do this.
And cmake is an inferior methodology, TBH, since it is effectively the
same as our own builtins. However, cmake also handles some bizarre
Windows library names whose provenance I'm not entirely sure of, in
addition to implementing the usual excessive pattern of hardcoded search
directories. So, this may be useful, at least on Windows, as a fallback.
(I am not really interested in offering feature compatibility with cmake
for a bunch of bizarre naming schemes that ***aren't the official cmake
library names***, so if cmake allows that and people really feel they
need it, all the more power to them.)
Nevertheless, I believe if it got found via our system dependency class,
it will always provide results which are just as functional as cmake.
cmake can only find openssl installations that would otherwise be
missed.
This also avoids the case where users did
```
dependency('OpenSSL', modules: [...], method: 'cmake')
```
and expected it to work, since our builtin dependency supersedes the
divergent case and didn't previously allow the cmake method. I don't
know why they would do such a thing, but who knows... it is always
possible.
3 years ago
|
|
|
cmake_class=lambda name, env, kwargs: CMakeDependency('OpenSSL', env, dict(kwargs, modules=['OpenSSL::Crypto', 'OpenSSL::SSL'])),
|
|
|
|
)
|
|
|
|
|
|
|
|
libcrypto_factory = DependencyFactory(
|
|
|
|
'libcrypto',
|
openssl dependency: add cmake support
This is gross and looks terrible, but I'm not entirely sure how else to
do this.
And cmake is an inferior methodology, TBH, since it is effectively the
same as our own builtins. However, cmake also handles some bizarre
Windows library names whose provenance I'm not entirely sure of, in
addition to implementing the usual excessive pattern of hardcoded search
directories. So, this may be useful, at least on Windows, as a fallback.
(I am not really interested in offering feature compatibility with cmake
for a bunch of bizarre naming schemes that ***aren't the official cmake
library names***, so if cmake allows that and people really feel they
need it, all the more power to them.)
Nevertheless, I believe if it got found via our system dependency class,
it will always provide results which are just as functional as cmake.
cmake can only find openssl installations that would otherwise be
missed.
This also avoids the case where users did
```
dependency('OpenSSL', modules: [...], method: 'cmake')
```
and expected it to work, since our builtin dependency supersedes the
divergent case and didn't previously allow the cmake method. I don't
know why they would do such a thing, but who knows... it is always
possible.
3 years ago
|
|
|
[DependencyMethods.PKGCONFIG, DependencyMethods.SYSTEM, DependencyMethods.CMAKE],
|
|
|
|
system_class=OpensslSystemDependency,
|
openssl dependency: add cmake support
This is gross and looks terrible, but I'm not entirely sure how else to
do this.
And cmake is an inferior methodology, TBH, since it is effectively the
same as our own builtins. However, cmake also handles some bizarre
Windows library names whose provenance I'm not entirely sure of, in
addition to implementing the usual excessive pattern of hardcoded search
directories. So, this may be useful, at least on Windows, as a fallback.
(I am not really interested in offering feature compatibility with cmake
for a bunch of bizarre naming schemes that ***aren't the official cmake
library names***, so if cmake allows that and people really feel they
need it, all the more power to them.)
Nevertheless, I believe if it got found via our system dependency class,
it will always provide results which are just as functional as cmake.
cmake can only find openssl installations that would otherwise be
missed.
This also avoids the case where users did
```
dependency('OpenSSL', modules: [...], method: 'cmake')
```
and expected it to work, since our builtin dependency supersedes the
divergent case and didn't previously allow the cmake method. I don't
know why they would do such a thing, but who knows... it is always
possible.
3 years ago
|
|
|
cmake_class=lambda name, env, kwargs: CMakeDependency('OpenSSL', env, dict(kwargs, modules=['OpenSSL::Crypto'])),
|
|
|
|
)
|
|
|
|
|
|
|
|
libssl_factory = DependencyFactory(
|
|
|
|
'libssl',
|
openssl dependency: add cmake support
This is gross and looks terrible, but I'm not entirely sure how else to
do this.
And cmake is an inferior methodology, TBH, since it is effectively the
same as our own builtins. However, cmake also handles some bizarre
Windows library names whose provenance I'm not entirely sure of, in
addition to implementing the usual excessive pattern of hardcoded search
directories. So, this may be useful, at least on Windows, as a fallback.
(I am not really interested in offering feature compatibility with cmake
for a bunch of bizarre naming schemes that ***aren't the official cmake
library names***, so if cmake allows that and people really feel they
need it, all the more power to them.)
Nevertheless, I believe if it got found via our system dependency class,
it will always provide results which are just as functional as cmake.
cmake can only find openssl installations that would otherwise be
missed.
This also avoids the case where users did
```
dependency('OpenSSL', modules: [...], method: 'cmake')
```
and expected it to work, since our builtin dependency supersedes the
divergent case and didn't previously allow the cmake method. I don't
know why they would do such a thing, but who knows... it is always
possible.
3 years ago
|
|
|
[DependencyMethods.PKGCONFIG, DependencyMethods.SYSTEM, DependencyMethods.CMAKE],
|
|
|
|
system_class=OpensslSystemDependency,
|
openssl dependency: add cmake support
This is gross and looks terrible, but I'm not entirely sure how else to
do this.
And cmake is an inferior methodology, TBH, since it is effectively the
same as our own builtins. However, cmake also handles some bizarre
Windows library names whose provenance I'm not entirely sure of, in
addition to implementing the usual excessive pattern of hardcoded search
directories. So, this may be useful, at least on Windows, as a fallback.
(I am not really interested in offering feature compatibility with cmake
for a bunch of bizarre naming schemes that ***aren't the official cmake
library names***, so if cmake allows that and people really feel they
need it, all the more power to them.)
Nevertheless, I believe if it got found via our system dependency class,
it will always provide results which are just as functional as cmake.
cmake can only find openssl installations that would otherwise be
missed.
This also avoids the case where users did
```
dependency('OpenSSL', modules: [...], method: 'cmake')
```
and expected it to work, since our builtin dependency supersedes the
divergent case and didn't previously allow the cmake method. I don't
know why they would do such a thing, but who knows... it is always
possible.
3 years ago
|
|
|
cmake_class=lambda name, env, kwargs: CMakeDependency('OpenSSL', env, dict(kwargs, modules=['OpenSSL::SSL'])),
|
|
|
|
)
|