|
|
@ -17,14 +17,16 @@ |
|
|
|
|
|
|
|
|
|
|
|
import os |
|
|
|
import os |
|
|
|
import re |
|
|
|
import re |
|
|
|
import shlex |
|
|
|
|
|
|
|
import shutil |
|
|
|
import shutil |
|
|
|
|
|
|
|
|
|
|
|
from .. import mlog |
|
|
|
from .. import mlog |
|
|
|
from .. import mesonlib |
|
|
|
from .. import mesonlib |
|
|
|
from ..mesonlib import version_compare, Popen_safe, stringlistify, extract_as_list |
|
|
|
from ..mesonlib import version_compare, Popen_safe, stringlistify, extract_as_list |
|
|
|
from .base import DependencyException, ExternalDependency, PkgConfigDependency |
|
|
|
from .base import ( |
|
|
|
from .base import strip_system_libdirs |
|
|
|
DependencyException, ExternalDependency, PkgConfigDependency, |
|
|
|
|
|
|
|
strip_system_libdirs, ConfigToolDependency, |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class GTestDependency(ExternalDependency): |
|
|
|
class GTestDependency(ExternalDependency): |
|
|
|
def __init__(self, environment, kwargs): |
|
|
|
def __init__(self, environment, kwargs): |
|
|
@ -109,7 +111,7 @@ class GMockDependency(ExternalDependency): |
|
|
|
self.is_found = False |
|
|
|
self.is_found = False |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class LLVMDependency(ExternalDependency): |
|
|
|
class LLVMDependency(ConfigToolDependency): |
|
|
|
""" |
|
|
|
""" |
|
|
|
LLVM uses a special tool, llvm-config, which has arguments for getting |
|
|
|
LLVM uses a special tool, llvm-config, which has arguments for getting |
|
|
|
c args, cxx args, and ldargs as well as version. |
|
|
|
c args, cxx args, and ldargs as well as version. |
|
|
@ -121,7 +123,7 @@ class LLVMDependency(ExternalDependency): |
|
|
|
# not be moved to the beginning of the list. The only difference between |
|
|
|
# not be moved to the beginning of the list. The only difference between |
|
|
|
# llvm-config-6.0 and llvm-config-devel is that the former is used by |
|
|
|
# llvm-config-6.0 and llvm-config-devel is that the former is used by |
|
|
|
# Debian and the latter is used by FreeBSD. |
|
|
|
# Debian and the latter is used by FreeBSD. |
|
|
|
llvm_config_bins = [ |
|
|
|
tools = [ |
|
|
|
'llvm-config', # base |
|
|
|
'llvm-config', # base |
|
|
|
'llvm-config-5.0', 'llvm-config50', # latest stable release |
|
|
|
'llvm-config-5.0', 'llvm-config50', # latest stable release |
|
|
|
'llvm-config-4.0', 'llvm-config40', # old stable releases |
|
|
|
'llvm-config-4.0', 'llvm-config40', # old stable releases |
|
|
@ -132,61 +134,31 @@ class LLVMDependency(ExternalDependency): |
|
|
|
'llvm-config-3.5', 'llvm-config35', |
|
|
|
'llvm-config-3.5', 'llvm-config35', |
|
|
|
'llvm-config-6.0', 'llvm-config-devel', # development snapshot |
|
|
|
'llvm-config-6.0', 'llvm-config-devel', # development snapshot |
|
|
|
] |
|
|
|
] |
|
|
|
|
|
|
|
tool_name = 'llvm-config' |
|
|
|
__cpp_blacklist = {'-DNDEBUG'} |
|
|
|
__cpp_blacklist = {'-DNDEBUG'} |
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, environment, kwargs): |
|
|
|
def __init__(self, environment, kwargs): |
|
|
|
# It's necessary for LLVM <= 3.8 to use the C++ linker. For 3.9 and 4.0 |
|
|
|
# It's necessary for LLVM <= 3.8 to use the C++ linker. For 3.9 and 4.0 |
|
|
|
# the C linker works fine if only using the C API. |
|
|
|
# the C linker works fine if only using the C API. |
|
|
|
super().__init__('llvm-config', environment, 'cpp', kwargs) |
|
|
|
super().__init__('config-tool', environment, 'cpp', kwargs) |
|
|
|
self.provided_modules = [] |
|
|
|
self.provided_modules = [] |
|
|
|
self.required_modules = set() |
|
|
|
self.required_modules = set() |
|
|
|
self.llvmconfig = None |
|
|
|
if not self.is_found: |
|
|
|
self.static = kwargs.get('static', False) |
|
|
|
|
|
|
|
self.__best_found = None |
|
|
|
|
|
|
|
# FIXME: Support multiple version requirements ala PkgConfigDependency |
|
|
|
|
|
|
|
req_version = kwargs.get('version', None) |
|
|
|
|
|
|
|
self.check_llvmconfig(req_version) |
|
|
|
|
|
|
|
if self.llvmconfig is None: |
|
|
|
|
|
|
|
if self.__best_found is not None: |
|
|
|
|
|
|
|
mlog.log('found {!r} but need:'.format(self.__best_found), |
|
|
|
|
|
|
|
req_version) |
|
|
|
|
|
|
|
else: |
|
|
|
|
|
|
|
mlog.log("No llvm-config found; can't detect dependency") |
|
|
|
|
|
|
|
mlog.log('Dependency LLVM found:', mlog.red('NO')) |
|
|
|
|
|
|
|
if self.required: |
|
|
|
|
|
|
|
raise DependencyException('Dependency LLVM not found') |
|
|
|
|
|
|
|
return |
|
|
|
return |
|
|
|
|
|
|
|
self.static = kwargs.get('static', False) |
|
|
|
p, out, err = Popen_safe([self.llvmconfig, '--version']) |
|
|
|
|
|
|
|
if p.returncode != 0: |
|
|
|
|
|
|
|
mlog.debug('stdout: {}\nstderr: {}'.format(out, err)) |
|
|
|
|
|
|
|
if self.required: |
|
|
|
|
|
|
|
raise DependencyException('Dependency LLVM not found') |
|
|
|
|
|
|
|
mlog.log('Dependency LLVM found:', mlog.red('NO')) |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mlog.log('Dependency LLVM found:', mlog.green('YES')) |
|
|
|
|
|
|
|
self.is_found = True |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Currently meson doesn't really atempt to handle pre-release versions, |
|
|
|
# Currently meson doesn't really atempt to handle pre-release versions, |
|
|
|
# so strip the 'svn' off the end, since it will probably cuase problems |
|
|
|
# so strip the 'svn' off the end, since it will probably cuase problems |
|
|
|
# for users who want the patch version. |
|
|
|
# for users who want the patch version. |
|
|
|
self.version = out.strip().rstrip('svn') |
|
|
|
self.version = self.version.rstrip('svn') |
|
|
|
|
|
|
|
|
|
|
|
p, out, err = Popen_safe([self.llvmconfig, '--components']) |
|
|
|
|
|
|
|
if p.returncode != 0: |
|
|
|
|
|
|
|
raise DependencyException('Could not generate modules for LLVM:\n' + err) |
|
|
|
|
|
|
|
self.provided_modules = shlex.split(out) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.provided_modules = self.get_config_value(['--components'], 'modules') |
|
|
|
modules = stringlistify(extract_as_list(kwargs, 'modules')) |
|
|
|
modules = stringlistify(extract_as_list(kwargs, 'modules')) |
|
|
|
self.check_components(modules) |
|
|
|
self.check_components(modules) |
|
|
|
opt_modules = stringlistify(extract_as_list(kwargs, 'optional_modules')) |
|
|
|
opt_modules = stringlistify(extract_as_list(kwargs, 'optional_modules')) |
|
|
|
self.check_components(opt_modules, required=False) |
|
|
|
self.check_components(opt_modules, required=False) |
|
|
|
|
|
|
|
|
|
|
|
p, out, err = Popen_safe([self.llvmconfig, '--cppflags']) |
|
|
|
cargs = set(self.get_config_value(['--cppflags'], 'compile_args')) |
|
|
|
if p.returncode != 0: |
|
|
|
|
|
|
|
raise DependencyException('Could not generate includedir for LLVM:\n' + err) |
|
|
|
|
|
|
|
cargs = mesonlib.OrderedSet(shlex.split(out)) |
|
|
|
|
|
|
|
self.compile_args = list(cargs.difference(self.__cpp_blacklist)) |
|
|
|
self.compile_args = list(cargs.difference(self.__cpp_blacklist)) |
|
|
|
|
|
|
|
|
|
|
|
if version_compare(self.version, '>= 3.9'): |
|
|
|
if version_compare(self.version, '>= 3.9'): |
|
|
@ -198,11 +170,9 @@ class LLVMDependency(ExternalDependency): |
|
|
|
def _set_new_link_args(self): |
|
|
|
def _set_new_link_args(self): |
|
|
|
"""How to set linker args for LLVM versions >= 3.9""" |
|
|
|
"""How to set linker args for LLVM versions >= 3.9""" |
|
|
|
link_args = ['--link-static', '--system-libs'] if self.static else ['--link-shared'] |
|
|
|
link_args = ['--link-static', '--system-libs'] if self.static else ['--link-shared'] |
|
|
|
p, out, err = Popen_safe( |
|
|
|
self.link_args = self.get_config_value( |
|
|
|
[self.llvmconfig, '--libs', '--ldflags'] + link_args + list(self.required_modules)) |
|
|
|
['--libs', '--ldflags'] + link_args + list(self.required_modules), |
|
|
|
if p.returncode != 0: |
|
|
|
'link_args') |
|
|
|
raise DependencyException('Could not generate libs for LLVM:\n' + err) |
|
|
|
|
|
|
|
self.link_args = shlex.split(out) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _set_old_link_args(self): |
|
|
|
def _set_old_link_args(self): |
|
|
|
"""Setting linker args for older versions of llvm. |
|
|
|
"""Setting linker args for older versions of llvm. |
|
|
@ -213,20 +183,15 @@ class LLVMDependency(ExternalDependency): |
|
|
|
of course we do. |
|
|
|
of course we do. |
|
|
|
""" |
|
|
|
""" |
|
|
|
if self.static: |
|
|
|
if self.static: |
|
|
|
p, out, err = Popen_safe( |
|
|
|
self.link_args = self.get_config_value( |
|
|
|
[self.llvmconfig, '--libs', '--ldflags', '--system-libs'] + list(self.required_modules)) |
|
|
|
['--libs', '--ldflags', '--system-libs'] + list(self.required_modules), |
|
|
|
if p.returncode != 0: |
|
|
|
'link_args') |
|
|
|
raise DependencyException('Could not generate libs for LLVM:\n' + err) |
|
|
|
|
|
|
|
self.link_args = shlex.split(out) |
|
|
|
|
|
|
|
else: |
|
|
|
else: |
|
|
|
# llvm-config will provide arguments for static linking, so we get |
|
|
|
# llvm-config will provide arguments for static linking, so we get |
|
|
|
# to figure out for ourselves what to link with. We'll do that by |
|
|
|
# to figure out for ourselves what to link with. We'll do that by |
|
|
|
# checking in the directory provided by --libdir for a library |
|
|
|
# checking in the directory provided by --libdir for a library |
|
|
|
# called libLLVM-<ver>.(so|dylib|dll) |
|
|
|
# called libLLVM-<ver>.(so|dylib|dll) |
|
|
|
p, out, err = Popen_safe([self.llvmconfig, '--libdir']) |
|
|
|
libdir = self.get_config_value(['--libdir'], 'link_args')[0] |
|
|
|
if p.returncode != 0: |
|
|
|
|
|
|
|
raise DependencyException('Could not generate libs for LLVM:\n' + err) |
|
|
|
|
|
|
|
libdir = out.strip() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
expected_name = 'libLLVM-{}'.format(self.version) |
|
|
|
expected_name = 'libLLVM-{}'.format(self.version) |
|
|
|
re_name = re.compile(r'{}.(so|dll|dylib)'.format(expected_name)) |
|
|
|
re_name = re.compile(r'{}.(so|dll|dylib)'.format(expected_name)) |
|
|
@ -259,34 +224,6 @@ class LLVMDependency(ExternalDependency): |
|
|
|
self.required_modules.add(mod) |
|
|
|
self.required_modules.add(mod) |
|
|
|
mlog.log('LLVM module', mod, 'found:', mlog.green('YES')) |
|
|
|
mlog.log('LLVM module', mod, 'found:', mlog.green('YES')) |
|
|
|
|
|
|
|
|
|
|
|
def check_llvmconfig(self, version_req): |
|
|
|
|
|
|
|
"""Try to find the highest version of llvm-config.""" |
|
|
|
|
|
|
|
for llvmconfig in self.llvm_config_bins: |
|
|
|
|
|
|
|
try: |
|
|
|
|
|
|
|
p, out = Popen_safe([llvmconfig, '--version'])[0:2] |
|
|
|
|
|
|
|
out = out.strip() |
|
|
|
|
|
|
|
if p.returncode != 0: |
|
|
|
|
|
|
|
continue |
|
|
|
|
|
|
|
if version_req: |
|
|
|
|
|
|
|
if version_compare(out, version_req, strict=True): |
|
|
|
|
|
|
|
if self.__best_found and version_compare( |
|
|
|
|
|
|
|
out, '<={}'.format(self.__best_found), strict=True): |
|
|
|
|
|
|
|
continue |
|
|
|
|
|
|
|
self.__best_found = out |
|
|
|
|
|
|
|
self.llvmconfig = llvmconfig |
|
|
|
|
|
|
|
else: |
|
|
|
|
|
|
|
# If no specific version is requested use the first version |
|
|
|
|
|
|
|
# found, since that should be the best. |
|
|
|
|
|
|
|
self.__best_found = out |
|
|
|
|
|
|
|
self.llvmconfig = llvmconfig |
|
|
|
|
|
|
|
break |
|
|
|
|
|
|
|
except (FileNotFoundError, PermissionError): |
|
|
|
|
|
|
|
pass |
|
|
|
|
|
|
|
if self.__best_found: |
|
|
|
|
|
|
|
mlog.log('Found llvm-config:', |
|
|
|
|
|
|
|
mlog.bold(shutil.which(self.llvmconfig)), |
|
|
|
|
|
|
|
'({})'.format(out.strip())) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def need_threads(self): |
|
|
|
def need_threads(self): |
|
|
|
return True |
|
|
|
return True |
|
|
|
|
|
|
|
|
|
|
|